Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-zbee-direct.c
blob20308dddd58233b202106c851fbbe67ad60bf9ea
1 /* packet-zbee-direct.c
2 * Dissector routines for the ZigBee Direct
3 * Copyright 2021 DSR Corporation, http://dsr-wireless.com/
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <gcrypt.h>
15 #include <epan/packet.h>
16 #include <epan/expert.h>
17 #include <epan/uat.h>
19 #include "packet-zbee-security.h"
20 #include "packet-bluetooth.h"
21 #include "packet-ieee802154.h"
22 #include "packet-zbee-nwk.h"
23 #include "packet-zbee-tlv.h"
24 #include "packet-zbee-direct.h"
26 /*-------------------------------------
27 * Dissector Function Prototypes
28 *-------------------------------------
31 static int dissect_zb_direct_dump_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
32 static int dissect_zb_direct_secur_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data, unsigned offset, unsigned msg_id);
33 static int dissect_zb_direct_secur_c25519_aesmmo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
34 static int dissect_zb_direct_secur_c25519_sha256(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
35 static int dissect_zb_direct_secur_p256(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
36 static int dissect_zb_direct_formation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
37 static int dissect_zb_direct_status(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
38 static int dissect_zb_direct_join(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
39 static int dissect_zb_direct_permit_join(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
40 static int dissect_zb_direct_leave(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
41 static int dissect_zb_direct_manage_joiners(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
42 static int dissect_zb_direct_identify(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
43 static int dissect_zb_direct_finding_binding(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
44 static int dissect_zb_direct_tunneling(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
46 static int dissect_zb_direct_common(tvbuff_t **tvb, packet_info *pinfo, proto_tree **tree, void *data, unsigned offset, const uint8_t *serv_uuid, const uint8_t *char_uuid);
48 /* Used dissectors */
49 static dissector_handle_t zbee_nwk_handle;
51 /* TLV Node-elements */
52 static int proto_zb_direct;
54 /* Leaf-elements */
55 static int hf_zb_direct_info_type;
56 static int hf_zb_direct_info_key;
57 static int hf_zb_direct_info_zdd_ieee;
58 static int hf_zb_direct_info_zvd_ieee;
59 static int hf_zb_direct_info_encryption;
60 static int hf_zb_direct_msg_type;
62 /* Commissioning */
63 static int hf_zb_direct_comm_permit_time;
64 static int hf_zb_direct_comm_rejoin;
65 static int hf_zb_direct_comm_rm_children;
66 static int hf_zb_direct_comm_identify_time;
67 static int hf_zb_direct_comm_fb_endpoint;
68 static int hf_zb_direct_comm_fb_initiator;
70 /* Markers (also leafs) */
71 static int hf_zb_direct_unrecognized_msg;
72 static int hf_zb_direct_char_info;
73 static int hf_zb_direct_char_c25519_aesmmo;
74 static int hf_zb_direct_char_c25519_sha256;
75 static int hf_zb_direct_char_p256;
76 static int hf_zb_direct_char_form;
77 static int hf_zb_direct_char_status;
78 static int hf_zb_direct_char_join;
79 static int hf_zb_direct_char_permit_join;
80 static int hf_zb_direct_char_leave;
81 static int hf_zb_direct_char_manage_joiners;
82 static int hf_zb_direct_char_identify;
83 static int hf_zb_direct_char_finding_binding;
84 static int hf_zb_direct_char_tunneling;
86 /* Expert items */
87 static expert_field ei_zb_direct_crypt_error;
89 /* Trees entities */
90 static int ett_zb_direct;
92 static const uint8_t serv_secur_uuid[] = { 0xe3, 0x29, 0xb4, 0x99, 0x02, 0x6d, 0xe9, 0xbf,
93 0x81, 0x44, 0x00, 0x00, 0xf4, 0x4a, 0x14, 0x29 };
94 static const uint8_t char_p256_uuid[] = { 0xe3, 0x29, 0xb4, 0x99, 0x02, 0x6d, 0xe9, 0xbf,
95 0x81, 0x44, 0x03, 0x00, 0xf4, 0x4a, 0x14, 0x29 };
96 static const uint8_t char_c25519_aesmmo_uuid[] = { 0xe3, 0x29, 0xb4, 0x99, 0x02, 0x6d, 0xe9, 0xbf,
97 0x81, 0x44, 0x01, 0x00, 0xf4, 0x4a, 0x14, 0x29 };
98 static const uint8_t char_c25519_sha256_uuid[] = { 0xe3, 0x29, 0xb4, 0x99, 0x02, 0x6d, 0xe9, 0xbf,
99 0x81, 0x44, 0x02, 0x00, 0xf4, 0x4a, 0x14, 0x29 };
100 static const uint8_t serv_comm_uuid[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
101 0x00, 0x10, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00 };
102 static const uint8_t char_form_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
103 0x1c, 0x42, 0x01, 0x00, 0x7d, 0x37, 0x72, 0x70 };
104 static const uint8_t char_join_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
105 0x1c, 0x42, 0x02, 0x00, 0x7d, 0x37, 0x72, 0x70 };
106 static const uint8_t char_permit_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
107 0x1c, 0x42, 0x03, 0x00, 0x7d, 0x37, 0x72, 0x70 };
108 static const uint8_t char_leave_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
109 0x1c, 0x42, 0x04, 0x00, 0x7d, 0x37, 0x72, 0x70 };
110 static const uint8_t char_status_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
111 0x1c, 0x42, 0x05, 0x00, 0x7d, 0x37, 0x72, 0x70 };
112 static const uint8_t char_identify_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
113 0x1c, 0x42, 0x07, 0x00, 0x7d, 0x37, 0x72, 0x70 };
114 static const uint8_t char_manage_joiners_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
115 0x1c, 0x42, 0x06, 0x00, 0x7d, 0x37, 0x72, 0x70 };
116 static const uint8_t char_finding_binding_uuid[] = { 0x61, 0x3a, 0x33, 0x27, 0x1c, 0x49, 0x63, 0xb1,
117 0x1c, 0x42, 0x08, 0x00, 0x7d, 0x37, 0x72, 0x70 };
118 static const uint8_t serv_tunnel_uuid[] = { 0x3f, 0x31, 0xd5, 0x8b, 0x37, 0xb2, 0x20, 0x81,
119 0xf4, 0x45, 0x00, 0x00, 0xfd, 0x78, 0xd1, 0x8b };
120 static const uint8_t char_tunnel_uuid[] = { 0x3f, 0x31, 0xd5, 0x8b, 0x37, 0xb2, 0x20, 0x81,
121 0xf4, 0x45, 0x01, 0x00, 0xfd, 0x78, 0xd1, 0x8b };
122 #define ZIGBEE_DIRECT_MAX_ATT_SIZE 248
123 #define ZIGBEE_DIRECT_AUTH_STR_SIZE (16 + 1 + 16 + 1)
124 #define ZIGBEE_DIRECT_SECUR_CONTROL 0x05
126 /* MIC length */
127 #define ZB_CCM_M 4
129 #define KEY_LEN 16
130 #define MAX_CONNECTIONS 2
132 /*****************************************************************************/
133 /******************************** Static Data ********************************/
134 /*****************************************************************************/
136 static uat_t *zbd_secur_key_table_uat;
138 /* Values in the key rings. */
139 typedef struct
141 unsigned frame_num;
142 uint8_t zdd_ieee[8];
143 uint8_t zvd_ieee[8];
144 uint8_t key[KEY_LEN];
145 char *label;
146 } zb_direct_key_record_t;
148 /* UAT Key Entry */
149 typedef struct uat_key_record_s
151 char *zdd_ieee;
152 char *zvd_ieee;
153 char *key;
154 char *label;
155 } uat_key_record_t;
157 UAT_CSTRING_CB_DEF(uat_key_records, zdd_ieee, uat_key_record_t)
158 UAT_CSTRING_CB_DEF(uat_key_records, zvd_ieee, uat_key_record_t)
159 UAT_CSTRING_CB_DEF(uat_key_records, key, uat_key_record_t)
160 UAT_CSTRING_CB_DEF(uat_key_records, label, uat_key_record_t)
162 static GSList *zbee_pc_keyring;
163 static uat_key_record_t *uat_key_records;
164 static unsigned num_uat_key_records;
166 /* Common data */
167 static uint8_t g_conn_id;
169 static bool ignore_late_keys = true;
171 /* Info types */
172 typedef enum
174 DUMP_INFO_KEY_DEL,
175 DUMP_INFO_KEY_SET,
176 DUMP_INFO_ENCRYPTION_STATUS
177 } dump_info_t;
179 static const value_string info_type_str[] =
181 { DUMP_INFO_KEY_DEL, "Delete CCM* key" },
182 { DUMP_INFO_KEY_SET, "Set CCM* key" },
183 { DUMP_INFO_ENCRYPTION_STATUS, "Set encryption status" },
184 { 0, NULL }
187 /* Message types */
188 typedef enum
190 MSG_SE1 = 1,
191 MSG_SE2 = 2,
192 MSG_SE3 = 3,
193 MSG_SE4 = 4
194 } msg_type_t;
196 static const value_string msg_type_str[] =
198 { MSG_SE1, "Message SE1" },
199 { MSG_SE2, "Message SE2" },
200 { MSG_SE3, "Message SE3" },
201 { MSG_SE4, "Message SE4" },
202 { 0, NULL }
205 #define BOOLSTR(b) ((b) ? "TRUE" : "FALSE")
207 /* "Cast" GSList node to zb_direct_key_record_t* */
208 #define keyrec(node) ((zb_direct_key_record_t*)((node)->data))
211 * Like memcpy, but in reverse order.
213 * @param dst pointer to destination (copy to)
214 * @param src pointer to source (copy from)
215 * @param len number of bytes
217 static inline void memcpy_reverse(uint8_t *dst, const uint8_t *src, size_t len)
219 len -= 1;
221 for (size_t i = 0; i <= len; ++i)
223 dst[i] = src[len - i];
227 /*****************************************************************************/
228 /************************************ UAT ************************************/
229 /*****************************************************************************/
232 * Parses a hex string into bytes.
234 * @param str pointer to a hex string
235 * @param buf pointer to buffer, where to place result
236 * @param bytes_num number of bytes to retrive from the string
237 * @return success
239 static bool zbd_parse_uat_hexline(const char *str,
240 uint8_t *buf,
241 unsigned bytes_num)
243 int i, j;
244 char temp;
245 bool string_mode = false;
247 /* Clear the key. */
248 memset(buf, 0, bytes_num);
249 if (str == NULL)
251 return false;
255 * Attempt to parse the hex string. The hex string must
256 * be at least 16 pairs of hexidecimal digits with the
257 * following optional separators: ':', '-', " ", or 16
258 * alphanumeric characters after a double-quote.
260 if ((temp = *str++) == '"')
262 string_mode = true;
263 temp = *str++;
266 j = 0;
267 for (i = bytes_num - 1; i >= 0; i--)
269 if (string_mode)
271 if (g_ascii_isprint(temp))
273 buf[j] = temp;
274 temp = *str++;
276 else
278 return false;
281 else
283 /* If this character is a separator, skip it. */
284 if (temp == ':' || temp == '-' || temp == ' ')
286 temp = *str++;
289 /* Process a nibble. */
290 if (g_ascii_isxdigit(temp))
292 buf[j] = g_ascii_xdigit_value(temp) << 4;
294 else
296 return false;
299 /* Get the next nibble. */
300 temp = *str++;
302 /* Process another nibble. */
303 if (g_ascii_isxdigit(temp))
305 buf[j] |= g_ascii_xdigit_value(temp);
307 else
309 return false;
312 /* Get the next nibble. */
313 temp = *str++;
316 /* Move buf pointer */
317 j++;
320 /* If we get this far, then the key was good. */
321 return true;
325 * UAT Copy callback.
327 * @param n pointer to new uat_kkey_record_t
328 * @param o pointer to old uat_key_record_t
329 * @param size unused
331 static void *uat_key_record_copy_cb(void *n, const void *o, size_t size _U_)
333 uat_key_record_t *new_key = (uat_key_record_t *)n;
334 const uat_key_record_t *old_key = (const uat_key_record_t *)o;
336 new_key->zdd_ieee = g_strdup(old_key->zdd_ieee);
337 new_key->zvd_ieee = g_strdup(old_key->zvd_ieee);
338 new_key->key = g_strdup(old_key->key);
339 new_key->label = g_strdup(old_key->label);
341 return new_key;
345 * UAT Update callback.
347 * @param r pointer to uat_kkey_record_t
348 * @param err pointer to error pointer
349 * @return success
351 static bool uat_key_record_update_cb(void *r, char **err)
353 uat_key_record_t *rec = (uat_key_record_t *)r;
354 uint8_t zdd_ieee[8];
355 uint8_t zvd_ieee[8];
356 uint8_t key[KEY_LEN];
358 *err = NULL;
360 if (rec->zdd_ieee == NULL)
362 *err = g_strdup("ZDD IEEE can't be blank");
363 return false;
366 if (rec->zvd_ieee == NULL)
368 *err = g_strdup("ZVD IEEE can't be blank");
369 return false;
372 if (rec->key == NULL)
374 *err = g_strdup("Key can't be blank");
375 return false;
378 g_strstrip(rec->zdd_ieee);
379 g_strstrip(rec->zvd_ieee);
380 g_strstrip(rec->key);
382 if (rec->zdd_ieee[0] == 0)
384 *err = g_strdup("ZDD IEEE can't be blank");
385 return false;
388 if (rec->zvd_ieee[0] == 0)
390 *err = g_strdup("ZVD IEEE can't be blank");
391 return false;
394 if (rec->key[0] == 0)
396 *err = g_strdup("Key can't be blank");
397 return false;
400 if (!zbd_parse_uat_hexline(rec->zdd_ieee, zdd_ieee, 8))
402 *err = g_strdup_printf("Expecting %d hexadecimal bytes or a %d character double-quoted string", 8, 8);
403 return false;
406 if (!zbd_parse_uat_hexline(rec->zvd_ieee, zvd_ieee, 8))
408 *err = g_strdup_printf("Expecting %d hexadecimal bytes or a %d character double-quoted string", 8, 8);
409 return false;
412 if (!zbd_parse_uat_hexline(rec->key, key, 16))
414 *err = g_strdup_printf("Expecting %d hexadecimal bytes or a %d character double-quoted string", 16, 16);
415 return false;
418 return true;
422 * UAT Free callback.
424 * @param r pointer to a uat_key_record_t
426 static void uat_key_record_free_cb(void *r)
428 uat_key_record_t *key = (uat_key_record_t *)r;
430 g_free(key->zdd_ieee);
431 g_free(key->zvd_ieee);
432 g_free(key->key);
433 g_free(key->label);
437 * Frees zb_direct_key_record_t.
439 * @param ptr pointer to a zb_direct_key_record_t
441 static void zbd_free_key_record(void *ptr)
443 zb_direct_key_record_t *k = (zb_direct_key_record_t *)ptr;
445 g_free(k->label);
446 g_free(k);
450 * Deletes all existing keys in zbee_pc_keyrig and adds new ones
451 * from uat_key_records.
453 static void uat_key_record_post_update(void)
455 zb_direct_key_record_t key_record;
456 uint8_t zdd_ieee[8];
457 uint8_t zvd_ieee[8];
458 uint8_t key[KEY_LEN];
460 /* Empty UAT keys */
461 GSList *element = zbee_pc_keyring;
463 /* Find where UAT table keys begin */
464 while (element && keyrec(element)->frame_num > 0)
466 element = g_slist_next(element);
469 /* Delete all UAT keys */
470 while (element)
472 GSList *next = element->next;
474 zbee_pc_keyring = g_slist_remove_link(zbee_pc_keyring, element);
476 g_slist_free_full(element, zbd_free_key_record);
477 element = next;
480 /* Load the pre-configured slist from the UAT */
481 for (unsigned i = 0U; uat_key_records && i < num_uat_key_records; i++)
483 bool success = (int)zbd_parse_uat_hexline(uat_key_records[i].zdd_ieee, zdd_ieee, sizeof(zdd_ieee))
484 | (int)zbd_parse_uat_hexline(uat_key_records[i].zvd_ieee, zvd_ieee, sizeof(zvd_ieee))
485 | (int)zbd_parse_uat_hexline(uat_key_records[i].key, key, sizeof(key));
487 if (success)
489 key_record.frame_num = 0; /* means it's a user PC key */
490 key_record.label = g_strdup(uat_key_records[i].label);
492 memcpy_reverse(key_record.zdd_ieee, zdd_ieee, 8);
493 memcpy_reverse(key_record.zvd_ieee, zvd_ieee, 8);
494 memcpy(key_record.key, key, KEY_LEN);
496 /* Add UAT keys to the end */
497 zbee_pc_keyring = g_slist_append(zbee_pc_keyring, g_memdup2(&key_record, sizeof(key_record)));
502 /*****************************************************************************/
503 /******************************** Decryption *********************************/
504 /*****************************************************************************/
506 #define MAX_CRYPT_TOGGLES 4096
508 typedef struct encryption_states_handler_s
510 /* How many toggles were performed */
511 uint16_t counter;
512 /* Even entries point, where encryption enabled region starts, odd ones point, where they end */
513 uint32_t states[MAX_CRYPT_TOGGLES];
514 } encryption_states_handler_t;
516 static encryption_states_handler_t enc_h[MAX_CONNECTIONS];
519 * Enables encryption for packet_info if possible.
521 * @param pinfo pointer to packet
523 static void zb_direct_encryption_enable(packet_info *pinfo)
525 encryption_states_handler_t *h = &enc_h[g_conn_id];
527 /* If currently enabled && was not disabled previously, exit */
528 if (h->counter % 2 == 1)
530 return;
533 /* If this packet was already handled, exit */
534 if (h->counter != 0 && pinfo->num <= h->states[h->counter - 1])
536 return;
539 if (h->counter >= MAX_CRYPT_TOGGLES)
541 return;
544 /* Enable */
545 h->states[h->counter++] = pinfo->num;
549 * Disables encryption for packet_info if possible.
551 * @param pinfo pointer to packet
553 static void zb_direct_encryption_disable(packet_info *pinfo)
555 encryption_states_handler_t *h = &enc_h[g_conn_id];
557 /* If currently enabled && was not disabled previously */
558 if (h->counter % 2 == 0)
560 return;
563 if (pinfo->num <= h->states[h->counter - 1])
565 return;
568 /* Enable */
569 h->states[h->counter++] = pinfo->num;
573 * Checks if the packet must be decrypted.
575 * @param pinfo pointer to packet
576 * @return true, if decryption is needed, false, otherwise
578 static bool zb_direct_decryption_needed(packet_info *pinfo)
580 encryption_states_handler_t *h = &enc_h[g_conn_id];
582 for (int i = 0; i < h->counter; i += 2)
584 if (h->states[i] < pinfo->num)
586 /* If the packet is before the beginning of current crypted block, shutdown the search */
587 if (pinfo->num < h->states[i])
589 return false;
592 /* If encrypted block was opened and not closed till now, or closed after current packet */
593 if (i == h->counter - 1 || pinfo->num < h->states[i + 1])
595 return true;
600 return false;
603 static bool decrypt_data(const uint8_t *serv_uuid,
604 const uint8_t *char_uuid,
605 bool to_zdd,
606 const uint8_t *in,
607 uint8_t *out,
608 uint16_t *len,
609 uint8_t zdd_ieee[8],
610 uint8_t zvd_ieee[8],
611 uint8_t key[KEY_LEN]);
614 * Tries to decrypt packet payload as ZDD and ZVD.
616 * @param serv_uuid service UUID
617 * @param char_uuid characteristic UUID
618 * @param in pointer to encrypted payload
619 * @param out pointer to buffer for the result
620 * @param len pointer to the length of payload, outputs length of out
621 * @param zdd_ieee ZDD IEEE
622 * @param zvd_ieee ZVD IEEE
623 * @param key key for decryption
624 * @return success
626 static bool try_decrypt(const uint8_t *serv_uuid,
627 const uint8_t *char_uuid,
628 const uint8_t *in,
629 uint8_t *out,
630 uint16_t *len,
631 uint8_t zdd_ieee[8],
632 uint8_t zvd_ieee[8],
633 uint8_t key[KEY_LEN])
635 /* As there is no reliable way known to determine,
636 * if the packet is from zdd or zvd, try both cases */
638 uint16_t len_buf = *len;
639 bool success = decrypt_data(serv_uuid, char_uuid,
640 true,
642 out, len,
643 zdd_ieee, zvd_ieee, key);
645 if (!success)
647 *len = len_buf;
648 success = decrypt_data(serv_uuid, char_uuid,
649 false,
651 out, len,
652 zdd_ieee, zvd_ieee, key);
655 return success;
659 * @brief Generates IEEE address from BLE MAC.
661 * @param mac_address BLE MAC in BE
662 * @param ieee generated IEEE in BE
664 static void zb_direct_ieee_from_mac(const uint8_t *mac_address, uint8_t *ieee)
666 ieee[0] = mac_address[0] ^ 0x02;
667 ieee[1] = mac_address[1];
668 ieee[2] = mac_address[2];
669 ieee[3] = 0xFF;
670 ieee[4] = 0xFE;
671 ieee[5] = mac_address[3];
672 ieee[6] = mac_address[4];
673 ieee[7] = mac_address[5];
677 * @brief Get BLE MAC address of the device which sent current packet from the packet data.
679 * @param pinfo packet info
680 * @param mac BLE MAC (bd_addr) corresponding to current packet sender
682 static void zb_direct_bd_addr_from_packet_data(const packet_info *pinfo,
683 uint8_t *mac)
685 (void)address_to_bytes(&pinfo->dl_src, mac, 6);
689 * @brief Get IEEE address of the device which generated current packet from the packet data.
691 * @param pinfo packet info
692 * @param ieee calculated IEEE in BE
694 static void zb_direct_ieee_from_packet_data(const packet_info *pinfo,
695 uint8_t *ieee)
697 uint8_t mac[6];
698 zb_direct_bd_addr_from_packet_data(pinfo, mac);
699 zb_direct_ieee_from_mac(mac, ieee);
703 * Decrypts ZB Direct packets.
705 * @param tvb pointer to buffer containing raw packet
706 * @param pinfo pointer to packet information fields
707 * @param tree pointer to the command subtree
708 * @param data raw packet private data
709 * @param offset offset into the tvb to begin dissection
710 * @param serv_uuid service UUID
711 * @param char_uuid characteristic UUID
712 * @return offset after command dissection
714 static int zb_direct_decrypt(tvbuff_t **tvb,
715 packet_info *pinfo,
716 proto_tree *tree,
717 void *data _U_,
718 unsigned offset,
719 const uint8_t *serv_uuid,
720 const uint8_t *char_uuid)
722 if (zb_direct_decryption_needed(pinfo))
724 uint8_t ieee[8];
725 bool success = false;
726 uint16_t size = tvb_reported_length_remaining(*tvb, offset);
727 uint8_t *decrypted = (uint8_t *)wmem_alloc(pinfo->pool, 512);
728 GList *pan_keyring;
729 GSList *i = zbee_pc_keyring;
730 uint16_t init_size = size;
732 zb_direct_ieee_from_packet_data(pinfo, ieee);
734 if (ignore_late_keys)
736 /* Skip all keys, which were reported after current package */
737 while (i && (keyrec(i)->frame_num > pinfo->num))
739 i = g_slist_next(i);
743 /* Try potential keys from preconfigured table and dump info packets */
744 while (i && !success)
746 success = try_decrypt(serv_uuid,
747 char_uuid,
748 tvb_get_ptr(*tvb, offset, size),
749 decrypted,
750 &size,
751 keyrec(i)->zdd_ieee,
752 keyrec(i)->zvd_ieee,
753 keyrec(i)->key);
755 if (!success)
757 i = g_slist_next(i);
758 size = init_size;
762 /* Retrieve all pan-specific nwk keyrings from the hash table */
763 if (!success && zbee_table_nwk_keyring)
765 pan_keyring = (GList*)g_hash_table_get_values(zbee_table_nwk_keyring);
767 while (!success && pan_keyring)
769 i = *((GSList**)pan_keyring->data);
771 /* Iterate over keys in the keyring */
772 while (!success && i)
774 if (!ignore_late_keys || ((key_record_t*)i->data)->frame_num > pinfo->num)
776 success = decrypt_data(serv_uuid, char_uuid, false,
777 tvb_get_ptr(*tvb, offset, size),
778 decrypted, &size,
779 ieee, NULL, ((key_record_t*)i->data)->key);
781 i = g_slist_next(i);
782 if (!success)
784 size = init_size;
788 pan_keyring = g_list_next(i);
792 if (success)
794 /* On decryption success: replace the tvb, make offset point to its beginning */
795 *tvb = tvb_new_child_real_data(*tvb, decrypted, size, size);
796 add_new_data_source(pinfo, *tvb, "CCM* decrypted payload");
797 offset = 0;
799 else
801 /* On decryption error: make offset point to the end of original tvb */
802 offset = tvb_reported_length(*tvb);
803 expert_add_info(pinfo, tree, &ei_zb_direct_crypt_error);
807 return offset;
810 /* 6.4.3. CCM Nonce */
811 typedef struct
812 #if defined(_MSC_VER)
813 # pragma pack(push, 1)
814 #else
815 __attribute__((__packed__))
816 #endif
817 zb_secur_ccm_nonce_s
819 uint8_t source_address[8];
820 uint32_t frame_counter;
821 uint8_t secur_control;
822 } zb_secur_ccm_nonce_t;
823 #ifdef _MSC_VER
824 # pragma pack(pop)
825 #endif
828 * Creates an auth string.
830 * @param serv_uuid service UUID
831 * @param char_uuid characteristic UUID
832 * @param auth_string output buffer
834 static void create_auth_string(const uint8_t serv_uuid[16],
835 const uint8_t char_uuid[16],
836 uint8_t auth_string[ZIGBEE_DIRECT_AUTH_STR_SIZE])
838 /* 6.4.5. Unique address */
839 memcpy_reverse(auth_string, serv_uuid, 16);
840 auth_string[16] = 0;
841 memcpy_reverse(&auth_string[17], char_uuid, 16);
842 auth_string[33] = 0;
846 * Decrypts packet payload as ZDD and ZVD.
848 * @param serv_uuid service UUID
849 * @param char_uuid characteristic UUID
850 * @param to_zdd true if packet ws sent to zdd, false if to zvd (needed for nonce formation)
851 * @param in pointer to encrypted payload
852 * @param out pointer to buffer for the result
853 * @param len pointer to the length of payload, outputs length of out
854 * @param zdd_ieee ZDD IEEE
855 * @param zvd_ieee ZVD IEEE
856 * @param key key for decryption
857 * @return success
859 static bool decrypt_data(const uint8_t *serv_uuid,
860 const uint8_t *char_uuid,
861 bool to_zdd,
862 const uint8_t *in,
863 uint8_t *out,
864 uint16_t *len,
865 uint8_t zdd_ieee[8],
866 uint8_t zvd_ieee[8],
867 uint8_t key[KEY_LEN])
869 bool success = true;
870 uint8_t auth_str[ZIGBEE_DIRECT_AUTH_STR_SIZE];
871 uint8_t decrypted_data[ZIGBEE_DIRECT_MAX_ATT_SIZE + 16];
872 uint16_t decrypted_data_len = sizeof(decrypted_data);
874 /* Remove 32-bit counter from the beginning */
875 const uint8_t *encrypted_data = in + sizeof(uint32_t);
876 uint16_t encrypted_data_len = *len - sizeof(uint32_t);
878 /* Form the nonce */
879 zb_secur_ccm_nonce_t nonce = (zb_secur_ccm_nonce_t)
881 .secur_control = ZIGBEE_DIRECT_SECUR_CONTROL
884 /* Fetch counter from the packet (don't check) */
885 memcpy(&nonce.frame_counter, in, sizeof(uint32_t));
886 memcpy(&nonce.source_address, to_zdd ? zvd_ieee : zdd_ieee, 8);
888 if (*len < 8) return false;
890 create_auth_string(serv_uuid, char_uuid, auth_str);
892 success = zbee_sec_ccm_decrypt(key,
893 (uint8_t*)&nonce,
894 auth_str,
895 encrypted_data,
896 decrypted_data,
897 sizeof(auth_str),
898 encrypted_data_len - ZB_CCM_M,
899 ZB_CCM_M);
902 if (success)
904 decrypted_data_len = encrypted_data_len - ZB_CCM_M;
905 memcpy(out, decrypted_data, decrypted_data_len);
906 *len = decrypted_data_len;
908 else
910 *len = 0;
913 return success;
916 /*****************************************************************************/
917 /***************************** Dissectors Common *****************************/
918 /*****************************************************************************/
921 * Common helper dissector.
923 * @param tvb pointer to buffer containing raw packet
924 * @param pinfo pointer to packet information fields
925 * @param tree pointer to the command subtree
926 * @param data pointer to packet data
927 * @param offset offset into the tvb to begin dissection
928 * @param serv_uuid service UUID
929 * @param char_uuid characteristic UUID
930 * @return offset after command dissection
932 static int dissect_zb_direct_common(tvbuff_t **tvb,
933 packet_info *pinfo,
934 proto_tree **tree,
935 void *data,
936 unsigned offset,
937 const uint8_t *serv_uuid,
938 const uint8_t *char_uuid)
940 proto_item *ti;
942 /** TODO: find a way to detect direct (master/slave) and particular connection from data, passed from Bluetooth dissector */
944 /* Set basic columns (proto, src, dst) */
945 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZBD");
948 * Actually should think of better way to know
950 * (probably try fetch BLE data: indication would reveal ZDD for example)
952 /* Add ZB Direct subtree */
953 ti = proto_tree_add_item(*tree, proto_zb_direct, *tvb, 0, -1, ENC_LITTLE_ENDIAN);
954 *tree = proto_item_add_subtree(ti, ett_zb_direct);
956 g_conn_id = 0;
958 proto_item_append_text(ti, " (Connection ID: %d)", (int)g_conn_id);
960 /* NULL uuid is for chars, which do not have to be encrypted at all (dump info) */
961 if (char_uuid != NULL && serv_uuid != NULL && memcmp(serv_uuid, serv_secur_uuid, sizeof(serv_secur_uuid)))
963 offset = zb_direct_decrypt(tvb, pinfo, *tree, data, offset, serv_uuid, char_uuid);
966 return offset;
969 /*****************************************************************************/
970 /**************************** Dump Info Dissector ****************************/
971 /*****************************************************************************/
973 typedef enum zb_dump_info_e
975 /* Clear current used key */
976 ZB_DUMP_INFO_CCM_KEY_DELETE,
977 /* Replace current key with a new one */
978 ZB_DUMP_INFO_CCM_KEY_SET,
979 /* Specify, if encryption is needed or not */
980 ZB_DUMP_INFO_ENCRYPTION_STATUS
981 } zb_dump_info_t;
984 * Dump Info dissector.
986 * @param tvb pointer to buffer containing raw packet
987 * @param pinfo pointer to packet information fields
988 * @param tree pointer to the command subtree
989 * @param data raw packet private data
990 * @return offset after command dissection
992 static int dissect_zb_direct_dump_info(tvbuff_t *tvb,
993 packet_info *pinfo,
994 proto_tree *tree,
995 void *data)
997 proto_item* ti;
998 unsigned offset = 0;
999 uint32_t type;
1001 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, NULL, NULL);
1002 col_set_str(pinfo->cinfo, COL_INFO, "Dump info");
1004 ti = proto_tree_add_item(tree, hf_zb_direct_char_info, tvb, offset, 0, ENC_NA);
1005 proto_item_set_generated(ti);
1007 proto_tree_add_item_ret_uint(tree, hf_zb_direct_info_type, tvb, offset, 1, ENC_LITTLE_ENDIAN, &type);
1008 offset += 1;
1010 switch(type)
1012 case ZB_DUMP_INFO_CCM_KEY_DELETE:
1013 /* Obsolete option */
1014 break;
1016 case ZB_DUMP_INFO_CCM_KEY_SET:
1018 zb_direct_key_record_t key_record;
1019 col_append_str(pinfo->cinfo, COL_INFO, ": update key");
1022 * From the Wireshark Developer's Guide:
1024 * Wireshark performs a first pass of dissecting all packets as they are loaded from the file.
1025 * All packets are dissected sequentially...
1027 * So, we can assume that keys are coming in order they will be used in file
1030 proto_tree_add_item(tree, hf_zb_direct_info_key, tvb, offset, KEY_LEN, ENC_NA);
1031 tvb_memcpy(tvb, key_record.key, offset, KEY_LEN);
1032 offset += KEY_LEN;
1034 proto_tree_add_item(tree, hf_zb_direct_info_zdd_ieee, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1035 tvb_memcpy(tvb, key_record.zdd_ieee, offset, sizeof(key_record.zdd_ieee));
1036 offset += 8;
1038 proto_tree_add_item(tree, hf_zb_direct_info_zvd_ieee, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1039 tvb_memcpy(tvb, key_record.zvd_ieee, offset, sizeof(key_record.zdd_ieee));
1040 offset += 8;
1042 key_record.frame_num = pinfo->num;
1043 key_record.label = g_strdup_printf("Key reported over air in packet #%d", pinfo->num);
1045 /* Check if this key was already added */
1046 if (zbee_pc_keyring == NULL || keyrec(zbee_pc_keyring)->frame_num < pinfo->num)
1048 /* store the keys in order: latest <- ... <- first <- (UAT: top <- ... <- bottom) */
1049 zbee_pc_keyring = g_slist_prepend(zbee_pc_keyring,
1050 g_memdup2(&key_record, sizeof(zb_direct_key_record_t)));
1052 break;
1055 case ZB_DUMP_INFO_ENCRYPTION_STATUS:
1057 bool is_enabled = tvb_get_uint8(tvb, offset);
1059 if (is_enabled)
1061 zb_direct_encryption_enable(pinfo);
1063 else
1065 zb_direct_encryption_disable(pinfo);
1068 proto_tree_add_item(tree,
1069 hf_zb_direct_info_encryption,
1070 tvb,
1071 offset,
1073 ENC_LITTLE_ENDIAN);
1074 offset += 1;
1076 if (is_enabled)
1078 col_append_str(pinfo->cinfo, COL_INFO, ": encryption ON");
1080 else
1082 col_append_str(pinfo->cinfo, COL_INFO, ": encryption OFF");
1084 break;
1087 return offset;
1090 /*****************************************************************************/
1091 /********* Zigbee Direct Security Service Characteristics Dissectors *********/
1092 /*****************************************************************************/
1095 * Dissector for the security packets.
1097 * @param tvb pointer to buffer containing raw packet
1098 * @param pinfo pointer to packet information fields
1099 * @param tree pointer to the command subtree
1100 * @param data raw packet private data
1101 * @param offset offset into the tvb to begin dissection.
1102 * @param msg_id ZB Direct local Message ID
1103 * @return offset after command dissection
1105 static int dissect_zb_direct_secur_common(tvbuff_t *tvb,
1106 packet_info *pinfo,
1107 proto_tree *tree,
1108 void *data,
1109 unsigned offset,
1110 unsigned msg_id)
1112 unsigned cap_len = tvb_captured_length(tvb);
1113 proto_item* ti;
1115 const uint8_t *decrypt_char_uuid;
1117 switch (msg_id)
1119 case ZB_DIRECT_MSG_ID_SECUR_C25519_AESMMO:
1120 decrypt_char_uuid = char_c25519_aesmmo_uuid;
1121 break;
1123 case ZB_DIRECT_MSG_ID_SECUR_C25519_SHA256:
1124 decrypt_char_uuid = char_c25519_sha256_uuid;
1125 break;
1127 case ZB_DIRECT_MSG_ID_SECUR_P256:
1128 decrypt_char_uuid = char_p256_uuid;
1129 break;
1131 default:
1132 DISSECTOR_ASSERT(false);
1133 break;
1136 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset,
1137 serv_secur_uuid, decrypt_char_uuid);
1139 switch (msg_id)
1141 case ZB_DIRECT_MSG_ID_SECUR_C25519_AESMMO:
1142 ti = proto_tree_add_item(tree, hf_zb_direct_char_c25519_aesmmo, tvb, offset, 0, ENC_NA);
1143 break;
1145 case ZB_DIRECT_MSG_ID_SECUR_C25519_SHA256:
1146 ti = proto_tree_add_item(tree, hf_zb_direct_char_c25519_sha256, tvb, offset, 0, ENC_NA);
1147 break;
1149 case ZB_DIRECT_MSG_ID_SECUR_P256:
1150 ti = proto_tree_add_item(tree, hf_zb_direct_char_p256, tvb, offset, 0, ENC_NA);
1151 break;
1153 default:
1154 DISSECTOR_ASSERT(false);
1155 break;
1158 proto_item_set_generated(ti);
1160 /* Discover type of the message */
1161 uint8_t msg_type = tvb_get_uint8(tvb, offset);
1163 proto_tree_add_item(tree, hf_zb_direct_msg_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1164 offset += 1;
1166 if (msg_type == MSG_SE1)
1168 zb_direct_encryption_disable(pinfo);
1170 else if (msg_type == MSG_SE4)
1172 zb_direct_encryption_enable(pinfo);
1175 offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, data,
1176 ZBEE_TLV_SRC_TYPE_ZB_DIRECT, msg_id);
1178 if (msg_type >= MSG_SE1 && msg_type <= MSG_SE4)
1180 size_t msg_type_idx = msg_type - MSG_SE1;
1181 col_set_str(pinfo->cinfo, COL_INFO, msg_type_str[msg_type_idx].strptr);
1183 else
1185 proto_tree_add_item(tree, hf_zb_direct_unrecognized_msg, tvb, 0, cap_len, ENC_NA);
1186 offset = cap_len;
1188 col_set_str(pinfo->cinfo, COL_INFO, "Unrecognized SE message");
1191 return offset;
1195 * Dissector for security packets authenticated with Curve25519/AESMMO.
1197 * @param tvb pointer to buffer containing raw packet
1198 * @param pinfo pointer to packet information fields
1199 * @param tree pointer to the command subtree
1200 * @param data raw packet private data
1201 * @return offset after command dissection
1203 static int dissect_zb_direct_secur_c25519_aesmmo(tvbuff_t *tvb,
1204 packet_info *pinfo,
1205 proto_tree *tree,
1206 void *data)
1208 return dissect_zb_direct_secur_common(tvb, pinfo, tree, data, 0U, ZB_DIRECT_MSG_ID_SECUR_C25519_AESMMO);
1212 * Dissector for security packets authenticated with Curve25519/SHA256.
1214 * @param tvb pointer to buffer containing raw packet
1215 * @param pinfo pointer to packet information fields
1216 * @param tree pointer to the command subtree
1217 * @param data raw packet private data
1218 * @return offset after command dissection
1220 static int dissect_zb_direct_secur_c25519_sha256(tvbuff_t *tvb,
1221 packet_info *pinfo,
1222 proto_tree *tree,
1223 void *data)
1225 return dissect_zb_direct_secur_common(tvb, pinfo, tree, data, 0U, ZB_DIRECT_MSG_ID_SECUR_C25519_SHA256);
1229 * Dissector for security packets authenticated with curve P-256.
1231 * @param tvb pointer to buffer containing raw packet
1232 * @param pinfo pointer to packet information fields
1233 * @param tree pointer to the command subtree
1234 * @param data raw packet private data
1235 * @return offset after command dissection
1237 static int dissect_zb_direct_secur_p256(tvbuff_t *tvb,
1238 packet_info *pinfo,
1239 proto_tree *tree,
1240 void *data)
1242 return dissect_zb_direct_secur_common(tvb, pinfo, tree, data, 0U, ZB_DIRECT_MSG_ID_SECUR_P256);
1245 /*****************************************************************************/
1246 /****************** BLE Service Characteristics Dissectors *******************/
1247 /*****************************************************************************/
1250 * Dissector for Form Network.
1252 * @param tvb pointer to buffer containing raw packet
1253 * @param pinfo pointer to packet information fields
1254 * @param tree pointer to subtree
1255 * @param data raw packet private data
1256 * @return offset after dissection
1258 static int dissect_zb_direct_formation(tvbuff_t *tvb,
1259 packet_info *pinfo,
1260 proto_tree *tree,
1261 void *data)
1263 proto_item* ti;
1264 unsigned offset = 0;
1266 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_form_uuid);
1267 ti = proto_tree_add_item(tree, hf_zb_direct_char_form, tvb, offset, 0, ENC_NA);
1268 proto_item_set_generated(ti);
1270 col_set_str(pinfo->cinfo, COL_INFO, "FORM Request");
1272 if (tree)
1274 offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, data,
1275 ZBEE_TLV_SRC_TYPE_ZB_DIRECT,
1276 ZB_DIRECT_MSG_ID_FORMATION);
1279 return offset;
1283 * Dissector for Commissioning Status.
1285 * @param tvb pointer to buffer containing raw packet
1286 * @param pinfo pointer to packet information fields
1287 * @param tree pointer to subtree
1288 * @param data raw packet private data
1289 * @return offset after dissection
1291 static int dissect_zb_direct_status(tvbuff_t *tvb,
1292 packet_info *pinfo,
1293 proto_tree *tree,
1294 void *data)
1296 proto_item* ti;
1297 unsigned offset = 0;
1298 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_status_uuid);
1299 ti = proto_tree_add_item(tree, hf_zb_direct_char_status, tvb, offset, 0, ENC_NA);
1300 proto_item_set_generated(ti);
1302 col_set_str(pinfo->cinfo, COL_INFO, "COMM STATUS Notification");
1304 offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, data,
1305 ZBEE_TLV_SRC_TYPE_ZB_DIRECT,
1306 ZB_DIRECT_MSG_ID_STATUS);
1308 return offset;
1312 * Dissector for Join Network.
1314 * @param tvb pointer to buffer containing raw packet
1315 * @param pinfo pointer to packet information fields
1316 * @param tree pointer to subtree
1317 * @param data raw packet private data
1318 * @return offset after dissection
1320 static int dissect_zb_direct_join(tvbuff_t *tvb,
1321 packet_info *pinfo,
1322 proto_tree *tree,
1323 void *data)
1325 proto_item* ti;
1326 unsigned offset = 0;
1328 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_join_uuid);
1329 ti = proto_tree_add_item(tree, hf_zb_direct_char_join, tvb, offset, 0, ENC_NA);
1330 proto_item_set_generated(ti);
1332 col_set_str(pinfo->cinfo, COL_INFO, "JOIN Request");
1334 if (tree)
1336 offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, data,
1337 ZBEE_TLV_SRC_TYPE_ZB_DIRECT,
1338 ZB_DIRECT_MSG_ID_JOIN);
1341 return offset;
1345 * Dissector for Permit Joining.
1347 * @param tvb pointer to buffer containing raw packet
1348 * @param pinfo pointer to packet information fields
1349 * @param tree pointer to subtree
1350 * @param data raw packet private data
1351 * @return offset after dissection
1353 static int dissect_zb_direct_permit_join(tvbuff_t *tvb,
1354 packet_info *pinfo,
1355 proto_tree *tree,
1356 void *data)
1358 proto_item* ti;
1359 unsigned offset = 0;
1361 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_permit_uuid);
1362 ti = proto_tree_add_item(tree, hf_zb_direct_char_permit_join, tvb, offset, 0, ENC_NA);
1363 proto_item_set_generated(ti);
1365 col_set_str(pinfo->cinfo, COL_INFO, "PERMIT JOIN Request");
1367 if (offset < tvb_reported_length(tvb))
1369 uint32_t parent_time;
1371 proto_tree_add_item_ret_uint(tree, hf_zb_direct_comm_permit_time, tvb, offset, 1, ENC_LITTLE_ENDIAN, &parent_time);
1372 offset += 1;
1374 if (parent_time > 0)
1376 col_append_fstr(pinfo->cinfo, COL_INFO, ": open for %us", parent_time);
1378 else
1380 col_append_str(pinfo->cinfo, COL_INFO, ": close");
1384 return offset;
1388 * Dissector for Leave Networ.
1390 * @param tvb pointer to buffer containing raw packet
1391 * @param pinfo pointer to packet information fields
1392 * @param tree pointer to subtree
1393 * @param data raw packet private data
1394 * @return offset after dissection
1396 static int dissect_zb_direct_leave(tvbuff_t *tvb,
1397 packet_info *pinfo,
1398 proto_tree *tree,
1399 void *data)
1401 proto_item* ti;
1402 unsigned offset = 0;
1404 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_leave_uuid);
1405 ti = proto_tree_add_item(tree, hf_zb_direct_char_leave, tvb, offset, 0, ENC_NA);
1406 proto_item_set_generated(ti);
1408 col_set_str(pinfo->cinfo, COL_INFO, "LEAVE Request");
1410 if (offset < tvb_reported_length(tvb))
1412 bool rm_children;
1413 bool rejoin;
1415 proto_tree_add_item_ret_boolean(tree, hf_zb_direct_comm_rm_children, tvb, offset, 1, ENC_LITTLE_ENDIAN, &rm_children);
1416 offset += 1;
1418 proto_tree_add_item_ret_boolean(tree, hf_zb_direct_comm_rejoin, tvb, offset, 1, ENC_LITTLE_ENDIAN, &rejoin);
1419 offset += 1;
1421 col_append_fstr(pinfo->cinfo, COL_INFO, " (remove children: %s, rejoin: %s)", BOOLSTR(rm_children), BOOLSTR(rejoin));
1424 return offset;
1428 * Dissector for Manage Joiners.
1430 * @param tvb pointer to buffer containing raw packet
1431 * @param pinfo pointer to packet information fields
1432 * @param tree pointer to subtree
1433 * @param data raw packet private data
1434 * @return offset after dissection
1436 static int dissect_zb_direct_manage_joiners(tvbuff_t *tvb,
1437 packet_info *pinfo,
1438 proto_tree *tree,
1439 void *data)
1441 proto_item* ti;
1442 unsigned offset = 0;
1444 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_manage_joiners_uuid);
1445 ti = proto_tree_add_item(tree, hf_zb_direct_char_manage_joiners, tvb, offset, 0, ENC_NA);
1446 proto_item_set_generated(ti);
1448 col_set_str(pinfo->cinfo, COL_INFO, "MANAGE JOINERS Request");
1450 if (tree)
1452 offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, data,
1453 ZBEE_TLV_SRC_TYPE_ZB_DIRECT,
1454 ZB_DIRECT_MSG_ID_MANAGE_JOINERS);
1457 return offset;
1461 * Dissector for Indentify.
1463 * @param tvb pointer to buffer containing raw packet
1464 * @param pinfo pointer to packet information fields
1465 * @param tree pointer to subtree
1466 * @param data raw packet private data
1467 * @return offset after dissection
1469 static int dissect_zb_direct_identify(tvbuff_t *tvb,
1470 packet_info *pinfo,
1471 proto_tree *tree,
1472 void *data)
1474 proto_item* ti;
1475 unsigned offset = 0;
1476 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_identify_uuid);
1477 ti = proto_tree_add_item(tree, hf_zb_direct_char_identify, tvb, offset, 0, ENC_NA);
1478 proto_item_set_generated(ti);
1480 col_set_str(pinfo->cinfo, COL_INFO, "IDENTIFY Request");
1482 if (offset < tvb_reported_length(tvb))
1484 uint32_t parent_time;
1486 proto_tree_add_item_ret_uint(tree, hf_zb_direct_comm_identify_time, tvb, offset, 2, ENC_LITTLE_ENDIAN, &parent_time);
1487 offset += 2;
1489 if (parent_time > 0)
1491 col_append_fstr(pinfo->cinfo, COL_INFO, ": start for %us", parent_time);
1493 else
1495 col_append_str(pinfo->cinfo, COL_INFO, ": stop");
1499 return offset;
1503 * Dissector for Finding & Binding.
1505 * @param tvb pointer to buffer containing raw packet
1506 * @param pinfo pointer to packet information fields
1507 * @param tree pointer to subtree
1508 * @param data raw packet private data
1509 * @return offset after dissection
1511 static int dissect_zb_direct_finding_binding(tvbuff_t *tvb,
1512 packet_info *pinfo,
1513 proto_tree *tree,
1514 void *data)
1516 proto_item* ti;
1517 unsigned offset = 0;
1519 offset = dissect_zb_direct_common(&tvb, pinfo, &tree, data, offset, serv_comm_uuid, char_finding_binding_uuid);
1520 ti = proto_tree_add_item(tree, hf_zb_direct_char_finding_binding, tvb, offset, 0, ENC_NA);
1521 proto_item_set_generated(ti);
1523 col_set_str(pinfo->cinfo, COL_INFO, "FINDING & BINDING Request");
1525 if (offset < tvb_reported_length(tvb))
1527 uint32_t endpoint;
1528 bool initiator;
1530 proto_tree_add_item_ret_uint(tree, hf_zb_direct_comm_fb_endpoint, tvb, offset, 1, ENC_LITTLE_ENDIAN, &endpoint);
1531 offset += 1;
1532 proto_tree_add_item_ret_boolean(tree, hf_zb_direct_comm_fb_initiator, tvb, offset, 1, ENC_LITTLE_ENDIAN, &initiator);
1533 offset += 1;
1535 col_append_fstr(pinfo->cinfo, COL_INFO, " (endpoint: %u, initiator: %s)", endpoint, BOOLSTR(initiator));
1538 return offset;
1542 * Helper dissector for Tunneling.
1544 * @param tvb pointer to buffer containing raw packet
1545 * @param pinfo pointer to packet information fields
1546 * @param tree pointer to subtree
1547 * @param data raw packet private data
1548 * @return offset after dissection
1550 static int dissect_zb_direct_tunneling(tvbuff_t *tvb,
1551 packet_info *pinfo,
1552 proto_tree *tree,
1553 void *data)
1555 proto_item* ti;
1556 unsigned offset = 0;
1558 offset = dissect_zb_direct_common(&tvb,
1559 pinfo,
1560 &tree,
1561 data,
1562 offset,
1563 serv_tunnel_uuid,
1564 char_tunnel_uuid);
1567 ti = proto_tree_add_item(tree, hf_zb_direct_char_tunneling, tvb, offset, 0, ENC_NA);
1568 proto_item_set_generated(ti);
1570 offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, data,
1571 ZBEE_TLV_SRC_TYPE_ZB_DIRECT,
1572 ZB_DIRECT_MSG_ID_TUNNELING);
1574 return offset;
1577 /*****************************************************************************/
1578 /******************************* Registration ********************************/
1579 /*****************************************************************************/
1582 * ZigBee Direct initialization routine.
1584 static void zb_direct_init(void)
1586 for (int i = 0; i < MAX_CONNECTIONS; i++)
1588 enc_h[i].counter = 0;
1590 for (int j = 0; j < MAX_CRYPT_TOGGLES && enc_h[i].states[j] != 0; j++)
1592 enc_h[i].states[j] = 0;
1598 * ZigBee Direct clean routine.
1600 static void zb_direct_cleanup(void)
1602 /* Empty temporary keys */
1603 while (zbee_pc_keyring && keyrec(zbee_pc_keyring)->frame_num > 0)
1605 GSList *element = zbee_pc_keyring;
1607 zbee_pc_keyring = g_slist_delete_link(zbee_pc_keyring, element);
1612 * ZigBee Direct registration routine.
1614 void proto_register_zb_direct(void)
1616 static hf_register_info hf[] =
1618 { &hf_zb_direct_unrecognized_msg,
1619 { "Unrecognized message", "zbd.unrecognized",
1620 FT_BYTES, SEP_SPACE,
1621 NULL, 0x0,
1622 NULL, HFILL }
1624 { &hf_zb_direct_info_type,
1625 { "Type", "zbd.dump_info.type",
1626 FT_UINT8, BASE_DEC,
1627 VALS(info_type_str), 0x0,
1628 NULL, HFILL }
1630 { &hf_zb_direct_info_key,
1631 { "Key", "zbd.key",
1632 FT_BYTES, SEP_SPACE,
1633 NULL, 0x0,
1634 NULL, HFILL }
1636 { &hf_zb_direct_info_zdd_ieee,
1637 { "ZDD IEEE Address", "zbd.dump_info.zdd_addr",
1638 FT_UINT64, BASE_HEX,
1639 NULL, 0x0,
1640 NULL, HFILL }
1642 { &hf_zb_direct_info_zvd_ieee,
1643 { "ZVD IEEE Address", "zbd.dump_info.zvd_addr",
1644 FT_UINT64, BASE_HEX,
1645 NULL, 0x0,
1646 NULL, HFILL }
1648 { &hf_zb_direct_info_encryption,
1649 { "Encryption enabled", "zbd.encryption_status",
1650 FT_BOOLEAN, BASE_NONE,
1651 NULL, 0x0,
1652 NULL, HFILL }
1654 /* secur */
1655 { &hf_zb_direct_msg_type,
1656 { "Message type", "zbd.secur.msg_type",
1657 FT_UINT8, BASE_HEX,
1658 VALS(msg_type_str), 0x0,
1659 NULL, HFILL }
1662 /* Markers */
1663 { &hf_zb_direct_char_info,
1664 { "Dump info", "zbd.dump_info",
1665 FT_NONE, BASE_NONE,
1666 NULL, 0x0,
1667 NULL, HFILL }
1669 { &hf_zb_direct_char_c25519_aesmmo,
1670 { "Characteristic: Security / C25519-AES-MMO", "zbd.secur.c25519_aesmmo",
1671 FT_NONE, BASE_NONE,
1672 NULL, 0x0,
1673 NULL, HFILL }
1675 { &hf_zb_direct_char_c25519_sha256,
1676 { "Characteristic: Security / C25519-SHA-256", "zbd.secur.c25519_sha256",
1677 FT_NONE, BASE_NONE,
1678 NULL, 0x0,
1679 NULL, HFILL }
1681 { &hf_zb_direct_char_p256,
1682 { "Characteristic: Security / P-256", "zbd.secur.p256",
1683 FT_NONE, BASE_NONE,
1684 NULL, 0x0,
1685 NULL, HFILL }
1687 { &hf_zb_direct_char_form,
1688 { "Characteristic: Commissioning / Formation", "zbd.comm.form",
1689 FT_NONE, BASE_NONE,
1690 NULL, 0x0,
1691 NULL, HFILL }
1693 { &hf_zb_direct_char_status,
1694 { "Characteristic: Commissioning / Status", "zbd.comm.status",
1695 FT_NONE, BASE_NONE,
1696 NULL, 0x0,
1697 NULL, HFILL }
1699 { &hf_zb_direct_char_join,
1700 { "Characteristic: Commissioning / Join", "zbd.comm.join",
1701 FT_NONE, BASE_NONE,
1702 NULL, 0x0,
1703 NULL, HFILL }
1705 { &hf_zb_direct_char_permit_join,
1706 { "Characteristic: Commissioning / Permit Join", "zbd.comm.permit_join",
1707 FT_NONE, BASE_NONE,
1708 NULL, 0x0,
1709 NULL, HFILL }
1711 { &hf_zb_direct_char_leave,
1712 { "Characteristic: Commissioning / Leave", "zbd.comm.leave",
1713 FT_NONE, BASE_NONE,
1714 NULL, 0x0,
1715 NULL, HFILL }
1717 { &hf_zb_direct_char_manage_joiners,
1718 { "Characteristic: Commissioning / Manage Joiners", "zbd.comm.manage_joiners",
1719 FT_NONE, BASE_NONE,
1720 NULL, 0x0,
1721 NULL, HFILL }
1723 { &hf_zb_direct_char_identify,
1724 { "Characteristic: Commissioning / Identify", "zbd.comm.identify",
1725 FT_NONE, BASE_NONE,
1726 NULL, 0x0,
1727 NULL, HFILL }
1729 { &hf_zb_direct_char_finding_binding,
1730 { "Characteristic: Commissioning / Finding & Binding", "zbd.comm.finding_binding",
1731 FT_NONE, BASE_NONE,
1732 NULL, 0x0,
1733 NULL, HFILL }
1735 { &hf_zb_direct_char_tunneling,
1736 { "Characteristic: Tunneling", "zbd.comm.tunneling",
1737 FT_NONE, BASE_NONE,
1738 NULL, 0x0,
1739 NULL, HFILL }
1742 /* Subtrees elements */
1743 { &hf_zb_direct_comm_permit_time,
1744 { "Permit time interval (sec)", "zbd.comm.permit_time",
1745 FT_UINT8, BASE_DEC,
1746 NULL, 0x0,
1747 NULL, HFILL }
1749 { &hf_zb_direct_comm_rejoin,
1750 { "Rejoin", "zbd.comm.rejoin",
1751 FT_BOOLEAN, BASE_NONE,
1752 NULL, 0x0,
1753 NULL, HFILL }
1755 { &hf_zb_direct_comm_rm_children,
1756 { "Remove children", "zbd.comm.rm_children",
1757 FT_BOOLEAN, BASE_NONE,
1758 NULL, 0x0,
1759 NULL, HFILL }
1761 { &hf_zb_direct_comm_identify_time,
1762 { "Identify time", "zbd.comm.identify_time",
1763 FT_UINT16, BASE_DEC,
1764 NULL, 0x0,
1765 NULL, HFILL }
1767 { &hf_zb_direct_comm_fb_endpoint,
1768 { "Endpoint", "zbd.comm.fb_endpoint",
1769 FT_UINT8, BASE_DEC,
1770 NULL, 0x0,
1771 NULL, HFILL }
1773 { &hf_zb_direct_comm_fb_initiator,
1774 { "Initiator", "zbd.comm.fb_initiator",
1775 FT_BOOLEAN, BASE_NONE,
1776 NULL, 0x0,
1777 NULL, HFILL }
1781 static ei_register_info ei[] = {
1782 { &ei_zb_direct_crypt_error,
1783 { "zbd.error.decryption", PI_UNDECODED, PI_WARN,
1784 "Decryption fail",
1785 EXPFILL }
1789 /* Setup protocol subtree array */
1790 static int *ett[] =
1792 &ett_zb_direct,
1795 expert_module_t *expert_zb_direct;
1797 proto_zb_direct = proto_register_protocol("ZigBee Direct", /* name */
1798 "ZBD", /* short_name */
1799 "zbd"); /* filter_name */
1801 proto_register_field_array(proto_zb_direct, hf, array_length(hf));
1802 proto_register_subtree_array(ett, array_length(ett));
1804 expert_zb_direct = expert_register_protocol(proto_zb_direct);
1805 expert_register_field_array(expert_zb_direct, ei, array_length(ei));
1807 register_init_routine(zb_direct_init);
1808 register_cleanup_routine(zb_direct_cleanup);
1810 module_t *zbd_prefs = prefs_register_protocol(proto_zb_direct, NULL);
1812 static uat_field_t key_uat_fields[] =
1814 UAT_FLD_CSTRING(uat_key_records, zdd_ieee, "ZDD IEEE",
1815 "A 8-byte address of ZDD in hexadecimal with optional "
1816 "dash-, colon-, or space-separator characters, "
1817 "in Big Endian"),
1818 UAT_FLD_CSTRING(uat_key_records, zvd_ieee, "ZVD IEEE",
1819 "A 8-byte address of ZVD in hexadecimal with optional "
1820 "dash-, colon-, or space-separator characters, "
1821 "in Big Endian"),
1822 UAT_FLD_CSTRING(uat_key_records, key, "Key",
1823 "A 16-byte session key in hexadecimal with optional "
1824 "dash-, colon-, or space-separator characters, "
1825 "in Big Endian"),
1827 UAT_FLD_CSTRING(uat_key_records, label, "Label", "User comment"),
1828 UAT_END_FIELDS
1831 /* Affects dissection of packets, but not set of named fields */
1832 unsigned uat_flags = UAT_AFFECTS_DISSECTION;
1834 zbd_secur_key_table_uat = uat_new("Pre-configured Keys",
1835 sizeof(uat_key_record_t),
1836 "zigbee_direct_pc_keys",
1837 true,
1838 &uat_key_records,
1839 &num_uat_key_records,
1840 uat_flags,
1841 NULL, /** TODO: ptr to help manual? */
1842 uat_key_record_copy_cb,
1843 uat_key_record_update_cb,
1844 uat_key_record_free_cb,
1845 uat_key_record_post_update,
1846 NULL,
1847 key_uat_fields);
1849 prefs_register_uat_preference(zbd_prefs,
1850 "key_table",
1851 "Pre-configured Keys",
1852 "Pre-configured session keys",
1853 zbd_secur_key_table_uat);
1855 prefs_register_bool_preference(zbd_prefs,
1856 "ignore_late_keys",
1857 "Ignore Late Keys",
1858 "Whether or not dissector shall ignore keys, "
1859 "which were provided after current packet "
1860 "during decryption",
1861 &ignore_late_keys);
1865 * ZigBee Direct handoff routine.
1867 void proto_reg_handoff_zb_direct(void)
1869 typedef struct
1871 const char * const uuid;
1872 char * const description;
1873 dissector_t dissector;
1874 } zb_direct_service_t;
1876 static zb_direct_service_t services[] =
1878 { "29144af4-00ff-4481-bfe9-6d0299b429e3", "ZBD Dump Info", dissect_zb_direct_dump_info },
1880 /* 6.5.1. Zigbee Direct Security Service characteristic */
1881 { "29144af4-0001-4481-bfe9-6d0299b429e3", "ZBD Authenticate SPEKE/Curve25519/AES-MMO-128/HMAC-AES-MMO-128", dissect_zb_direct_secur_c25519_aesmmo },
1882 { "29144af4-0002-4481-bfe9-6d0299b429e3", "ZBD Authenticate SPEKE/Curve25519/SHA-256/HMAC-SHA-256-128", dissect_zb_direct_secur_c25519_sha256 },
1883 { "29144af4-0003-4481-bfe9-6d0299b429e3", "ZBD Authenticate ECDHE-PSK/P-256/SHA-256/HMAC-SHA-256-128", dissect_zb_direct_secur_p256 },
1885 /* 7.7.2.3. Zigbee Direct Commissioning Service characteristics */
1886 { "7072377d-0001-421c-b163-491c27333a61", "ZBD Form Network", dissect_zb_direct_formation },
1887 { "7072377d-0002-421c-b163-491c27333a61", "ZBD Join Network", dissect_zb_direct_join },
1888 { "7072377d-0003-421c-b163-491c27333a61", "ZBD Permit Joining", dissect_zb_direct_permit_join },
1889 { "7072377d-0004-421c-b163-491c27333a61", "ZBD Leave Network", dissect_zb_direct_leave },
1890 { "7072377d-0005-421c-b163-491c27333a61", "ZBD Commissioning Status", dissect_zb_direct_status },
1891 { "7072377d-0006-421c-b163-491c27333a61", "ZBD Manage Joiners", dissect_zb_direct_manage_joiners },
1892 { "7072377d-0007-421c-b163-491c27333a61", "ZBD Identify", dissect_zb_direct_identify },
1893 { "7072377d-0008-421c-b163-491c27333a61", "ZBD Finding & Binding", dissect_zb_direct_finding_binding },
1895 /* 7.7.3.3. Zigbee Direct Tunnel Service characteristics */
1896 { "8bd178fd-0001-45f4-8120-b2378bd5313f", "ZBD Tunnel Service NPDU", dissect_zb_direct_tunneling },
1897 { NULL, NULL, NULL },
1900 for (size_t i = 0; services[i].uuid; i++)
1902 wmem_tree_insert_string(bluetooth_uuids, services[i].uuid, services[i].description, 0);
1904 dissector_handle_t handle = create_dissector_handle_with_name_and_description(
1905 services[i].dissector, proto_zb_direct,
1906 NULL, services[i].description);
1907 dissector_add_string("bluetooth.uuid", services[i].uuid, handle);
1910 zbee_nwk_handle = find_dissector("zbee_nwk");
1914 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1916 * Local variables:
1917 * c-basic-offset: 4
1918 * tab-width: 8
1919 * indent-tabs-mode: nil
1920 * End:
1922 * vi: set shiftwidth=4 tabstop=8 expandtab:
1923 * :indentSize=4:tabSize=8:noTabs=true: