Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-zbee-nwk.c
Line
Count
Source
1
/* packet-zbee-nwk.c
2
 * Dissector routines for the ZigBee Network Layer (NWK)
3
 * By Owen Kirby <osk@exegin.com>
4
 * Copyright 2009 Exegin Technologies Limited
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/*  Include Files */
14
#include "config.h"
15
16
17
#include <epan/packet.h>
18
#include <epan/exceptions.h>
19
#include <epan/prefs.h>
20
#include <epan/addr_resolv.h>
21
#include <epan/address_types.h>
22
#include <epan/expert.h>
23
#include <epan/proto_data.h>
24
#include <epan/conversation_table.h>
25
#include <epan/conversation_filter.h>
26
#include <epan/tap.h>
27
#include <wsutil/bits_ctz.h>    /* for ws_ctz */
28
#include <wsutil/pint.h>
29
#include "packet-ieee802154.h"
30
#include "packet-zbee.h"
31
#include "packet-zbee-nwk.h"
32
#include "packet-zbee-aps.h"    /* for ZBEE_APS_CMD_KEY_LENGTH */
33
#include "packet-zbee-zdp.h"
34
#include "packet-zbee-security.h"
35
#include "packet-zbee-tlv.h"
36
37
/*************************/
38
/* Function Declarations */
39
/*************************/
40
/* Dissector Routines */
41
static int         dissect_zbee_nwk        (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
42
static void        dissect_zbee_nwk_cmd    (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet* packet);
43
static int         dissect_zbee_beacon     (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
44
static int         dissect_zbip_beacon     (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
45
static int         dissect_zbee_ie         (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data);
46
static void        dissect_ieee802154_zigbee_rejoin(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, unsigned *offset);
47
static void        dissect_ieee802154_zigbee_txpower(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, unsigned *offset);
48
49
/* Command Dissector Helpers */
50
static unsigned    dissect_zbee_nwk_route_req  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
51
                                                zbee_nwk_packet * packet, unsigned offset);
52
static unsigned    dissect_zbee_nwk_route_rep  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, uint8_t version);
53
static unsigned    dissect_zbee_nwk_status     (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset);
54
static unsigned    dissect_zbee_nwk_leave      (tvbuff_t *tvb, proto_tree *tree, unsigned offset);
55
static unsigned    dissect_zbee_nwk_route_rec  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
56
                                                zbee_nwk_packet * packet, unsigned offset);
57
static unsigned    dissect_zbee_nwk_rejoin_req (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
58
                                                zbee_nwk_packet * packet, unsigned offset);
59
static unsigned    dissect_zbee_nwk_rejoin_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
60
                                                zbee_nwk_packet * packet, unsigned offset);
61
static unsigned    dissect_zbee_nwk_link_status(tvbuff_t *tvb, proto_tree *tree, unsigned offset);
62
static unsigned    dissect_zbee_nwk_report     (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset);
63
static unsigned    dissect_zbee_nwk_update     (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset);
64
static unsigned    dissect_zbee_nwk_ed_timeout_request(tvbuff_t *tvb, proto_tree *tree, unsigned offset);
65
static unsigned    dissect_zbee_nwk_ed_timeout_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset);
66
static unsigned    dissect_zbee_nwk_link_pwr_delta(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset);
67
static unsigned    dissect_zbee_nwk_commissioning_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
68
                                                        zbee_nwk_packet * packet, unsigned offset);
69
static unsigned    dissect_zbee_nwk_commissioning_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
70
                                                         zbee_nwk_packet * packet, unsigned offset);
71
static void        proto_init_zbee_nwk         (void);
72
static void        proto_cleanup_zbee_nwk(void);
73
void               proto_register_zbee_nwk(void);
74
void               proto_reg_handoff_zbee_nwk(void);
75
76
/********************/
77
/* Global Variables */
78
/********************/
79
static int proto_zbee_nwk;
80
static int proto_zbee_beacon;
81
static int proto_zbip_beacon;
82
static int proto_zbee_ie;
83
static int hf_zbee_nwk_fcf;
84
static int hf_zbee_nwk_frame_type;
85
static int hf_zbee_nwk_proto_version;
86
static int hf_zbee_nwk_discover_route;
87
static int hf_zbee_nwk_multicast;
88
static int hf_zbee_nwk_security;
89
static int hf_zbee_nwk_source_route;
90
static int hf_zbee_nwk_ext_dst;
91
static int hf_zbee_nwk_ext_src;
92
static int hf_zbee_nwk_end_device_initiator;
93
static int hf_zbee_nwk_dst;
94
static int hf_zbee_nwk_src;
95
static int hf_zbee_nwk_addr;
96
static int hf_zbee_nwk_radius;
97
static int hf_zbee_nwk_seqno;
98
static int hf_zbee_nwk_mcast;
99
static int hf_zbee_nwk_mcast_mode;
100
static int hf_zbee_nwk_mcast_radius;
101
static int hf_zbee_nwk_mcast_max_radius;
102
static int hf_zbee_nwk_dst64;
103
static int hf_zbee_nwk_src64;
104
static int hf_zbee_nwk_addr64;
105
static int hf_zbee_nwk_src64_origin;
106
static int hf_zbee_nwk_relay_count;
107
static int hf_zbee_nwk_relay_index;
108
static int hf_zbee_nwk_relay;
109
110
static int hf_zbee_nwk_cmd_id;
111
static int hf_zbee_nwk_cmd_addr;
112
static int hf_zbee_nwk_cmd_route_id;
113
static int hf_zbee_nwk_cmd_route_dest;
114
static int hf_zbee_nwk_cmd_route_orig;
115
static int hf_zbee_nwk_cmd_route_resp;
116
static int hf_zbee_nwk_cmd_route_dest_ext;
117
static int hf_zbee_nwk_cmd_route_orig_ext;
118
static int hf_zbee_nwk_cmd_route_resp_ext;
119
static int hf_zbee_nwk_cmd_route_cost;
120
static int hf_zbee_nwk_cmd_route_options;
121
static int hf_zbee_nwk_cmd_route_opt_repair;
122
static int hf_zbee_nwk_cmd_route_opt_multicast;
123
static int hf_zbee_nwk_cmd_route_opt_dest_ext;
124
static int hf_zbee_nwk_cmd_route_opt_resp_ext;
125
static int hf_zbee_nwk_cmd_route_opt_orig_ext;
126
static int hf_zbee_nwk_cmd_route_opt_many_to_one;
127
static int hf_zbee_nwk_cmd_nwk_status;
128
static int hf_zbee_nwk_cmd_nwk_status_command_id;
129
static int hf_zbee_nwk_cmd_leave_rejoin;
130
static int hf_zbee_nwk_cmd_leave_request;
131
static int hf_zbee_nwk_cmd_leave_children;
132
static int hf_zbee_nwk_cmd_relay_count;
133
static int hf_zbee_nwk_cmd_relay_device;
134
static int hf_zbee_nwk_cmd_cinfo;
135
static int hf_zbee_nwk_cmd_cinfo_alt_coord;
136
static int hf_zbee_nwk_cmd_cinfo_type;
137
static int hf_zbee_nwk_cmd_cinfo_power;
138
static int hf_zbee_nwk_cmd_cinfo_idle_rx;
139
static int hf_zbee_nwk_cmd_cinfo_security;
140
static int hf_zbee_nwk_cmd_cinfo_alloc;
141
static int hf_zbee_nwk_cmd_rejoin_status;
142
static int hf_zbee_nwk_cmd_link_last;
143
static int hf_zbee_nwk_cmd_link_first;
144
static int hf_zbee_nwk_cmd_link_count;
145
static int hf_zbee_nwk_cmd_link_address;
146
static int hf_zbee_nwk_cmd_link_incoming_cost;
147
static int hf_zbee_nwk_cmd_link_outgoing_cost;
148
static int hf_zbee_nwk_cmd_report_type;
149
static int hf_zbee_nwk_cmd_report_count;
150
static int hf_zbee_nwk_cmd_update_type;
151
static int hf_zbee_nwk_cmd_update_count;
152
static int hf_zbee_nwk_cmd_update_id;
153
static int hf_zbee_nwk_panid;
154
static int hf_zbee_zboss_nwk_cmd_key;
155
static int hf_zbee_nwk_cmd_epid;
156
static int hf_zbee_nwk_cmd_end_device_timeout_request_enum;
157
static int hf_zbee_nwk_cmd_end_device_configuration;
158
static int hf_zbee_nwk_cmd_end_device_timeout_resp_status;
159
static int hf_zbee_nwk_cmd_end_device_timeout_resp_parent_info;
160
static int hf_zbee_nwk_cmd_prnt_info_mac_data_poll_keepalive_supported;
161
static int hf_zbee_nwk_cmd_prnt_info_ed_to_req_keepalive_supported;
162
static int hf_zbee_nwk_cmd_prnt_info_power_negotiation_supported;
163
static int hf_zbee_nwk_cmd_link_pwr_list_count;
164
static int hf_zbee_nwk_cmd_link_pwr_type;
165
static int hf_zbee_nwk_cmd_link_pwr_device_address;
166
static int hf_zbee_nwk_cmd_link_pwr_power_delta;
167
static int hf_zbee_nwk_cmd_association_type;
168
169
/*  ZigBee Beacons */
170
static int hf_zbee_beacon_protocol;
171
static int hf_zbee_beacon_stack_profile;
172
static int hf_zbee_beacon_version;
173
static int hf_zbee_beacon_router_capacity;
174
static int hf_zbee_beacon_depth;
175
static int hf_zbee_beacon_end_device_capacity;
176
static int hf_zbee_beacon_epid;
177
static int hf_zbee_beacon_tx_offset;
178
static int hf_zbee_beacon_update_id;
179
180
static int hf_zbip_beacon_allow_join;
181
static int hf_zbip_beacon_router_capacity;
182
static int hf_zbip_beacon_host_capacity;
183
static int hf_zbip_beacon_unsecure;
184
static int hf_zbip_beacon_network_id;
185
186
/* IEEE 802.15.4 IEs (Information Elements) */
187
static int hf_ieee802154_zigbee_ie;
188
static int hf_ieee802154_zigbee_ie_id;
189
static int hf_ieee802154_zigbee_ie_length;
190
static int hf_ieee802154_zigbee_ie_tx_power;
191
static int hf_ieee802154_zigbee_ie_source_addr;
192
193
static int hf_ieee802154_zigbee_rejoin_epid;
194
static int hf_ieee802154_zigbee_rejoin_source_addr;
195
196
static int ett_zbee_nwk;
197
static int ett_zbee_nwk_beacon;
198
static int ett_zbee_nwk_fcf;
199
static int ett_zbee_nwk_fcf_ext;
200
static int ett_zbee_nwk_mcast;
201
static int ett_zbee_nwk_route;
202
static int ett_zbee_nwk_cmd;
203
static int ett_zbee_nwk_cmd_options;
204
static int ett_zbee_nwk_cmd_cinfo;
205
static int ett_zbee_nwk_cmd_link;
206
static int ett_zbee_nwk_cmd_ed_to_rsp_prnt_info;
207
static int ett_zbee_nwk_cmd_link_pwr_struct;
208
static int ett_zbee_nwk_zigbee_ie_fields;
209
static int ett_zbee_nwk_ie_rejoin;
210
static int ett_zbee_nwk_header;
211
static int ett_zbee_nwk_header_ie;
212
static int ett_zbee_nwk_beacon_bitfield;
213
214
static expert_field ei_zbee_nwk_missing_payload;
215
216
static dissector_handle_t   aps_handle;
217
static dissector_handle_t   zbee_gp_handle;
218
219
static int zbee_nwk_address_type = -1;
220
221
static int zbee_nwk_tap;
222
223
/* Cached protocol identifier */
224
static int proto_ieee802154;
225
226
/********************/
227
/* Field Names      */
228
/********************/
229
/* Frame Types */
230
static const value_string zbee_nwk_frame_types[] = {
231
    { ZBEE_NWK_FCF_DATA,    "Data" },
232
    { ZBEE_NWK_FCF_CMD,     "Command" },
233
    { ZBEE_NWK_FCF_INTERPAN,"Interpan" },
234
    { 0, NULL }
235
};
236
237
/* Route Discovery Modes */
238
static const value_string zbee_nwk_discovery_modes[] = {
239
    { ZBEE_NWK_FCF_DISCOVERY_SUPPRESS,  "Suppress" },
240
    { ZBEE_NWK_FCF_DISCOVERY_ENABLE,    "Enable" },
241
    { ZBEE_NWK_FCF_DISCOVERY_FORCE,     "Force" },
242
    { 0, NULL }
243
};
244
245
/* Command Names*/
246
static const value_string zbee_nwk_cmd_names[] = {
247
    { ZBEE_NWK_CMD_ROUTE_REQ,           "Route Request" },
248
    { ZBEE_NWK_CMD_ROUTE_REPLY,         "Route Reply" },
249
    { ZBEE_NWK_CMD_NWK_STATUS,          "Network Status" },
250
    { ZBEE_NWK_CMD_LEAVE,               "Leave" },
251
    { ZBEE_NWK_CMD_ROUTE_RECORD,        "Route Record" },
252
    { ZBEE_NWK_CMD_REJOIN_REQ,          "Rejoin Request" },
253
    { ZBEE_NWK_CMD_REJOIN_RESP,         "Rejoin Response" },
254
    { ZBEE_NWK_CMD_LINK_STATUS,         "Link Status" },
255
    { ZBEE_NWK_CMD_NWK_REPORT,          "Network Report" },
256
    { ZBEE_NWK_CMD_NWK_UPDATE,          "Network Update" },
257
    { ZBEE_NWK_CMD_ED_TIMEOUT_REQUEST,  "End Device Timeout Request" },
258
    { ZBEE_NWK_CMD_ED_TIMEOUT_RESPONSE, "End Device Timeout Response" },
259
    { ZBEE_NWK_CMD_LINK_PWR_DELTA,      "Link Power Delta" },
260
    { ZBEE_NWK_CMD_COMMISSIONING_REQUEST,  "Network Commissioning Request" },
261
    { ZBEE_NWK_CMD_COMMISSIONING_RESPONSE,  "Network Commissioning Response" },
262
    { 0, NULL }
263
};
264
265
/* Many-To-One Route Discovery Modes. */
266
static const value_string zbee_nwk_cmd_route_many_modes[] = {
267
    { ZBEE_NWK_CMD_ROUTE_OPTION_MANY_NONE,  "Not Many-to-One" },
268
    { ZBEE_NWK_CMD_ROUTE_OPTION_MANY_REC,   "With Source Routing" },
269
    { ZBEE_NWK_CMD_ROUTE_OPTION_MANY_NOREC, "Without Source Routing" },
270
    { 0, NULL }
271
};
272
273
/* Rejoin Status Codes */
274
static const value_string zbee_nwk_rejoin_codes[] = {
275
    { IEEE802154_CMD_ASRSP_AS_SUCCESS,      "Success" },
276
    { IEEE802154_CMD_ASRSP_PAN_FULL,        "PAN Full" },
277
    { IEEE802154_CMD_ASRSP_PAN_DENIED,      "PAN Access Denied" },
278
    { 0, NULL }
279
};
280
281
/* Network Report Types */
282
static const value_string zbee_nwk_report_types[] = {
283
    { ZBEE_NWK_CMD_NWK_REPORT_ID_PAN_CONFLICT,  "PAN Identifier Conflict" },
284
    { ZBEE_NWK_CMD_NWK_REPORT_ID_ZBOSS_KEY_TRACE,  "ZBOSS key trace" },
285
    { 0, NULL }
286
};
287
288
/* Network Update Types */
289
static const value_string zbee_nwk_update_types[] = {
290
    { ZBEE_NWK_CMD_NWK_UPDATE_ID_PAN_UPDATE,  "PAN Identifier Update" },
291
    { 0, NULL }
292
};
293
294
/* Network Status Codes */
295
static const value_string zbee_nwk_status_codes[] = {
296
    { ZBEE_NWK_STATUS_NO_ROUTE_AVAIL,       "No Route Available" },
297
    { ZBEE_NWK_STATUS_TREE_LINK_FAIL,       "Tree Link Failure" },
298
    { ZBEE_NWK_STATUS_NON_TREE_LINK_FAIL,   "Non-tree Link Failure" },
299
    { ZBEE_NWK_STATUS_LOW_BATTERY,          "Low Battery" },
300
    { ZBEE_NWK_STATUS_NO_ROUTING,           "No Routing Capacity" },
301
    { ZBEE_NWK_STATUS_NO_INDIRECT,          "No Indirect Capacity" },
302
    { ZBEE_NWK_STATUS_INDIRECT_EXPIRE,      "Indirect Transaction Expiry" },
303
    { ZBEE_NWK_STATUS_DEVICE_UNAVAIL,       "Target Device Unavailable" },
304
    { ZBEE_NWK_STATUS_ADDR_UNAVAIL,         "Target Address Unallocated" },
305
    { ZBEE_NWK_STATUS_PARENT_LINK_FAIL,     "Parent Link Failure" },
306
    { ZBEE_NWK_STATUS_VALIDATE_ROUTE,       "Validate Route" },
307
    { ZBEE_NWK_STATUS_SOURCE_ROUTE_FAIL,    "Source Route Failure" },
308
    { ZBEE_NWK_STATUS_MANY_TO_ONE_FAIL,     "Many-to-One Route Failure" },
309
    { ZBEE_NWK_STATUS_ADDRESS_CONFLICT,     "Address Conflict" },
310
    { ZBEE_NWK_STATUS_VERIFY_ADDRESS,       "Verify Address" },
311
    { ZBEE_NWK_STATUS_PANID_UPDATE,         "PAN ID Update" },
312
    { ZBEE_NWK_STATUS_ADDRESS_UPDATE,       "Network Address Update" },
313
    { ZBEE_NWK_STATUS_BAD_FRAME_COUNTER,    "Bad Frame Counter" },
314
    { ZBEE_NWK_STATUS_BAD_KEY_SEQNO,        "Bad Key Sequence Number" },
315
    { 0, NULL }
316
};
317
318
/* Stack Profile Values. */
319
static const value_string zbee_nwk_stack_profiles[] = {
320
    { 0x00, "Network Specific" },
321
    { 0x01, "ZigBee Home" },
322
    { 0x02, "ZigBee PRO" },
323
    { 0, NULL }
324
};
325
326
/* ED Requested Timeout Enumerated Values */
327
static const value_string zbee_nwk_end_device_timeout_request[] = {
328
    { 0, "10 sec" },
329
    { 1, "2 min" },
330
    { 2, "4 min" },
331
    { 3, "8 min" },
332
    { 4, "16 min" },
333
    { 5, "32 min" },
334
    { 6, "64 min" },
335
    { 7, "128 min" },
336
    { 8, "256 min" },
337
    { 9, "512 min" },
338
    { 10, "1024 min" },
339
    { 11, "2048 min" },
340
    { 12, "4096 min" },
341
    { 13, "8192 min" },
342
    { 14, "16384 min" },
343
    { 0, NULL }
344
};
345
346
347
/* End Device Timeout Response Status Codes */
348
static const value_string zbee_nwk_end_device_timeout_resp_status[] = {
349
    { 0,      "Success" },
350
    { 1,      "Incorrect value" },
351
    { 0, NULL }
352
};
353
354
/* Names of IEEE 802.15.4 IEs (Information Elements) for ZigBee */
355
static const value_string ieee802154_zigbee_ie_names[] = {
356
    { ZBEE_ZIGBEE_IE_REJOIN,                    "Rejoin"   },
357
    { ZBEE_ZIGBEE_IE_TX_POWER,                  "Tx Power" },
358
    { ZBEE_ZIGBEE_IE_BEACON_PAYLOAD,            "Extended Beacon Payload" },
359
    { 0, NULL }
360
};
361
362
/* Stack Profile Values. */
363
static const value_string zbee_nwk_link_power_delta_types[] = {
364
    { 0x00, "Notification" },
365
    { 0x01, "Request" },
366
    { 0x02, "Response" },
367
    { 0x03, "Reserved" },
368
    { 0, NULL }
369
};
370
371
static const value_string zbee_nwk_commissioning_types[] = {
372
    { 0x00, "Initial Join" },
373
    { 0x01, "Rejoin" },
374
    { 0x02, "Establish Trusted Link" },
375
    { 0, NULL }
376
};
377
378
/* TODO: much of the following copied from ieee80154 dissector */
379
/*-------------------------------------
380
 * Hash Tables and Lists
381
 *-------------------------------------
382
 */
383
ieee802154_map_tab_t zbee_nwk_map;
384
GHashTable *zbee_table_nwk_keyring;
385
GHashTable *zbee_table_link_keyring;
386
387
static int zbee_nwk_address_to_str(const address* addr, char *buf, int buf_len)
388
6.86k
{
389
6.86k
    uint16_t zbee_nwk_addr = pletohu16(addr->data);
390
391
6.86k
    if ((zbee_nwk_addr == ZBEE_BCAST_ALL) || (zbee_nwk_addr == ZBEE_BCAST_ACTIVE) || (zbee_nwk_addr == ZBEE_BCAST_ROUTERS)) {
392
32
        return (int)g_strlcpy(buf, "Broadcast", buf_len) + 1;
393
32
    }
394
6.83k
    else {
395
6.83k
        return snprintf(buf, buf_len, "0x%04x", zbee_nwk_addr) + 1;
396
6.83k
    }
397
6.86k
}
398
399
static int zbee_nwk_address_str_len(const address* addr _U_)
400
6.86k
{
401
6.86k
    return sizeof("Broadcast");
402
6.86k
}
403
404
static int zbee_nwk_address_len(void)
405
0
{
406
0
    return sizeof(uint16_t);
407
0
}
408
409
/**
410
 *Extracts an integer sub-field from an int with a given mask
411
 *
412
*/
413
unsigned
414
zbee_get_bit_field(unsigned input, unsigned mask)
415
104k
{
416
    /* Sanity Check, don't want infinite loops. */
417
104k
    if (mask == 0) return 0;
418
    /* Shift input and mask together. */
419
527k
    while (!(mask & 0x1)) {
420
422k
        input >>= 1;
421
422k
        mask >>=1;
422
422k
    } /* while */
423
104k
    return (input & mask);
424
104k
} /* zbee_get_bit_field */
425
426
/**
427
 *Heuristic interpreter for the ZigBee network dissectors.
428
 *
429
 *@param tvb pointer to buffer containing raw packet.
430
 *@param pinfo pointer to packet information fields
431
 *@param tree pointer to data tree Wireshark uses to display packet.
432
 *@return Boolean value, whether it handles the packet or not.
433
*/
434
static bool
435
dissect_zbee_nwk_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
436
5.26k
{
437
5.26k
    ieee802154_packet   *packet = (ieee802154_packet *)data;
438
5.26k
    uint16_t            fcf;
439
5.26k
    unsigned            ver;
440
5.26k
    unsigned            type;
441
442
    /* All ZigBee frames must always have a 16-bit source and destination address. */
443
5.26k
    if (packet == NULL) return false;
444
445
    /* If the frame type and version are not sane, then it's probably not ZigBee. */
446
5.26k
    fcf = tvb_get_letohs(tvb, 0);
447
5.26k
    ver = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_VERSION);
448
5.26k
    type = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_FRAME_TYPE);
449
5.26k
    if ((ver < ZBEE_VERSION_2004) || (ver > ZBEE_VERSION_2007)) return false;
450
3.84k
    if (!try_val_to_str(type, zbee_nwk_frame_types)) return false;
451
452
    /* All interpan frames should originate from an extended address. */
453
3.83k
    if (type == ZBEE_NWK_FCF_INTERPAN) {
454
392
        if (packet->src_addr_mode != IEEE802154_FCF_ADDR_EXT) return false;
455
392
    }
456
    /* All other ZigBee frames must have 16-bit source and destination addresses. */
457
3.44k
    else {
458
3.44k
        if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) return false;
459
3.44k
        if (packet->dst_addr_mode != IEEE802154_FCF_ADDR_SHORT) return false;
460
3.44k
    }
461
462
    /* Assume it's ZigBee */
463
3.82k
    dissect_zbee_nwk(tvb, pinfo, tree, packet);
464
3.82k
    return true;
465
3.83k
} /* dissect_zbee_heur */
466
467
/**
468
 *ZigBee NWK packet dissection routine for 2006, 2007 and Pro stack versions.
469
 *
470
 *@param tvb pointer to buffer containing raw packet.
471
 *@param pinfo pointer to packet information fields.
472
 *@param tree pointer to data tree Wireshark uses to display packet.
473
 *@param data raw packet private data.
474
*/
475
476
static int
477
dissect_zbee_nwk_full(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
478
3.82k
{
479
3.82k
    tvbuff_t            *payload_tvb = NULL;
480
481
3.82k
    proto_item          *proto_root;
482
3.82k
    proto_item          *ti = NULL;
483
3.82k
    proto_tree          *nwk_tree;
484
485
3.82k
    zbee_nwk_packet     packet;
486
3.82k
    ieee802154_packet   *ieee_packet;
487
488
3.82k
    unsigned            offset = 0;
489
3.82k
    char                *src_addr, *dst_addr;
490
491
3.82k
    uint16_t            fcf;
492
493
3.82k
    ieee802154_short_addr   addr16;
494
3.82k
    ieee802154_map_rec     *map_rec;
495
3.82k
    ieee802154_hints_t     *ieee_hints;
496
497
3.82k
    zbee_nwk_hints_t       *nwk_hints;
498
3.82k
    bool                    unicast_src;
499
500
3.82k
    static int * const fcf_flags_2007[] = {
501
3.82k
        &hf_zbee_nwk_frame_type,
502
3.82k
        &hf_zbee_nwk_proto_version,
503
3.82k
        &hf_zbee_nwk_discover_route,
504
3.82k
        &hf_zbee_nwk_multicast,
505
3.82k
        &hf_zbee_nwk_security,
506
3.82k
        &hf_zbee_nwk_source_route,
507
3.82k
        &hf_zbee_nwk_ext_dst,
508
3.82k
        &hf_zbee_nwk_ext_src,
509
3.82k
        &hf_zbee_nwk_end_device_initiator,
510
3.82k
        NULL
511
3.82k
    };
512
513
3.82k
    static int * const fcf_flags[] = {
514
3.82k
        &hf_zbee_nwk_frame_type,
515
3.82k
        &hf_zbee_nwk_proto_version,
516
3.82k
        &hf_zbee_nwk_discover_route,
517
3.82k
        &hf_zbee_nwk_security,
518
3.82k
        NULL
519
3.82k
    };
520
521
    /* Reject the packet if data is NULL */
522
3.82k
    if (data == NULL)
523
0
        return 0;
524
3.82k
    ieee_packet = (ieee802154_packet *)data;
525
526
3.82k
    memset(&packet, 0, sizeof(packet));
527
528
    /* Set up hint structures */
529
3.82k
    if (!pinfo->fd->visited) {
530
        /* Allocate frame data with hints for upper layers */
531
3.82k
        nwk_hints = wmem_new0(wmem_file_scope(), zbee_nwk_hints_t);
532
3.82k
        p_add_proto_data(wmem_file_scope(), pinfo, proto_zbee_nwk, 0, nwk_hints);
533
3.82k
    } else {
534
        /* Retrieve existing structure */
535
0
        nwk_hints = (zbee_nwk_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_zbee_nwk, 0);
536
0
    }
537
538
3.82k
    ieee_hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ieee802154, 0);
539
540
    /* Add ourself to the protocol column, clear the info column, and create the protocol tree. */
541
3.82k
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZigBee");
542
3.82k
    col_clear(pinfo->cinfo, COL_INFO);
543
3.82k
    proto_root = proto_tree_add_item(tree, proto_zbee_nwk, tvb, offset, -1, ENC_NA);
544
3.82k
    nwk_tree = proto_item_add_subtree(proto_root, ett_zbee_nwk);
545
546
    /* Get and parse the FCF */
547
3.82k
    fcf = tvb_get_letohs(tvb, offset);
548
3.82k
    packet.type         = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_FRAME_TYPE);
549
3.82k
    packet.version      = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_VERSION);
550
3.82k
    packet.discovery    = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_DISCOVER_ROUTE);
551
3.82k
    packet.security     = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_SECURITY);
552
3.82k
    packet.multicast    = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_MULTICAST);
553
3.82k
    packet.route        = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_SOURCE_ROUTE);
554
3.82k
    packet.ext_dst      = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_EXT_DEST);
555
3.82k
    packet.ext_src      = zbee_get_bit_field(fcf, ZBEE_NWK_FCF_EXT_SOURCE);
556
557
    /* Display the FCF. */
558
3.82k
    if (packet.version >= ZBEE_VERSION_2007) {
559
2.43k
        ti = proto_tree_add_bitmask(nwk_tree, tvb, offset, hf_zbee_nwk_fcf, ett_zbee_nwk_fcf, fcf_flags_2007, ENC_LITTLE_ENDIAN);
560
2.43k
    } else {
561
1.38k
        ti = proto_tree_add_bitmask(nwk_tree, tvb, offset, hf_zbee_nwk_fcf, ett_zbee_nwk_fcf, fcf_flags, ENC_LITTLE_ENDIAN);
562
1.38k
    }
563
3.82k
    proto_item_append_text(ti, " %s", val_to_str_const(packet.type, zbee_nwk_frame_types, "Unknown"));
564
3.82k
    offset += 2;
565
566
    /* Add the frame type to the info column and protocol root. */
567
3.82k
    proto_item_append_text(proto_root, " %s", val_to_str_const(packet.type, zbee_nwk_frame_types, "Unknown Type"));
568
3.82k
    col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet.type, zbee_nwk_frame_types, "Reserved Frame Type"));
569
570
3.82k
    if (packet.type != ZBEE_NWK_FCF_INTERPAN) {
571
        /* Get the destination address. */
572
3.43k
        packet.dst = tvb_get_letohs(tvb, offset);
573
574
3.43k
        set_address_tvb(&pinfo->net_dst, zbee_nwk_address_type, 2, tvb, offset);
575
3.43k
        copy_address_shallow(&pinfo->dst, &pinfo->net_dst);
576
3.43k
        dst_addr = address_to_str(pinfo->pool, &pinfo->dst);
577
578
3.43k
        proto_tree_add_uint(nwk_tree, hf_zbee_nwk_dst, tvb, offset, 2, packet.dst);
579
3.43k
        ti = proto_tree_add_uint(nwk_tree, hf_zbee_nwk_addr, tvb, offset, 2, packet.dst);
580
3.43k
        proto_item_set_generated(ti);
581
3.43k
        proto_item_set_hidden(ti);
582
3.43k
        offset += 2;
583
584
3.43k
        proto_item_append_text(proto_root, ", Dst: %s", dst_addr);
585
3.43k
        col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr);
586
587
        /* Get the short nwk source address and pass it to upper layers */
588
3.43k
        packet.src = tvb_get_letohs(tvb, offset);
589
590
3.43k
        set_address_tvb(&pinfo->net_src, zbee_nwk_address_type, 2, tvb, offset);
591
3.43k
        copy_address_shallow(&pinfo->src, &pinfo->net_src);
592
3.43k
        src_addr = address_to_str(pinfo->pool, &pinfo->src);
593
594
3.43k
        if (nwk_hints)
595
3.43k
            nwk_hints->src = packet.src;
596
3.43k
        proto_tree_add_uint(nwk_tree, hf_zbee_nwk_src, tvb, offset, 2, packet.src);
597
3.43k
        ti = proto_tree_add_uint(nwk_tree, hf_zbee_nwk_addr, tvb, offset, 2, packet.src);
598
3.43k
        proto_item_set_generated(ti);
599
3.43k
        proto_item_set_hidden(ti);
600
3.43k
        offset += 2;
601
602
3.43k
        if (   (packet.src == ZBEE_BCAST_ALL)
603
3.40k
               || (packet.src == ZBEE_BCAST_ACTIVE)
604
3.40k
               || (packet.src == ZBEE_BCAST_ROUTERS)){
605
            /* Source Broadcast doesn't make much sense. */
606
27
            unicast_src = false;
607
27
        }
608
3.40k
        else {
609
3.40k
            unicast_src = true;
610
3.40k
        }
611
612
3.43k
        proto_item_append_text(proto_root, ", Src: %s", src_addr);
613
3.43k
        col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr);
614
615
        /* Get and display the radius. */
616
3.43k
        packet.radius = tvb_get_uint8(tvb, offset);
617
3.43k
        proto_tree_add_uint(nwk_tree, hf_zbee_nwk_radius, tvb, offset, 1, packet.radius);
618
3.43k
        offset += 1;
619
620
        /* Get and display the sequence number. */
621
3.43k
        packet.seqno = tvb_get_uint8(tvb, offset);
622
3.43k
        proto_tree_add_uint(nwk_tree, hf_zbee_nwk_seqno, tvb, offset, 1, packet.seqno);
623
3.43k
        offset += 1;
624
625
        /* Add the extended destination address (ZigBee 2006 and later). */
626
3.43k
        if ((packet.version >= ZBEE_VERSION_2007) && packet.ext_dst) {
627
641
            packet.dst64 = tvb_get_letoh64(tvb, offset);
628
641
            proto_tree_add_item(nwk_tree, hf_zbee_nwk_dst64, tvb, offset, 8, ENC_LITTLE_ENDIAN);
629
641
            ti = proto_tree_add_eui64(nwk_tree, hf_zbee_nwk_addr64, tvb, offset, 8, packet.dst64);
630
641
            proto_item_set_generated(ti);
631
641
            proto_item_set_hidden(ti);
632
641
            offset += 8;
633
641
        }
634
635
        /* Display the extended source address. (ZigBee 2006 and later). */
636
3.43k
        if (packet.version >= ZBEE_VERSION_2007) {
637
2.05k
            addr16.pan = ieee_packet->src_pan;
638
639
2.05k
            if (packet.ext_src) {
640
192
                packet.src64 = tvb_get_letoh64(tvb, offset);
641
192
                proto_tree_add_item(nwk_tree, hf_zbee_nwk_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN);
642
192
                ti = proto_tree_add_eui64(nwk_tree, hf_zbee_nwk_addr64, tvb, offset, 8, packet.src64);
643
192
                proto_item_set_generated(ti);
644
192
                proto_item_set_hidden(ti);
645
192
                offset += 8;
646
647
192
                if (!pinfo->fd->visited && nwk_hints) {
648
                    /* Provide hints to upper layers */
649
192
                    nwk_hints->src_pan = ieee_packet->src_pan;
650
651
                    /* Update nwk extended address hash table */
652
192
                    if ( unicast_src ) {
653
173
                        nwk_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map,
654
173
                                                                    packet.src, addr16.pan, packet.src64, pinfo->current_proto, pinfo->num);
655
173
                    }
656
192
                }
657
192
            }
658
1.86k
            else {
659
                /* See if extended source info was previously sniffed */
660
1.86k
                if (!pinfo->fd->visited && nwk_hints) {
661
1.86k
                    nwk_hints->src_pan = ieee_packet->src_pan;
662
1.86k
                    addr16.addr = packet.src;
663
664
1.86k
                    map_rec = (ieee802154_map_rec *) g_hash_table_lookup(zbee_nwk_map.short_table, &addr16);
665
1.86k
                    if (map_rec) {
666
                        /* found a nwk mapping record */
667
97
                        nwk_hints->map_rec = map_rec;
668
97
                    }
669
1.76k
                    else {
670
                        /* does ieee layer know? */
671
1.76k
                        map_rec = (ieee802154_map_rec *) g_hash_table_lookup(ieee_packet->short_table, &addr16);
672
1.76k
                        if (map_rec) nwk_hints->map_rec = map_rec;
673
1.76k
                    }
674
1.86k
                } /* (!pinfo->fd->visited) */
675
0
                else {
676
0
                    if (nwk_hints && nwk_hints->map_rec ) {
677
                        /* Display inferred source address info */
678
0
                        ti = proto_tree_add_eui64(nwk_tree, hf_zbee_nwk_src64, tvb, offset, 0,
679
0
                                                  nwk_hints->map_rec->addr64);
680
0
                        proto_item_set_generated(ti);
681
0
                        ti = proto_tree_add_eui64(nwk_tree, hf_zbee_nwk_addr64, tvb, offset, 0, nwk_hints->map_rec->addr64);
682
0
                        proto_item_set_generated(ti);
683
0
                        proto_item_set_hidden(ti);
684
685
0
                        if ( nwk_hints->map_rec->start_fnum ) {
686
0
                            ti = proto_tree_add_uint(nwk_tree, hf_zbee_nwk_src64_origin, tvb, 0, 0,
687
0
                                                     nwk_hints->map_rec->start_fnum);
688
0
                        }
689
0
                        else {
690
0
                            ti = proto_tree_add_uint_format_value(nwk_tree, hf_zbee_nwk_src64_origin, tvb, 0, 0, 0, "Pre-configured");
691
0
                        }
692
0
                        proto_item_set_generated(ti);
693
0
                    }
694
0
                }
695
1.86k
            }
696
697
            /* If ieee layer didn't know its extended source address, and nwk layer does, fill it in */
698
2.05k
            if (!pinfo->fd->visited) {
699
2.05k
                if ( (ieee_packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
700
2.05k
                     ieee_hints && !ieee_hints->map_rec ) {
701
2.05k
                    addr16.pan = ieee_packet->src_pan;
702
2.05k
                    addr16.addr = ieee_packet->src16;
703
2.05k
                    map_rec = (ieee802154_map_rec *) g_hash_table_lookup(zbee_nwk_map.short_table, &addr16);
704
705
2.05k
                    if (map_rec) {
706
                        /* found a ieee mapping record */
707
733
                        ieee_hints->map_rec = map_rec;
708
733
                    }
709
2.05k
                }
710
2.05k
            } /* (!pinfo->fd->visited */
711
2.05k
        } /* (pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) */
712
713
        /* Add multicast control field (ZigBee 2006 and later). */
714
3.43k
        if ((packet.version >= ZBEE_VERSION_2007) && packet.multicast) {
715
212
            static int * const multicast_flags[] = {
716
212
                &hf_zbee_nwk_mcast_mode,
717
212
                &hf_zbee_nwk_mcast_radius,
718
212
                &hf_zbee_nwk_mcast_max_radius,
719
212
                NULL
720
212
            };
721
722
212
            uint8_t mcast_control = tvb_get_uint8(tvb, offset);
723
212
            packet.mcast_mode = zbee_get_bit_field(mcast_control, ZBEE_NWK_MCAST_MODE);
724
212
            packet.mcast_radius = zbee_get_bit_field(mcast_control, ZBEE_NWK_MCAST_RADIUS);
725
212
            packet.mcast_max_radius = zbee_get_bit_field(mcast_control, ZBEE_NWK_MCAST_MAX_RADIUS);
726
727
212
            proto_tree_add_bitmask(nwk_tree, tvb, offset, hf_zbee_nwk_mcast, ett_zbee_nwk_mcast, multicast_flags, ENC_NA);
728
212
            offset += 1;
729
212
        }
730
731
        /* Add the Source Route field. (ZigBee 2006 and later). */
732
3.43k
        if ((packet.version >= ZBEE_VERSION_2007) && packet.route) {
733
169
            proto_tree *field_tree;
734
169
            uint8_t     relay_count;
735
169
            uint16_t    relay_addr;
736
169
            unsigned    i;
737
738
            /* Create a subtree for the source route field. */
739
169
            field_tree = proto_tree_add_subtree(nwk_tree, tvb, offset, 1, ett_zbee_nwk_route, &ti, "Source Route");
740
741
            /* Get and display the relay count. */
742
169
            relay_count = tvb_get_uint8(tvb, offset);
743
169
            proto_tree_add_uint(field_tree, hf_zbee_nwk_relay_count, tvb, offset, 1, relay_count);
744
169
            proto_item_append_text(ti, ", Length: %d", relay_count);
745
169
            offset += 1;
746
747
            /* Correct the length of the source route fields. */
748
169
            proto_item_set_len(ti, 1 + relay_count*2);
749
750
            /* Get and display the relay index. */
751
169
            proto_tree_add_item(field_tree, hf_zbee_nwk_relay_index, tvb, offset, 1, ENC_NA);
752
169
            offset += 1;
753
754
            /* Get and display the relay list. */
755
3.24k
            for (i=0; i<relay_count; i++) {
756
3.07k
                relay_addr = tvb_get_letohs(tvb, offset);
757
3.07k
                proto_tree_add_uint_format(field_tree, hf_zbee_nwk_relay, tvb, offset, 2, relay_addr, "Relay %d: 0x%04x", i+1, relay_addr);
758
3.07k
                offset += 2;
759
3.07k
            } /* for */
760
169
        }
761
3.43k
    } /* if not interpan */
762
763
    /*
764
     * Ensure that the payload exists. There are no valid ZigBee network
765
     * packets that have no payload.
766
     */
767
3.82k
    if (offset >= tvb_captured_length(tvb)) {
768
        /* Non-existent or truncated payload. */
769
4
        expert_add_info(pinfo, proto_root, &ei_zbee_nwk_missing_payload);
770
4
        return tvb_captured_length(tvb);
771
4
    }
772
    /* Payload is encrypted, attempt security operations. */
773
3.81k
    else if (packet.security) {
774
22
        payload_tvb = dissect_zbee_secure(tvb, pinfo, nwk_tree, offset);
775
22
        if (payload_tvb == NULL) {
776
            /* If Payload_tvb is NULL, then the security dissector cleaned up. */
777
21
            return tvb_captured_length(tvb);
778
21
        }
779
22
    }
780
    /* Plaintext payload. */
781
3.79k
    else {
782
3.79k
        payload_tvb = tvb_new_subset_remaining(tvb, offset);
783
3.79k
    }
784
785
3.79k
    if (packet.type == ZBEE_NWK_FCF_CMD) {
786
        /* Dissect the Network Command. */
787
100
        dissect_zbee_nwk_cmd(payload_tvb, pinfo, nwk_tree, &packet);
788
100
    }
789
3.69k
    else if (packet.type == ZBEE_NWK_FCF_DATA || packet.type == ZBEE_NWK_FCF_INTERPAN) {
790
        /* Dissect the Network Payload (APS layer). */
791
3.67k
        call_dissector_with_data(aps_handle, payload_tvb, pinfo, tree, &packet);
792
3.67k
    }
793
20
    else {
794
        /* Invalid type. */
795
20
        call_data_dissector(payload_tvb, pinfo, tree);
796
20
    }
797
798
3.79k
    tap_queue_packet(zbee_nwk_tap, pinfo, NULL);
799
800
3.79k
    return tvb_captured_length(tvb);
801
3.82k
} /* dissect_zbee_nwk */
802
803
/**
804
 *ZigBee packet dissection with proto version determination.
805
 *
806
 *@param tvb pointer to buffer containing raw packet.
807
 *@param pinfo pointer to packet information fields.
808
 *@param tree pointer to data tree Wireshark uses to display packet.
809
 *@param data raw packet private data.
810
*/
811
static int
812
dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
813
3.82k
{
814
3.82k
    uint8_t fcf0;
815
3.82k
    uint8_t proto_version;
816
817
3.82k
    fcf0 = tvb_get_uint8(tvb, 0);
818
3.82k
    proto_version = (fcf0 & ZBEE_NWK_FCF_VERSION) >> 2;
819
3.82k
    if (proto_version == ZBEE_VERSION_GREEN_POWER) {
820
0
        call_dissector_with_data(zbee_gp_handle, tvb, pinfo, tree, data);
821
3.82k
    } else {
822
        /* TODO: add check for FCF proto versions. */
823
3.82k
        dissect_zbee_nwk_full(tvb, pinfo, tree, data);
824
3.82k
    }
825
3.82k
    return tvb_captured_length(tvb);
826
3.82k
}
827
828
/**
829
 *ZigBee Network command packet dissection routine for Wireshark.
830
 *
831
 *@param tvb pointer to buffer containing raw packet.
832
 *@param pinfo pointer to packet information fields
833
 *@param tree pointer to data tree Wireshark uses to display packet.
834
*/
835
static void dissect_zbee_nwk_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet* packet)
836
100
{
837
100
    proto_tree  *cmd_tree;
838
100
    proto_item  *cmd_root;
839
840
100
    unsigned    offset=0;
841
100
    uint8_t     cmd_id = tvb_get_uint8(tvb, offset);
842
843
    /* Create a subtree for this command. */
844
100
    cmd_tree = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_zbee_nwk_cmd, &cmd_root, "Command Frame: %s",
845
100
                                    val_to_str_const(cmd_id, zbee_nwk_cmd_names, "Unknown"));
846
847
    /* Add the command ID. */
848
100
    proto_tree_add_uint(cmd_tree, hf_zbee_nwk_cmd_id, tvb, offset, 1, cmd_id);
849
100
    offset += 1;
850
851
    /* Add the command name to the info column. */
852
100
    col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(cmd_id, zbee_nwk_cmd_names, "Unknown Command"));
853
854
855
    /* Handle the command. */
856
100
    switch(cmd_id){
857
25
        case ZBEE_NWK_CMD_ROUTE_REQ:
858
            /* Route Request Command. */
859
25
            offset = dissect_zbee_nwk_route_req(tvb, pinfo, cmd_tree, packet, offset);
860
25
            break;
861
862
8
        case ZBEE_NWK_CMD_ROUTE_REPLY:
863
            /* Route Reply Command. */
864
8
            offset = dissect_zbee_nwk_route_rep(tvb, pinfo, cmd_tree, offset, packet->version);
865
8
            break;
866
867
16
        case ZBEE_NWK_CMD_NWK_STATUS:
868
            /* Network Status Command. */
869
16
            offset = dissect_zbee_nwk_status(tvb, pinfo, cmd_tree, offset);
870
16
            break;
871
872
2
        case ZBEE_NWK_CMD_LEAVE:
873
            /* Leave Command. */
874
2
            offset = dissect_zbee_nwk_leave(tvb, cmd_tree, offset);
875
2
            break;
876
877
8
        case ZBEE_NWK_CMD_ROUTE_RECORD:
878
            /* Route Record Command. */
879
8
            offset = dissect_zbee_nwk_route_rec(tvb, pinfo, cmd_tree, packet, offset);
880
8
            break;
881
882
1
        case ZBEE_NWK_CMD_REJOIN_REQ:
883
            /* Rejoin Request Command. */
884
1
            offset = dissect_zbee_nwk_rejoin_req(tvb, pinfo, cmd_tree, packet, offset);
885
1
            break;
886
887
3
        case ZBEE_NWK_CMD_REJOIN_RESP:
888
            /* Rejoin Response Command. */
889
3
            offset = dissect_zbee_nwk_rejoin_resp(tvb, pinfo, cmd_tree, packet, offset);
890
3
            break;
891
892
4
        case ZBEE_NWK_CMD_LINK_STATUS:
893
            /* Link Status Command. */
894
4
            offset = dissect_zbee_nwk_link_status(tvb, cmd_tree, offset);
895
4
            break;
896
897
6
        case ZBEE_NWK_CMD_NWK_REPORT:
898
            /* Network Report Command. */
899
6
            offset = dissect_zbee_nwk_report(tvb, pinfo, cmd_tree, offset);
900
6
            break;
901
902
3
        case ZBEE_NWK_CMD_NWK_UPDATE:
903
            /* Network Update Command. */
904
3
            offset = dissect_zbee_nwk_update(tvb, pinfo, cmd_tree, offset);
905
3
            break;
906
907
0
        case ZBEE_NWK_CMD_ED_TIMEOUT_REQUEST:
908
            /* Network End Device Timeout Request Command. */
909
0
            offset = dissect_zbee_nwk_ed_timeout_request(tvb, cmd_tree, offset);
910
0
            break;
911
912
0
        case ZBEE_NWK_CMD_ED_TIMEOUT_RESPONSE:
913
            /* Network End Device Timeout Response Command. */
914
0
            offset = dissect_zbee_nwk_ed_timeout_response(tvb, pinfo, cmd_tree, offset);
915
0
            break;
916
917
5
        case ZBEE_NWK_CMD_LINK_PWR_DELTA:
918
5
            offset = dissect_zbee_nwk_link_pwr_delta(tvb, pinfo, cmd_tree, offset);
919
5
            break;
920
921
1
        case ZBEE_NWK_CMD_COMMISSIONING_REQUEST:
922
            /* Network Commissioning Request Command. */
923
1
            offset = dissect_zbee_nwk_commissioning_request(tvb, pinfo, cmd_tree, packet, offset);
924
1
            break;
925
926
3
        case ZBEE_NWK_CMD_COMMISSIONING_RESPONSE:
927
            /* Network Commissioning Response Command. */
928
3
            offset = dissect_zbee_nwk_commissioning_response(tvb, pinfo, cmd_tree, packet, offset);
929
3
            break;
930
931
15
        default:
932
            /* Just break out and let the overflow handler deal with the payload. */
933
15
            break;
934
100
    } /* switch */
935
936
    /* Dissect any TLVs */
937
90
    offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, NULL, ZBEE_TLV_SRC_TYPE_ZBEE_NWK, cmd_id);
938
939
    /* There is excess data in the packet. */
940
90
    if (offset < tvb_captured_length(tvb)) {
941
        /* There are leftover bytes! */
942
3
        tvbuff_t    *leftover_tvb   = tvb_new_subset_remaining(tvb, offset);
943
3
        proto_tree  *root;
944
945
        /* Correct the length of the command tree. */
946
3
        root = proto_tree_get_root(tree);
947
3
        proto_item_set_len(cmd_root, offset);
948
949
        /* Dump the leftover to the data dissector. */
950
3
        call_data_dissector(leftover_tvb, pinfo, root);
951
3
    }
952
90
} /* dissect_zbee_nwk_cmd */
953
954
/**
955
 *Helper dissector for the Route Request command.
956
 *
957
 *@param tvb pointer to buffer containing raw packet.
958
 *@param pinfo pointer to packet information fields
959
 *@param tree pointer to the command subtree.
960
 *@param packet pointer to the network packet struct.
961
 *@param  offset into the tvb to begin dissection.
962
 *@return offset after command dissection.
963
*/
964
static unsigned
965
dissect_zbee_nwk_route_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, unsigned offset)
966
25
{
967
25
    uint8_t route_options;
968
25
    uint16_t dest_addr;
969
970
25
    static int * const nwk_route_command_options_2007[] = {
971
25
        &hf_zbee_nwk_cmd_route_opt_multicast,
972
25
        &hf_zbee_nwk_cmd_route_opt_dest_ext,
973
25
        &hf_zbee_nwk_cmd_route_opt_many_to_one,
974
25
        NULL
975
25
    };
976
977
25
    static int * const nwk_route_command_options[] = {
978
25
        &hf_zbee_nwk_cmd_route_opt_repair,
979
25
        NULL
980
25
    };
981
982
    /* Get and display the route options field. */
983
25
    route_options = tvb_get_uint8(tvb, offset);
984
25
    if (packet->version >= ZBEE_VERSION_2007) {
985
13
        proto_tree_add_bitmask(tree, tvb, offset, hf_zbee_nwk_cmd_route_options, ett_zbee_nwk_cmd_options, nwk_route_command_options_2007, ENC_NA);
986
13
    } else {
987
12
        proto_tree_add_bitmask(tree, tvb, offset, hf_zbee_nwk_cmd_route_options, ett_zbee_nwk_cmd_options, nwk_route_command_options, ENC_NA);
988
12
    }
989
25
    offset += 1;
990
991
    /* Get and display the route request ID. */
992
25
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_route_id, tvb, offset, 1, ENC_NA);
993
25
    offset += 1;
994
995
    /* Get and display the destination address. */
996
25
    dest_addr = tvb_get_letohs(tvb, offset);
997
25
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_route_dest, tvb, offset, 2, dest_addr);
998
25
    offset += 2;
999
1000
    /* Get and display the path cost. */
1001
25
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_route_cost, tvb, offset, 1, ENC_NA);
1002
25
    offset += 1;
1003
1004
    /* Get and display the extended destination address. */
1005
25
    if (route_options & ZBEE_NWK_CMD_ROUTE_OPTION_DEST_EXT) {
1006
3
        proto_tree_add_item(tree, hf_zbee_nwk_cmd_route_dest_ext, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1007
3
        offset += 8;
1008
3
    }
1009
1010
    /* Update the info column. */
1011
25
    if (route_options & ZBEE_NWK_CMD_ROUTE_OPTION_MANY_MASK) {
1012
3
        col_clear(pinfo->cinfo, COL_INFO);
1013
3
        col_append_str(pinfo->cinfo, COL_INFO, "Many-to-One Route Request");
1014
3
    }
1015
25
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: 0x%04x, Src: 0x%04x", dest_addr, packet->src);
1016
1017
    /* Done */
1018
25
    return offset;
1019
25
} /* dissect_zbee_nwk_route_req */
1020
1021
/**
1022
 *Helper dissector for the Route Reply command.
1023
 *
1024
 *@param tvb pointer to buffer containing raw packet.
1025
 *@param pinfo pointer to packet information fields
1026
 *@param tree pointer to the command subtree.
1027
 *@param  offset into the tvb to begin dissection.
1028
 *@return offset after command dissection.
1029
*/
1030
static unsigned
1031
dissect_zbee_nwk_route_rep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, uint8_t version)
1032
8
{
1033
8
    uint8_t route_options;
1034
8
    uint16_t orig_addr;
1035
8
    uint16_t resp_addr;
1036
1037
8
    static int * const nwk_route_command_options_2007[] = {
1038
8
        &hf_zbee_nwk_cmd_route_opt_multicast,
1039
8
        &hf_zbee_nwk_cmd_route_opt_resp_ext,
1040
8
        &hf_zbee_nwk_cmd_route_opt_orig_ext,
1041
8
        NULL
1042
8
    };
1043
1044
8
    static int * const nwk_route_command_options[] = {
1045
8
        &hf_zbee_nwk_cmd_route_opt_repair,
1046
8
        NULL
1047
8
    };
1048
1049
    /* Get and display the route options field. */
1050
8
    route_options = tvb_get_uint8(tvb, offset);
1051
8
    if (version >= ZBEE_VERSION_2007) {
1052
1
        proto_tree_add_bitmask(tree, tvb, offset, hf_zbee_nwk_cmd_route_options, ett_zbee_nwk_cmd_options, nwk_route_command_options_2007, ENC_NA);
1053
7
    } else {
1054
7
        proto_tree_add_bitmask(tree, tvb, offset, hf_zbee_nwk_cmd_route_options, ett_zbee_nwk_cmd_options, nwk_route_command_options, ENC_NA);
1055
7
    }
1056
8
    offset += 1;
1057
1058
    /* Get and display the route request ID. */
1059
8
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_route_id, tvb, offset, 1, ENC_NA);
1060
8
    offset += 1;
1061
1062
    /* Get and display the originator address. */
1063
8
    orig_addr = tvb_get_letohs(tvb, offset);
1064
8
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_route_orig, tvb, offset, 2, orig_addr);
1065
8
    offset += 2;
1066
1067
    /* Get and display the responder address. */
1068
8
    resp_addr = tvb_get_letohs(tvb, offset);
1069
8
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_route_resp, tvb, offset, 2, resp_addr);
1070
8
    offset += 2;
1071
1072
    /* Get and display the path cost. */
1073
8
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_route_cost, tvb, offset, 1, ENC_NA);
1074
8
    offset += 1;
1075
1076
    /* Get and display the originator extended address. */
1077
8
    if (route_options & ZBEE_NWK_CMD_ROUTE_OPTION_ORIG_EXT) {
1078
2
        proto_tree_add_item(tree, hf_zbee_nwk_cmd_route_orig_ext, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1079
2
        offset += 8;
1080
2
    }
1081
1082
    /* Get and display the responder extended address. */
1083
8
    if (route_options & ZBEE_NWK_CMD_ROUTE_OPTION_RESP_EXT) {
1084
1
        proto_tree_add_item(tree, hf_zbee_nwk_cmd_route_resp_ext, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1085
1
        offset += 8;
1086
1
    }
1087
1088
    /* Update the info column. */
1089
8
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Responder: 0x%04x, Originator: 0x%04x", resp_addr, orig_addr);
1090
1091
    /* Done */
1092
8
    return offset;
1093
8
} /* dissect_zbee_nwk_route_rep */
1094
1095
/**
1096
 *Helper dissector for the Network Status command.
1097
 *
1098
 *@param tvb pointer to buffer containing raw packet.
1099
 *@param pinfo pointer to packet information fields
1100
 *@param tree pointer to the command subtree.
1101
 *@param  offset into the tvb to begin dissection.
1102
 *@return offset after command dissection.
1103
*/
1104
static unsigned
1105
dissect_zbee_nwk_status(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset)
1106
16
{
1107
16
    uint8_t status_code;
1108
16
    uint8_t command_id;
1109
16
    uint16_t addr;
1110
1111
    /* Get and display the status code. */
1112
16
    status_code = tvb_get_uint8(tvb, offset);
1113
16
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_nwk_status, tvb, offset, 1, status_code);
1114
16
    offset += 1;
1115
1116
    /* Get and display the destination address. */
1117
16
    addr = tvb_get_letohs(tvb, offset);
1118
16
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_route_dest, tvb, offset, 2, addr);
1119
16
    offset += 2;
1120
1121
    /* Update the info column. */
1122
16
    col_append_fstr(pinfo->cinfo, COL_INFO, ", 0x%04x: %s", addr, val_to_str_const(status_code, zbee_nwk_status_codes, "Unknown Status Code"));
1123
1124
16
    if (status_code == ZBEE_NWK_STATUS_UNKNOWN_COMMAND) {
1125
0
        command_id = tvb_get_uint8(tvb, offset);
1126
0
        proto_tree_add_uint(tree, hf_zbee_nwk_cmd_nwk_status_command_id, tvb, offset, 1, command_id);
1127
0
        col_append_fstr(pinfo->cinfo, COL_INFO, ", Unknown Command ID 0x%02x (%s)", command_id,
1128
0
                val_to_str_const(command_id, zbee_nwk_cmd_names, "Unknown ID"));
1129
0
        offset++;
1130
0
    }
1131
1132
    /* Done */
1133
16
    return offset;
1134
16
} /* dissect_zbee_nwk_status */
1135
1136
/**
1137
 *Helper dissector for the Leave command.
1138
 *
1139
 *@param tvb pointer to buffer containing raw packet.
1140
 *@param tree pointer to the command subtree.
1141
 *@param  offset into the tvb to begin dissection.
1142
 *@return offset after command dissection.
1143
*/
1144
static unsigned
1145
dissect_zbee_nwk_leave(tvbuff_t *tvb, proto_tree *tree, unsigned offset)
1146
2
{
1147
2
    static int * const leave_options[] = {
1148
2
        &hf_zbee_nwk_cmd_leave_rejoin,
1149
2
        &hf_zbee_nwk_cmd_leave_request,
1150
2
        &hf_zbee_nwk_cmd_leave_children,
1151
2
        NULL
1152
2
    };
1153
1154
    /* Get and display the leave options. */
1155
2
    proto_tree_add_bitmask_list(tree, tvb, offset, 1, leave_options, ENC_NA);
1156
2
    offset += 1;
1157
1158
    /* Done */
1159
2
    return offset;
1160
2
} /* dissect_zbee_nwk_leave */
1161
1162
/**
1163
 *Helper dissector for the Route Record command.
1164
 *
1165
 *@param tvb pointer to buffer containing raw packet.
1166
 *@param pinfo pointer to packet information fields
1167
 *@param tree pointer to the command subtree.
1168
 *@param packet pointer to the network packet struct.
1169
 *@param  offset into the tvb to begin dissection.
1170
 *@return offset after command dissection.
1171
*/
1172
static unsigned
1173
dissect_zbee_nwk_route_rec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, unsigned offset)
1174
8
{
1175
8
    uint8_t relay_count;
1176
8
    uint16_t relay_addr;
1177
8
    unsigned   i;
1178
1179
    /* Get and display the relay count. */
1180
8
    relay_count = tvb_get_uint8(tvb, offset);
1181
8
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_relay_count, tvb, offset, 1, relay_count);
1182
8
    offset += 1;
1183
1184
    /* Get and display the relay addresses. */
1185
71
    for (i=0; i<relay_count; i++) {
1186
63
        relay_addr = tvb_get_letohs(tvb, offset);
1187
63
        proto_tree_add_uint_format(tree, hf_zbee_nwk_cmd_relay_device, tvb, offset, 2, relay_addr,
1188
63
                                   "Relay Device %d: 0x%04x", i+1, relay_addr);
1189
63
        offset += 2;
1190
63
    } /* for */
1191
1192
    /* Update the info column. */
1193
8
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: 0x%04x", packet->dst);
1194
1195
1196
    /* Done */
1197
8
    return offset;
1198
8
} /* dissect_zbee_nwk_route_rec */
1199
1200
/**
1201
 *Helper dissector for the Rejoin Request command.
1202
 *
1203
 *@param tvb pointer to buffer containing raw packet.
1204
 *@param pinfo pointer to packet information fields
1205
 *@param tree pointer to the command subtree.
1206
 *@param packet pointer to the network packet struct.
1207
 *@param  offset into the tvb to begin dissection.
1208
 *@return offset after command dissection.
1209
*/
1210
static unsigned
1211
dissect_zbee_nwk_rejoin_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, unsigned offset)
1212
1
{
1213
1
    static int * const capabilities[] = {
1214
1
        &hf_zbee_nwk_cmd_cinfo_alt_coord,
1215
1
        &hf_zbee_nwk_cmd_cinfo_type,
1216
1
        &hf_zbee_nwk_cmd_cinfo_power,
1217
1
        &hf_zbee_nwk_cmd_cinfo_idle_rx,
1218
1
        &hf_zbee_nwk_cmd_cinfo_security,
1219
1
        &hf_zbee_nwk_cmd_cinfo_alloc,
1220
1
        NULL
1221
1
    };
1222
1223
1
    proto_tree_add_bitmask(tree, tvb, offset, hf_zbee_nwk_cmd_cinfo, ett_zbee_nwk_cmd_cinfo, capabilities, ENC_NA);
1224
1
    offset += 1;
1225
1226
    /* Update the info column.*/
1227
1
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Device: 0x%04x", packet->src);
1228
1229
    /* Done */
1230
1
    return offset;
1231
1
} /* dissect_zbee_nwk_rejoin_req */
1232
1233
/**
1234
 *Helper dissector for the Rejoin Response command.
1235
 *
1236
 *@param tvb pointer to buffer containing raw packet.
1237
 *@param pinfo pointer to packet information fields
1238
 *@param tree pointer to the command subtree.
1239
 *@param packet pointer to the network packet struct.
1240
 *@param  offset into the tvb to begin dissection.
1241
 *@return offset after command dissection.
1242
*/
1243
static unsigned
1244
dissect_zbee_nwk_rejoin_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet _U_, unsigned offset)
1245
3
{
1246
3
    uint8_t status;
1247
3
    uint16_t new_address;
1248
1249
    /* Get and display the short address. */
1250
3
    new_address = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN);
1251
3
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_addr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1252
3
    offset += 2;
1253
1254
    /* Get and display the rejoin status. */
1255
3
    status = tvb_get_uint8(tvb, offset);
1256
3
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_rejoin_status, tvb, offset, 1, status);
1257
3
    offset += 1;
1258
1259
    /* Update the info column. */
1260
3
    if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) {
1261
1
        col_append_fstr(pinfo->cinfo, COL_INFO, ", New Address: 0x%04x", new_address);
1262
1
    }
1263
2
    else {
1264
2
        col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(status, zbee_nwk_rejoin_codes, "Unknown Rejoin Response"));
1265
2
    }
1266
1267
    /* Done */
1268
3
    return offset;
1269
3
} /* dissect_zbee_nwk_rejoin_resp */
1270
1271
/**
1272
 *Helper dissector for the Link Status command.
1273
 *
1274
 *@param tvb pointer to buffer containing raw packet.
1275
 *@param tree pointer to the command subtree.
1276
 *@param  offset into the tvb to begin dissection.
1277
 *@return offset after command dissection.
1278
*/
1279
static unsigned
1280
dissect_zbee_nwk_link_status(tvbuff_t *tvb, proto_tree *tree, unsigned offset)
1281
4
{
1282
4
    uint8_t options;
1283
4
    int     i, link_count;
1284
4
    proto_tree *subtree;
1285
4
    static int * const link_options[] = {
1286
4
        &hf_zbee_nwk_cmd_link_last,
1287
4
        &hf_zbee_nwk_cmd_link_first,
1288
4
        &hf_zbee_nwk_cmd_link_count,
1289
4
        NULL
1290
4
    };
1291
1292
    /* Get and Display the link status options. */
1293
4
    options = tvb_get_uint8(tvb, offset);
1294
4
    link_count = options & ZBEE_NWK_CMD_LINK_OPTION_COUNT_MASK;
1295
4
    proto_tree_add_bitmask_list(tree, tvb, offset, 1, link_options, ENC_NA);
1296
4
    offset += 1;
1297
1298
    /* Get and Display the link status list. */
1299
42
    for (i=0; i<link_count; i++) {
1300
        /* Get the address and link status. */
1301
38
        subtree = proto_tree_add_subtree_format(tree, tvb, offset, 3, ett_zbee_nwk_cmd_link, NULL, "Link %d", i+1);
1302
38
        proto_tree_add_item(subtree, hf_zbee_nwk_cmd_link_address, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1303
38
        proto_tree_add_item(subtree, hf_zbee_nwk_cmd_link_incoming_cost, tvb, offset+2, 1, ENC_NA);
1304
38
        proto_tree_add_item(subtree, hf_zbee_nwk_cmd_link_outgoing_cost, tvb, offset+2, 1, ENC_NA);
1305
38
        offset += (2+1);
1306
38
    } /* for */
1307
1308
    /* TODO: Update the info column. */
1309
4
    return offset;
1310
4
} /* dissect_zbee_nwk_link_status */
1311
1312
/**
1313
 *Helper dissector for the End Device Timeout Request command.
1314
 *
1315
 *@param tvb pointer to buffer containing raw packet.
1316
 *@param tree pointer to the command subtree.
1317
 *@param  offset into the tvb to begin dissection.
1318
 *@return offset after command dissection.
1319
*/
1320
static unsigned
1321
dissect_zbee_nwk_ed_timeout_request(tvbuff_t *tvb, proto_tree *tree, unsigned offset)
1322
0
{
1323
    /* See 3.4.11 End Device Timeout Request Command */
1324
1325
    /* 3.4.11.3.1 Requested Timeout Field */
1326
0
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_end_device_timeout_request_enum, tvb, offset, 1, ENC_NA);
1327
0
    offset++;
1328
1329
    /* 3.4.11.3.2 End Device Configuration Field */
1330
0
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_end_device_configuration, tvb, offset, 1, ENC_NA);
1331
0
    offset++;
1332
1333
0
    return offset;
1334
0
} /* dissect_zbee_nwk_ed_timeout_request */
1335
1336
/**
1337
 *Helper dissector for the End Device Timeout Response command.
1338
 *
1339
 *@param tvb pointer to buffer containing raw packet.
1340
 *@param tree pointer to the command subtree.
1341
 *@param  offset into the tvb to begin dissection.
1342
 *@return offset after command dissection.
1343
*/
1344
static unsigned
1345
dissect_zbee_nwk_ed_timeout_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset)
1346
0
{
1347
0
    static int * const end_device_parent_info[] = {
1348
0
        &hf_zbee_nwk_cmd_prnt_info_mac_data_poll_keepalive_supported,
1349
0
        &hf_zbee_nwk_cmd_prnt_info_ed_to_req_keepalive_supported,
1350
0
        &hf_zbee_nwk_cmd_prnt_info_power_negotiation_supported,
1351
0
        NULL
1352
0
    };
1353
0
    unsigned status = tvb_get_uint8(tvb, offset);
1354
    /* 3.4.12 End Device Timeout Response Command */
1355
1356
    /* status */
1357
0
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_end_device_timeout_resp_status, tvb, offset, 1, ENC_NA);
1358
0
    offset++;
1359
1360
    /* Parent Information bitmask */
1361
0
    proto_tree_add_bitmask(tree, tvb, offset, hf_zbee_nwk_cmd_end_device_timeout_resp_parent_info, ett_zbee_nwk_cmd_ed_to_rsp_prnt_info, end_device_parent_info, ENC_NA);
1362
0
    offset++;
1363
1364
0
    proto_item_append_text(tree, ", %s", val_to_str_const(status, zbee_nwk_end_device_timeout_resp_status, "Unknown Status"));
1365
0
    col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(status, zbee_nwk_end_device_timeout_resp_status, "Unknown Status"));
1366
1367
0
    return offset;
1368
0
} /* dissect_zbee_nwk_ed_timeout_response */
1369
1370
/**
1371
 *Helper dissector for the Link Power Delta command.
1372
 *
1373
 *@param tvb pointer to buffer containing raw packet.
1374
 *@param tree pointer to the command subtree.
1375
 *@param  offset into the tvb to begin dissection.
1376
 *@return offset after command dissection.
1377
*/
1378
static unsigned
1379
dissect_zbee_nwk_link_pwr_delta(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, unsigned offset)
1380
5
{
1381
5
    uint8_t i, count;
1382
5
    int     delta;
1383
5
    uint8_t type;
1384
5
    uint16_t addr;
1385
5
    proto_tree *subtree;
1386
1387
5
    proto_tree_add_item_ret_uint8(tree, hf_zbee_nwk_cmd_link_pwr_type, tvb, offset, 1, ENC_NA, &type);
1388
5
    offset++;
1389
1390
5
    proto_tree_add_item_ret_uint8(tree, hf_zbee_nwk_cmd_link_pwr_list_count, tvb, offset, 1, ENC_NA, &count);
1391
5
    offset++;
1392
1393
5
    proto_item_append_text(tree, ": %s, Count %u", val_to_str_const(type, zbee_nwk_link_power_delta_types, "Unknown"), count);
1394
1395
356
    for (i=0; i<count; i++) {
1396
351
        subtree = proto_tree_add_subtree(tree, tvb, count, 3, ett_zbee_nwk_cmd_link_pwr_struct, NULL, "Power Delta Structure");
1397
351
        proto_tree_add_item_ret_uint16(subtree, hf_zbee_nwk_cmd_link_pwr_device_address, tvb, offset, 2, ENC_LITTLE_ENDIAN, &addr);
1398
351
        offset += 2;
1399
351
        delta = (char)tvb_get_uint8(tvb, offset);
1400
351
        proto_tree_add_item(subtree, hf_zbee_nwk_cmd_link_pwr_power_delta, tvb, offset, 1, ENC_NA);
1401
351
        offset++;
1402
351
        proto_item_append_text(subtree, ": Device Address 0x%04X, Power Delta %d dBm", addr, delta);
1403
351
    }
1404
5
    return offset;
1405
5
}
1406
1407
/**
1408
 *Helper dissector for the Network Commissioning Request command.
1409
 *
1410
 *@param tvb pointer to buffer containing raw packet.
1411
 *@param tree pointer to the command subtree.
1412
 *@param  offset into the tvb to begin dissection.
1413
 *@return offset after command dissection.
1414
 */
1415
static unsigned
1416
dissect_zbee_nwk_commissioning_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, unsigned offset)
1417
1
{
1418
    /* See 3.4.14 Network Commissioning Request Command */
1419
1420
1
    static int * const capabilities[] = {
1421
1
        &hf_zbee_nwk_cmd_cinfo_alt_coord,
1422
1
        &hf_zbee_nwk_cmd_cinfo_type,
1423
1
        &hf_zbee_nwk_cmd_cinfo_power,
1424
1
        &hf_zbee_nwk_cmd_cinfo_idle_rx,
1425
1
        &hf_zbee_nwk_cmd_cinfo_security,
1426
1
        &hf_zbee_nwk_cmd_cinfo_alloc,
1427
1
        NULL
1428
1
    };
1429
1430
    /* 3.4.14.3 Association Type */
1431
1
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_association_type, tvb, offset, 1, ENC_NA);
1432
1
    offset += 1;
1433
1434
1
    proto_tree_add_bitmask(tree, tvb, offset, hf_zbee_nwk_cmd_cinfo, ett_zbee_nwk_cmd_cinfo, capabilities, ENC_NA);
1435
1
    offset += 1;
1436
1437
    /* Update the info column.*/
1438
1
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Device: 0x%04x", packet->src);
1439
1440
1
    return offset;
1441
1
} /* dissect_zbee_nwk_commissioning_request */
1442
1443
/**
1444
 *Helper dissector for the Commissioning Response command.
1445
 *
1446
 *@param tvb pointer to buffer containing raw packet.
1447
 *@param tree pointer to the command subtree.
1448
 *@param  offset into the tvb to begin dissection.
1449
 *@return offset after command dissection.
1450
*/
1451
static unsigned
1452
dissect_zbee_nwk_commissioning_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet _U_, unsigned offset)
1453
3
{
1454
3
    uint8_t status;
1455
3
    uint16_t new_address;
1456
1457
    /* Get and display the short address. */
1458
3
    new_address = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN);
1459
3
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_addr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1460
3
    offset += 2;
1461
1462
    /* Get and display the rejoin status. */
1463
3
    status = tvb_get_uint8(tvb, offset);
1464
3
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_rejoin_status, tvb, offset, 1, status);
1465
3
    offset += 1;
1466
1467
    /* Update the info column. */
1468
3
    if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) {
1469
0
        col_append_fstr(pinfo->cinfo, COL_INFO, ", New Address: 0x%04x", new_address);
1470
0
    }
1471
3
    else {
1472
3
        col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(status, zbee_nwk_rejoin_codes, "Unknown Commissioning Response"));
1473
3
    }
1474
1475
3
    return offset;
1476
3
} /* dissect_zbee_nwk_commissioning_response */
1477
1478
/**
1479
 *Helper dissector for the Network Report command.
1480
 *
1481
 *@param tvb pointer to buffer containing raw packet.
1482
 *@param pinfo pointer to packet information fields
1483
 *@param tree pointer to the command subtree.
1484
 *@param  offset into the tvb to begin dissection.
1485
 *@return offset after command dissection.
1486
*/
1487
static unsigned
1488
dissect_zbee_nwk_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset)
1489
6
{
1490
6
    uint8_t options;
1491
6
    uint8_t report_type;
1492
6
    int     report_count;
1493
6
    int     i;
1494
1495
    /* Get and display the command options field. */
1496
6
    options = tvb_get_uint8(tvb, offset);
1497
6
    report_count = options & ZBEE_NWK_CMD_NWK_REPORT_COUNT_MASK;
1498
6
    report_type = options & ZBEE_NWK_CMD_NWK_REPORT_ID_MASK;
1499
6
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_report_type, tvb, offset, 1, report_type);
1500
6
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_report_count, tvb, offset, 1, report_count);
1501
6
    offset += 1;
1502
6
    report_type >>= ws_ctz(ZBEE_NWK_CMD_NWK_REPORT_ID_MASK);
1503
1504
    /* Get and display the epid. */
1505
6
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_epid, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1506
6
    offset += 8;
1507
1508
6
    if (report_type == ZBEE_NWK_CMD_NWK_REPORT_ID_PAN_CONFLICT) {
1509
1510
        /* Report information contains a list of PANS with range of the sender. */
1511
20
        for (i=0; i<report_count; i++) {
1512
18
            proto_tree_add_item(tree, hf_zbee_nwk_panid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1513
18
            offset += 2;
1514
18
        } /* for */
1515
2
    }
1516
6
    if (report_type == ZBEE_NWK_CMD_NWK_REPORT_ID_ZBOSS_KEY_TRACE) {
1517
1
        uint8_t             key[ZBEE_APS_CMD_KEY_LENGTH];
1518
1519
17
        for (i=0; i<ZBEE_APS_CMD_KEY_LENGTH ; i++) {
1520
16
            key[i] = tvb_get_uint8(tvb, offset+i);
1521
16
        } /* for */
1522
1
        proto_tree_add_item(tree, hf_zbee_zboss_nwk_cmd_key, tvb, offset, ZBEE_APS_CMD_KEY_LENGTH, ENC_NA);
1523
1
        offset += ZBEE_APS_CMD_KEY_LENGTH;
1524
1
        zbee_sec_add_key_to_keyring(pinfo, key);
1525
1
    }
1526
1527
    /* Update the info column. */
1528
6
    col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(report_type, zbee_nwk_report_types, "Unknown Report Type"));
1529
1530
    /* Done */
1531
6
    return offset;
1532
6
} /* dissect_zbee_nwk_report */
1533
1534
/**
1535
 *Helper dissector for the Network Update command.
1536
 *
1537
 *@param tvb pointer to buffer containing raw packet.
1538
 *@param pinfo pointer to packet information fields
1539
 *@param tree pointer to the command subtree.
1540
 *@param  offset into the tvb to begin dissection.
1541
 *@return offset after command dissection.
1542
*/
1543
static unsigned
1544
dissect_zbee_nwk_update(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset)
1545
3
{
1546
3
    uint8_t options;
1547
3
    uint8_t update_type;
1548
3
    uint8_t update_id;
1549
3
    int     update_count;
1550
3
    int     i;
1551
1552
    /* Get and display the command options field. */
1553
3
    options = tvb_get_uint8(tvb, offset);
1554
3
    update_count = options & ZBEE_NWK_CMD_NWK_UPDATE_COUNT_MASK;
1555
3
    update_type = options & ZBEE_NWK_CMD_NWK_UPDATE_ID_MASK;
1556
3
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_update_type, tvb, offset, 1, update_type);
1557
3
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_update_count, tvb, offset, 1, update_count);
1558
3
    offset += 1;
1559
1560
    /* Get and display the epid. */
1561
3
    proto_tree_add_item(tree, hf_zbee_nwk_cmd_epid, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1562
3
    offset += 8;
1563
1564
    /* Get and display the updateID. */
1565
3
    update_id = tvb_get_uint8(tvb, offset);
1566
3
    proto_tree_add_uint(tree, hf_zbee_nwk_cmd_update_id, tvb, offset, 1, update_id);
1567
3
    offset += 1;
1568
1569
3
    if (update_type == ZBEE_NWK_CMD_NWK_UPDATE_ID_PAN_UPDATE) {
1570
1571
        /* Report information contains a list of PANS with range of the sender. */
1572
11
        for (i=0; i<update_count; i++) {
1573
8
            proto_tree_add_item(tree, hf_zbee_nwk_panid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1574
8
            offset += 2;
1575
8
        } /* for */
1576
3
    }
1577
1578
    /* Update the info column. */
1579
3
    col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(update_type, zbee_nwk_update_types, "Unknown Update Type"));
1580
1581
    /* Done */
1582
3
    return offset;
1583
3
} /* dissect_zbee_nwk_update */
1584
1585
1586
/**
1587
 *Heuristic interpreter for the ZigBee PRO beacon dissectors.
1588
 *
1589
 *@param tvb pointer to buffer containing raw packet.
1590
 *@param pinfo pointer to packet information fields
1591
 *@param tree pointer to data tree Wireshark uses to display packet.
1592
 *@return Boolean value, whether it handles the packet or not.
1593
*/
1594
static bool
1595
dissect_zbee_beacon_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1596
167
{
1597
167
    ieee802154_packet   *packet = (ieee802154_packet *)data;
1598
1599
    /* All ZigBee frames must always have a 16-bit source address. */
1600
167
    if (!packet) return false;
1601
167
    if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) return false;
1602
17
    if (tvb_captured_length(tvb) == 0) return false;
1603
1604
    /* ZigBee beacons begin with a protocol identifier. */
1605
17
    if (tvb_get_uint8(tvb, 0) != ZBEE_NWK_BEACON_PROTOCOL_ID) return false;
1606
10
    dissect_zbee_beacon(tvb, pinfo, tree, packet);
1607
10
    return true;
1608
17
} /* dissect_zbee_beacon_heur */
1609
1610
/**
1611
 *Dissector for Legacy ZigBee Beacon Payloads (prior to the Enhanced Beacon)
1612
 *
1613
 *@param tvb pointer to buffer containing raw packet.
1614
 *@param pinfo pointer to packet information fields
1615
 *@param tree pointer to data tree Wireshark uses to display packet.
1616
*/
1617
static int dissect_zbee_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1618
10
{
1619
1620
10
    proto_item  *beacon_root;
1621
10
    proto_tree  *beacon_tree;
1622
10
    unsigned     offset = 0;
1623
10
    uint8_t      version;
1624
10
    uint32_t     profile;
1625
1626
10
    static int * const beacon_fields[] = {
1627
10
        &hf_zbee_beacon_stack_profile,
1628
10
        &hf_zbee_beacon_version,
1629
10
        &hf_zbee_beacon_router_capacity,
1630
10
        &hf_zbee_beacon_depth,
1631
10
        &hf_zbee_beacon_end_device_capacity,
1632
10
        NULL
1633
10
    };
1634
1635
    /* Add ourself to the protocol column. */
1636
10
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZigBee");
1637
    /* Create the tree for this beacon. */
1638
10
    beacon_root = proto_tree_add_item(tree, proto_zbee_beacon, tvb, 0, -1, ENC_NA);
1639
10
    beacon_tree = proto_item_add_subtree(beacon_root, ett_zbee_nwk_beacon);
1640
1641
    /* Get and display the protocol id, must be 0 on all ZigBee beacons. */
1642
10
    proto_tree_add_item(beacon_tree, hf_zbee_beacon_protocol, tvb, offset, 1, ENC_NA);
1643
10
    offset += 1;
1644
1645
10
    proto_tree_add_bitmask_text(beacon_tree, tvb, offset, 2, "Beacon: ", NULL , ett_zbee_nwk_beacon_bitfield, beacon_fields,
1646
10
            ENC_LITTLE_ENDIAN, BMT_NO_INT|BMT_NO_TFS);
1647
1648
    /* Get and display the stack profile and protocol version. */
1649
10
    version = (uint8_t)((tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN) & ZBEE_NWK_BEACON_PROTOCOL_VERSION) >> 4);
1650
10
    profile = (uint32_t)(tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN) & ZBEE_NWK_BEACON_STACK_PROFILE);
1651
10
    proto_item_append_text(beacon_root, ", %s", val_to_str_const(profile, zbee_nwk_stack_profiles, "Unknown Profile"));
1652
10
    offset += 2;
1653
1654
10
    if (version >= ZBEE_VERSION_2007) {
1655
        /* In ZigBee 2006 and later, the beacon contains an extended PAN ID. */
1656
5
        proto_tree_add_item(beacon_tree, hf_zbee_beacon_epid, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1657
5
        col_append_fstr(pinfo->cinfo, COL_INFO, ", EPID: %s", eui64_to_display(pinfo->pool,
1658
5
            tvb_get_uint64(tvb, offset, ENC_LITTLE_ENDIAN)));
1659
5
        proto_item_append_text(beacon_root, ", EPID: %s", eui64_to_display(pinfo->pool,
1660
5
                tvb_get_uint64(tvb, offset, ENC_LITTLE_ENDIAN)));
1661
5
        offset += 8;
1662
1663
        /*
1664
         * In ZigBee 2006 the Tx-Offset is optional, while in the 2007 and
1665
         * later versions, the Tx-Offset is a required value. Since both 2006 and
1666
         * and 2007 versions have the same protocol version (2), we should treat
1667
         * the Tx-Offset as well as the update ID as optional elements
1668
         */
1669
5
        if (tvb_bytes_exist(tvb, offset, 3)) {
1670
3
            proto_tree_add_item(beacon_tree, hf_zbee_beacon_tx_offset, tvb, offset, 3, ENC_LITTLE_ENDIAN);
1671
3
            offset += 3;
1672
1673
            /* Get and display the update ID. */
1674
3
            if(tvb_captured_length_remaining(tvb, offset)) {
1675
2
                proto_tree_add_item(beacon_tree, hf_zbee_beacon_update_id, tvb, offset, 1, ENC_NA);
1676
2
                offset += 1;
1677
2
            }
1678
3
        }
1679
5
    }
1680
5
    else if (tvb_bytes_exist(tvb, offset, 3)) {
1681
        /* In ZigBee 2004, the Tx-Offset is an optional value. */
1682
3
        proto_tree_add_item(beacon_tree, hf_zbee_beacon_tx_offset, tvb, offset, 3, ENC_LITTLE_ENDIAN);
1683
3
        offset += 3;
1684
1685
3
    }
1686
1687
10
    offset = dissect_zbee_tlvs(tvb, pinfo, beacon_tree, offset, data, ZBEE_TLV_SRC_TYPE_DEFAULT, 0);
1688
1689
10
    return offset;
1690
10
} /* dissect_zbee_beacon */
1691
1692
/**
1693
 *Heuristic interpreter for the ZigBee IP beacon dissectors.
1694
 *
1695
 *@param tvb pointer to buffer containing raw packet.
1696
 *@param pinfo pointer to packet information fields
1697
 *@param tree pointer to data tree Wireshark uses to display packet.
1698
 *@return Boolean value, whether it handles the packet or not.
1699
*/
1700
static bool
1701
dissect_zbip_beacon_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1702
167
{
1703
167
    ieee802154_packet   *packet = (ieee802154_packet *)data;
1704
1705
    /* All ZigBee frames must always have a 16-bit source address. */
1706
167
    if (!packet) return false;
1707
167
    if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) return false;
1708
16
    if (tvb_captured_length(tvb) == 0) return false;
1709
1710
    /* ZigBee beacons begin with a protocol identifier. */
1711
16
    if (tvb_get_uint8(tvb, 0) != ZBEE_IP_BEACON_PROTOCOL_ID) return false;
1712
2
    dissect_zbip_beacon(tvb, pinfo, tree, packet);
1713
2
    return true;
1714
16
} /* dissect_zbip_beacon_heur */
1715
1716
/**
1717
 *Dissector for ZigBee IP beacons.
1718
 *
1719
 *@param tvb pointer to buffer containing raw packet.
1720
 *@param pinfo pointer to packet information fields
1721
 *@param tree pointer to data tree Wireshark uses to display packet.
1722
*/
1723
static int dissect_zbip_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1724
2
{
1725
2
    ieee802154_packet   *packet = (ieee802154_packet *)data;
1726
1727
2
    proto_item  *beacon_root;
1728
2
    proto_tree  *beacon_tree;
1729
2
    unsigned    offset = 0;
1730
2
    uint8_t     proto_id;
1731
2
    char        *ssid;
1732
1733
    /* Reject the packet if data is NULL */
1734
2
    if (!packet) return 0;
1735
1736
    /* Add ourself to the protocol column. */
1737
2
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZigBee IP");
1738
    /* Create the tree for this beacon. */
1739
2
    beacon_root = proto_tree_add_item(tree, proto_zbip_beacon, tvb, 0, -1, ENC_NA);
1740
2
    beacon_tree = proto_item_add_subtree(beacon_root, ett_zbee_nwk_beacon);
1741
1742
    /* Update the info column. */
1743
2
    col_clear(pinfo->cinfo, COL_INFO);
1744
2
    col_append_fstr(pinfo->cinfo, COL_INFO, "Beacon, Src: 0x%04x", packet->src16);
1745
1746
    /* Get and display the protocol id, must be 0x02 on all ZigBee beacons. */
1747
2
    proto_id = tvb_get_uint8(tvb, offset);
1748
2
    proto_tree_add_uint(beacon_tree, hf_zbee_beacon_protocol, tvb, offset, 1, proto_id);
1749
2
    offset += 1;
1750
1751
    /* Get and display the beacon flags */
1752
2
    proto_tree_add_item(beacon_tree, hf_zbip_beacon_allow_join, tvb, offset, 1, ENC_BIG_ENDIAN);
1753
2
    proto_tree_add_item(beacon_tree, hf_zbip_beacon_router_capacity, tvb, offset, 1, ENC_BIG_ENDIAN);
1754
2
    proto_tree_add_item(beacon_tree, hf_zbip_beacon_host_capacity, tvb, offset, 1, ENC_BIG_ENDIAN);
1755
2
    proto_tree_add_item(beacon_tree, hf_zbip_beacon_unsecure, tvb, offset, 1, ENC_BIG_ENDIAN);
1756
2
    offset += 1;
1757
1758
    /* Get and display the network ID. */
1759
2
    proto_tree_add_item(beacon_tree, hf_zbip_beacon_network_id, tvb, offset, 16, ENC_ASCII);
1760
1761
2
    ssid = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, 16, ENC_ASCII|ENC_NA);
1762
2
    col_append_fstr(pinfo->cinfo, COL_INFO, ", SSID: %s", ssid);
1763
2
    offset += 16;
1764
1765
2
    offset = dissect_zbee_tlvs(tvb, pinfo, beacon_tree, offset, data, ZBEE_TLV_SRC_TYPE_DEFAULT, 0);
1766
1767
    /* Check for leftover bytes. */
1768
2
    if (offset < tvb_captured_length(tvb)) {
1769
        /* Bytes leftover! */
1770
1
        tvbuff_t    *leftover_tvb   = tvb_new_subset_remaining(tvb, offset);
1771
1
        proto_tree  *root;
1772
1773
        /* Correct the length of the beacon tree. */
1774
1
        root = proto_tree_get_root(tree);
1775
1
        proto_item_set_len(beacon_root, offset);
1776
1777
        /* Dump the leftover to the data dissector. */
1778
1
        call_data_dissector(leftover_tvb, pinfo, root);
1779
1
    }
1780
2
    return tvb_captured_length(tvb);
1781
2
} /* dissect_zbip_beacon */
1782
1783
/**
1784
 *Subdissector command for ZigBee Specific IEs (Information Elements)
1785
 *
1786
 *@param tvb pointer to buffer containing raw packet.
1787
 *@param pinfo pointer to packet information fields (unused).
1788
 *@param tree pointer to command subtree.
1789
 *@param data pointer to the length of the payload IE.
1790
*/
1791
static int
1792
dissect_zbee_ie(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1793
0
{
1794
0
    proto_tree *subtree;
1795
0
    tvbuff_t   *ie_tvb;
1796
0
    uint16_t    zigbee_ie;
1797
0
    uint16_t    id;
1798
0
    uint16_t    length;
1799
0
    unsigned    pie_length;
1800
0
    unsigned    offset = 0;
1801
1802
0
    static int * const fields[] = {
1803
0
        &hf_ieee802154_zigbee_ie_id,
1804
0
        &hf_ieee802154_zigbee_ie_length,
1805
0
        NULL
1806
0
    };
1807
1808
0
    pie_length = *(int *)data;
1809
1810
0
    do {
1811
0
        zigbee_ie =  tvb_get_letohs(tvb, offset);
1812
0
        id        = (zigbee_ie & ZBEE_ZIGBEE_IE_ID_MASK) >> 6;
1813
0
        length    =  zigbee_ie & ZBEE_ZIGBEE_IE_LENGTH_MASK;
1814
1815
        /* Create a subtree for this command frame. */
1816
0
        subtree = proto_tree_add_subtree(tree, tvb, offset, 2+length, ett_zbee_nwk_header, NULL, "ZigBee IE");
1817
0
        proto_item_append_text(subtree, ", %s, Length: %d", val_to_str_const(id, ieee802154_zigbee_ie_names, "Unknown"), length);
1818
1819
0
        proto_tree_add_bitmask(subtree, tvb, offset, hf_ieee802154_zigbee_ie,
1820
0
                               ett_zbee_nwk_zigbee_ie_fields, fields, ENC_LITTLE_ENDIAN);
1821
0
        offset += 2;
1822
1823
0
        switch (id) {
1824
0
            case ZBEE_ZIGBEE_IE_REJOIN:
1825
0
                dissect_ieee802154_zigbee_rejoin(tvb, pinfo, subtree, &offset);
1826
0
                break;
1827
1828
0
            case ZBEE_ZIGBEE_IE_TX_POWER:
1829
0
                dissect_ieee802154_zigbee_txpower(tvb, pinfo, subtree, &offset);
1830
0
                break;
1831
1832
0
            case ZBEE_ZIGBEE_IE_BEACON_PAYLOAD:
1833
0
                ie_tvb = tvb_new_subset_length(tvb, offset, ZBEE_NWK_BEACON_LENGTH);
1834
0
                offset += dissect_zbee_beacon(ie_tvb, pinfo, subtree, NULL); /* Legacy ZigBee Beacon */
1835
0
                dissect_ieee802154_superframe(tvb, pinfo, subtree, &offset);
1836
0
                proto_tree_add_item(subtree, hf_ieee802154_zigbee_ie_source_addr, tvb, offset, 2, ENC_BIG_ENDIAN);
1837
0
                offset += 2;
1838
0
                break;
1839
1840
0
            default:
1841
0
                if (length > 0) { /* just use the data dissector */
1842
0
                    call_data_dissector(tvb, pinfo, tree);
1843
0
                    offset += length;
1844
0
                }
1845
0
                break;
1846
0
        }
1847
0
    } while (offset < pie_length);
1848
1849
0
    return tvb_captured_length(tvb);
1850
0
}
1851
1852
/**
1853
 *Subdissector for the ZigBee specific TX Power IE (information element)
1854
 *
1855
 *@param tvb pointer to buffer containing raw packet.
1856
 *@param pinfo pointer to packet information fields (unused).
1857
 *@param tree pointer to command subtree.
1858
 *@param offset offset into the tvbuff to begin dissection.
1859
*/
1860
static void
1861
dissect_ieee802154_zigbee_txpower(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, unsigned *offset)
1862
0
{
1863
0
    int32_t txpower;
1864
1865
0
    txpower = (char)tvb_get_uint8(tvb, *offset); /* tx power is a signed byte */
1866
1867
0
    proto_tree_add_item_ret_int(tree, hf_ieee802154_zigbee_ie_tx_power, tvb, *offset, 1, ENC_NA, &txpower);
1868
0
    proto_item_append_text(tree, ", TX Power %d dBm", txpower);
1869
1870
0
    *offset += 1;
1871
0
}
1872
1873
/**
1874
 *Subdissector for the ZigBee specific Rejoin IE (information element)
1875
 *
1876
 *@param tvb pointer to buffer containing raw packet.
1877
 *@param pinfo pointer to packet information fields (unused).
1878
 *@param tree pointer to command subtree.
1879
 *@param offset offset into the tvbuff to begin dissection.
1880
*/
1881
static void
1882
dissect_ieee802154_zigbee_rejoin(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, unsigned *offset)
1883
0
{
1884
0
    proto_tree *subtree;
1885
1886
0
    subtree = proto_tree_add_subtree(tree, tvb, *offset, 10, ett_zbee_nwk_ie_rejoin, NULL, "ZigBee Rejoin");
1887
1888
0
    proto_tree_add_item(subtree, hf_ieee802154_zigbee_rejoin_epid, tvb, *offset, 8, ENC_LITTLE_ENDIAN);
1889
0
    proto_item_append_text(tree, ", EPID %s", eui64_to_display(pinfo->pool,
1890
0
            tvb_get_uint64(tvb, *offset, ENC_LITTLE_ENDIAN)));
1891
0
    *offset += 8;
1892
1893
0
    proto_tree_add_item(subtree, hf_ieee802154_zigbee_rejoin_source_addr, tvb, *offset, 2, ENC_LITTLE_ENDIAN);
1894
0
    proto_item_append_text(tree, ", Src: 0x%04x",
1895
0
            tvb_get_uint16(tvb, *offset, ENC_LITTLE_ENDIAN));
1896
0
    *offset += 2;
1897
1898
0
} /* dissect_ieee802154_zigbee_rejoin */
1899
1900
static const char* zbee_nwk_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter)
1901
0
{
1902
0
    if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == zbee_nwk_address_type))
1903
0
        return "zbee_nwk.src";
1904
1905
0
    if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == zbee_nwk_address_type))
1906
0
        return "zbee_nwk.dst";
1907
1908
0
    if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == zbee_nwk_address_type))
1909
0
        return "zbee_nwk.addr";
1910
1911
0
    return CONV_FILTER_INVALID;
1912
0
}
1913
1914
static ct_dissector_info_t zbee_nwk_ct_dissector_info = {&zbee_nwk_conv_get_filter_type };
1915
1916
static tap_packet_status zbee_nwk_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip _U_, tap_flags_t flags)
1917
0
{
1918
0
    conv_hash_t *hash = (conv_hash_t*)pct;
1919
0
    hash->flags = flags;
1920
1921
0
    add_conversation_table_data(hash, &pinfo->net_src, &pinfo->net_dst, 0, 0, 1,
1922
0
            pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts,
1923
0
            &zbee_nwk_ct_dissector_info, CONVERSATION_NONE);
1924
1925
0
    return TAP_PACKET_REDRAW;
1926
0
}
1927
1928
static const char* zbee_nwk_endpoint_get_filter_type(endpoint_item_t* endpoint, conv_filter_type_e filter)
1929
0
{
1930
0
  if ((filter == CONV_FT_ANY_ADDRESS) && (endpoint->myaddress.type == zbee_nwk_address_type))
1931
0
  {
1932
0
      return "zbee_nwk.addr";
1933
0
  }
1934
0
  else
1935
0
  {
1936
0
      return CONV_FILTER_INVALID;
1937
0
  }
1938
0
}
1939
1940
static et_dissector_info_t zbee_nwk_endpoint_dissector_info = {&zbee_nwk_endpoint_get_filter_type };
1941
1942
static tap_packet_status zbee_nwk_endpoint_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip _U_, tap_flags_t flags)
1943
0
{
1944
0
    conv_hash_t *hash = (conv_hash_t*)pit;
1945
0
    hash->flags = flags;
1946
1947
    /* Take two "add" passes per packet, adding for each direction, ensures that all
1948
     packets are counted properly (even if address is sending to itself)
1949
     XXX - this could probably be done more efficiently inside endpoint_table */
1950
0
    add_endpoint_table_data(hash, &pinfo->net_src, 0, true, 1,
1951
0
            pinfo->fd->pkt_len, &zbee_nwk_endpoint_dissector_info, ENDPOINT_NONE);
1952
0
    add_endpoint_table_data(hash, &pinfo->net_dst, 0, false, 1,
1953
0
            pinfo->fd->pkt_len, &zbee_nwk_endpoint_dissector_info, ENDPOINT_NONE);
1954
1955
0
    return TAP_PACKET_REDRAW;
1956
0
}
1957
1958
static bool zbee_nwk_filter_valid(packet_info *pinfo, void *user_data _U_)
1959
0
{
1960
0
    return proto_is_frame_protocol(pinfo->layers, "zbee_nwk");
1961
0
}
1962
1963
static char* zbee_nwk_build_filter(packet_info *pinfo, void *user_data _U_)
1964
0
{
1965
0
    return ws_strdup_printf("zbee_nwk.addr eq %s and zbee_nwk.addr eq %s",
1966
0
            address_to_str(pinfo->pool, &pinfo->net_src),
1967
0
            address_to_str(pinfo->pool, &pinfo->net_dst));
1968
0
}
1969
1970
/**
1971
 *ZigBee protocol registration routine.
1972
 *
1973
*/
1974
void proto_register_zbee_nwk(void)
1975
16
{
1976
16
    static hf_register_info hf[] = {
1977
1978
16
            { &hf_zbee_nwk_fcf,
1979
16
            { "Frame Control Field",             "zbee_nwk.fcf", FT_UINT16, BASE_HEX, NULL,
1980
16
                0x0, NULL, HFILL }},
1981
1982
16
            { &hf_zbee_nwk_frame_type,
1983
16
            { "Frame Type",             "zbee_nwk.frame_type", FT_UINT16, BASE_HEX, VALS(zbee_nwk_frame_types),
1984
16
                ZBEE_NWK_FCF_FRAME_TYPE, NULL, HFILL }},
1985
1986
16
            { &hf_zbee_nwk_proto_version,
1987
16
            { "Protocol Version",       "zbee_nwk.proto_version", FT_UINT16, BASE_DEC, NULL, ZBEE_NWK_FCF_VERSION,
1988
16
                NULL, HFILL }},
1989
1990
16
            { &hf_zbee_nwk_discover_route,
1991
16
            { "Discover Route",         "zbee_nwk.discovery", FT_UINT16, BASE_HEX, VALS(zbee_nwk_discovery_modes),
1992
16
                ZBEE_NWK_FCF_DISCOVER_ROUTE,
1993
16
                "Determines how route discovery may be handled, if at all.", HFILL }},
1994
1995
16
            { &hf_zbee_nwk_multicast,
1996
16
            { "Multicast",              "zbee_nwk.multicast", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_MULTICAST,
1997
16
                NULL, HFILL }},
1998
1999
16
            { &hf_zbee_nwk_security,
2000
16
            { "Security",               "zbee_nwk.security", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_SECURITY,
2001
16
                "Whether or not security operations are performed on the network payload.", HFILL }},
2002
2003
16
            { &hf_zbee_nwk_source_route,
2004
16
            { "Source Route",           "zbee_nwk.src_route", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_SOURCE_ROUTE,
2005
16
                NULL, HFILL }},
2006
2007
16
            { &hf_zbee_nwk_ext_dst,
2008
16
            { "Destination",            "zbee_nwk.ext_dst", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_EXT_DEST,
2009
16
                NULL, HFILL }},
2010
2011
16
            { &hf_zbee_nwk_ext_src,
2012
16
            { "Extended Source",        "zbee_nwk.ext_src", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_EXT_SOURCE,
2013
16
                NULL, HFILL }},
2014
2015
16
            { &hf_zbee_nwk_end_device_initiator,
2016
16
            { "End Device Initiator",   "zbee_nwk.end_device_initiator", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_END_DEVICE_INITIATOR,
2017
16
                NULL, HFILL }},
2018
2019
16
            { &hf_zbee_nwk_dst,
2020
16
            { "Destination",            "zbee_nwk.dst", FT_UINT16, BASE_HEX, NULL, 0x0,
2021
16
                NULL, HFILL }},
2022
2023
16
            { &hf_zbee_nwk_src,
2024
16
            { "Source",                 "zbee_nwk.src", FT_UINT16, BASE_HEX, NULL, 0x0,
2025
16
                NULL, HFILL }},
2026
2027
16
            { &hf_zbee_nwk_addr,
2028
16
            { "Address",                 "zbee_nwk.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
2029
16
                NULL, HFILL }},
2030
2031
16
            { &hf_zbee_nwk_radius,
2032
16
            { "Radius",                 "zbee_nwk.radius", FT_UINT8, BASE_DEC, NULL, 0x0,
2033
16
                "Number of hops remaining for a range-limited broadcast packet.", HFILL }},
2034
2035
16
            { &hf_zbee_nwk_seqno,
2036
16
            { "Sequence Number",        "zbee_nwk.seqno", FT_UINT8, BASE_DEC, NULL, 0x0,
2037
16
                NULL, HFILL }},
2038
2039
16
            { &hf_zbee_nwk_mcast,
2040
16
            { "Multicast Control Field",         "zbee_nwk.multicast.cf", FT_UINT8, BASE_HEX, NULL, 0x0,
2041
16
                NULL, HFILL }},
2042
2043
16
            { &hf_zbee_nwk_mcast_mode,
2044
16
            { "Multicast Mode",         "zbee_nwk.multicast.mode", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_MCAST_MODE,
2045
16
                "Controls whether this packet is permitted to be routed through non-members of the multicast group.",
2046
16
                HFILL }},
2047
2048
16
            { &hf_zbee_nwk_mcast_radius,
2049
16
            { "Non-Member Radius",      "zbee_nwk.multicast.radius", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_MCAST_RADIUS,
2050
16
                "Limits the range of multicast packets when being routed through non-members.", HFILL }},
2051
2052
16
            { &hf_zbee_nwk_mcast_max_radius,
2053
16
            { "Max Non-Member Radius",  "zbee_nwk.multicast.max_radius", FT_UINT8, BASE_DEC, NULL,
2054
16
                ZBEE_NWK_MCAST_MAX_RADIUS, NULL, HFILL }},
2055
2056
16
            { &hf_zbee_nwk_dst64,
2057
16
            { "Destination",   "zbee_nwk.dst64", FT_EUI64, BASE_NONE, NULL, 0x0,
2058
16
                NULL, HFILL }},
2059
2060
16
            { &hf_zbee_nwk_src64,
2061
16
            { "Extended Source",        "zbee_nwk.src64", FT_EUI64, BASE_NONE, NULL, 0x0,
2062
16
                NULL, HFILL }},
2063
2064
16
            { &hf_zbee_nwk_addr64,
2065
16
            { "Extended Address",        "zbee_nwk.addr64", FT_EUI64, BASE_NONE, NULL, 0x0,
2066
16
                NULL, HFILL }},
2067
2068
16
            { &hf_zbee_nwk_src64_origin,
2069
16
            { "Origin",        "zbee_nwk.src64.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2070
16
                NULL, HFILL }},
2071
2072
16
            { &hf_zbee_nwk_relay_count,
2073
16
            { "Relay Count",            "zbee_nwk.relay.count", FT_UINT8, BASE_DEC, NULL, 0x0,
2074
16
                "Number of entries in the relay list.", HFILL }},
2075
2076
16
            { &hf_zbee_nwk_relay_index,
2077
16
            { "Relay Index",            "zbee_nwk.relay.index", FT_UINT8, BASE_DEC, NULL, 0x0,
2078
16
                "Number of relays required to route to the source device.", HFILL }},
2079
2080
16
            { &hf_zbee_nwk_relay,
2081
16
            { "Relay",            "zbee_nwk.relay", FT_UINT16, BASE_DEC, NULL, 0x0,
2082
16
                NULL, HFILL }},
2083
2084
16
            { &hf_zbee_nwk_cmd_id,
2085
16
            { "Command Identifier",     "zbee_nwk.cmd.id", FT_UINT8, BASE_HEX, VALS(zbee_nwk_cmd_names), 0x0,
2086
16
                NULL, HFILL }},
2087
2088
16
            { &hf_zbee_nwk_cmd_addr,
2089
16
            { "Address",                "zbee_nwk.cmd.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
2090
16
                NULL, HFILL }},
2091
2092
16
            { &hf_zbee_nwk_cmd_route_id,
2093
16
            { "Route ID",               "zbee_nwk.cmd.route.id", FT_UINT8, BASE_DEC, NULL, 0x0,
2094
16
                "A sequence number for routing commands.", HFILL }},
2095
2096
16
            { &hf_zbee_nwk_cmd_route_dest,
2097
16
            { "Destination",            "zbee_nwk.cmd.route.dest", FT_UINT16, BASE_HEX, NULL, 0x0,
2098
16
                NULL, HFILL }},
2099
2100
16
            { &hf_zbee_nwk_cmd_route_orig,
2101
16
            { "Originator",             "zbee_nwk.cmd.route.orig", FT_UINT16, BASE_HEX, NULL, 0x0,
2102
16
                NULL, HFILL }},
2103
2104
16
            { &hf_zbee_nwk_cmd_route_resp,
2105
16
            { "Responder",              "zbee_nwk.cmd.route.resp", FT_UINT16, BASE_HEX, NULL, 0x0,
2106
16
                NULL, HFILL }},
2107
2108
16
            { &hf_zbee_nwk_cmd_route_dest_ext,
2109
16
            { "Extended Destination",   "zbee_nwk.cmd.route.dest_ext", FT_EUI64, BASE_NONE, NULL, 0x0,
2110
16
                NULL, HFILL }},
2111
2112
16
            { &hf_zbee_nwk_cmd_route_orig_ext,
2113
16
            { "Extended Originator",    "zbee_nwk.cmd.route.orig_ext", FT_EUI64, BASE_NONE, NULL, 0x0,
2114
16
                NULL, HFILL }},
2115
2116
16
            { &hf_zbee_nwk_cmd_route_resp_ext,
2117
16
            { "Extended Responder",     "zbee_nwk.cmd.route.resp_ext", FT_EUI64, BASE_NONE, NULL, 0x0,
2118
16
                NULL, HFILL }},
2119
2120
16
            { &hf_zbee_nwk_cmd_route_cost,
2121
16
            { "Path Cost",              "zbee_nwk.cmd.route.cost", FT_UINT8, BASE_DEC, NULL, 0x0,
2122
16
                "A value specifying the efficiency of this route.", HFILL }},
2123
2124
16
            { &hf_zbee_nwk_cmd_route_options,
2125
16
            { "Command Options",           "zbee_nwk.cmd.route.opts", FT_UINT8, BASE_HEX, NULL, 0x0,
2126
16
                NULL, HFILL }},
2127
2128
16
            { &hf_zbee_nwk_cmd_route_opt_repair,
2129
16
            { "Route Repair",           "zbee_nwk.cmd.route.opts.repair", FT_BOOLEAN, 8, NULL,
2130
16
                ZBEE_NWK_CMD_ROUTE_OPTION_REPAIR,
2131
16
                "Flag identifying whether the route request command was to repair a failed route.", HFILL }},
2132
2133
16
            { &hf_zbee_nwk_cmd_route_opt_multicast,
2134
16
            { "Multicast",              "zbee_nwk.cmd.route.opts.mcast", FT_BOOLEAN, 8, NULL,
2135
16
                ZBEE_NWK_CMD_ROUTE_OPTION_MCAST,
2136
16
                "Flag identifying this as a multicast route request.", HFILL }},
2137
2138
16
            { &hf_zbee_nwk_cmd_route_opt_dest_ext,
2139
16
            { "Extended Destination",   "zbee_nwk.cmd.route.opts.dest_ext", FT_BOOLEAN, 8, NULL,
2140
16
                ZBEE_NWK_CMD_ROUTE_OPTION_DEST_EXT, NULL, HFILL }},
2141
2142
16
            { &hf_zbee_nwk_cmd_route_opt_resp_ext,
2143
16
            { "Extended Responder",   "zbee_nwk.cmd.route.opts.resp_ext", FT_BOOLEAN, 8, NULL,
2144
16
                ZBEE_NWK_CMD_ROUTE_OPTION_RESP_EXT, NULL, HFILL }},
2145
2146
16
            { &hf_zbee_nwk_cmd_route_opt_orig_ext,
2147
16
            { "Extended Originator",    "zbee_nwk.cmd.route.opts.orig_ext", FT_BOOLEAN, 8, NULL,
2148
16
                ZBEE_NWK_CMD_ROUTE_OPTION_ORIG_EXT, NULL, HFILL }},
2149
2150
16
            { &hf_zbee_nwk_cmd_route_opt_many_to_one,
2151
16
            { "Many-to-One Discovery",  "zbee_nwk.cmd.route.opts.many2one", FT_UINT8, BASE_HEX,
2152
16
                VALS(zbee_nwk_cmd_route_many_modes), ZBEE_NWK_CMD_ROUTE_OPTION_MANY_MASK,
2153
16
                NULL, HFILL }},
2154
2155
16
            { &hf_zbee_nwk_cmd_nwk_status,
2156
16
            { "Status Code",            "zbee_nwk.cmd.status", FT_UINT8, BASE_HEX, VALS(zbee_nwk_status_codes), 0x0,
2157
16
                NULL, HFILL }},
2158
2159
16
            { &hf_zbee_nwk_cmd_nwk_status_command_id,
2160
16
            { "Unknown Command ID",     "zbee_nwk.cmd.status.unknown_command_id", FT_UINT8, BASE_HEX,
2161
16
                    VALS(zbee_nwk_cmd_names), 0x0, NULL, HFILL }},
2162
2163
16
            { &hf_zbee_nwk_cmd_leave_rejoin,
2164
16
            { "Rejoin",                 "zbee_nwk.cmd.leave.rejoin", FT_BOOLEAN, 8, NULL,
2165
16
                ZBEE_NWK_CMD_LEAVE_OPTION_REJOIN, "Flag instructing the device to rejoin the network.", HFILL }},
2166
2167
16
            { &hf_zbee_nwk_cmd_leave_request,
2168
16
            { "Request",                "zbee_nwk.cmd.leave.request", FT_BOOLEAN, 8, NULL,
2169
16
                ZBEE_NWK_CMD_LEAVE_OPTION_REQUEST,
2170
16
                "Flag identifying the direction of this command. 1=Request, 0=Indication", HFILL }},
2171
2172
16
            { &hf_zbee_nwk_cmd_leave_children,
2173
16
            { "Remove Children",        "zbee_nwk.cmd.leave.children", FT_BOOLEAN, 8, NULL,
2174
16
                ZBEE_NWK_CMD_LEAVE_OPTION_CHILDREN,
2175
16
                "Flag instructing the device to remove its children in addition to itself.", HFILL }},
2176
2177
16
            { &hf_zbee_nwk_cmd_relay_count,
2178
16
            { "Relay Count",            "zbee_nwk.cmd.relay_count", FT_UINT8, BASE_DEC, NULL, 0x0,
2179
16
                "Number of relays required to route to the destination.", HFILL }},
2180
2181
16
            { &hf_zbee_nwk_cmd_relay_device,
2182
16
            { "Relay Device",            "zbee_nwk.cmd.relay_device", FT_UINT16, BASE_HEX, NULL, 0x0,
2183
16
                NULL, HFILL }},
2184
2185
16
            { &hf_zbee_nwk_cmd_cinfo,
2186
16
            { "Capability Information",  "zbee_nwk.cmd.cinfo", FT_UINT8, BASE_HEX, NULL,
2187
16
                0x0, NULL, HFILL }},
2188
2189
16
            { &hf_zbee_nwk_cmd_cinfo_alt_coord,
2190
16
            { "Alternate Coordinator",  "zbee_nwk.cmd.cinfo.alt_coord", FT_BOOLEAN, 8, NULL,
2191
16
                IEEE802154_CMD_CINFO_ALT_PAN_COORD,
2192
16
                "Indicates that the device is able to operate as a PAN coordinator.", HFILL }},
2193
2194
16
            { &hf_zbee_nwk_cmd_cinfo_type,
2195
16
            { "Full-Function Device",   "zbee_nwk.cmd.cinfo.ffd", FT_BOOLEAN, 8, NULL,
2196
16
                IEEE802154_CMD_CINFO_DEVICE_TYPE, NULL, HFILL }},
2197
2198
16
            { &hf_zbee_nwk_cmd_cinfo_power,
2199
16
            { "AC Power",               "zbee_nwk.cmd.cinfo.power", FT_BOOLEAN, 8, NULL,
2200
16
                IEEE802154_CMD_CINFO_POWER_SRC, "Indicates this device is using AC/Mains power.", HFILL }},
2201
2202
16
            { &hf_zbee_nwk_cmd_cinfo_idle_rx,
2203
16
            { "Rx On When Idle",        "zbee_nwk.cmd.cinfo.on_idle", FT_BOOLEAN, 8, NULL,
2204
16
                IEEE802154_CMD_CINFO_IDLE_RX,
2205
16
                "Indicates the receiver is active when the device is idle.", HFILL }},
2206
2207
16
            { &hf_zbee_nwk_cmd_cinfo_security,
2208
16
            { "Security Capability",    "zbee_nwk.cmd.cinfo.security", FT_BOOLEAN, 8, NULL,
2209
16
                IEEE802154_CMD_CINFO_SEC_CAPABLE,
2210
16
                "Indicates this device is capable of performing encryption/decryption.", HFILL }},
2211
2212
16
            { &hf_zbee_nwk_cmd_cinfo_alloc,
2213
16
            { "Allocate Short Address", "zbee_nwk.cmd.cinfo.alloc", FT_BOOLEAN, 8, NULL,
2214
16
                IEEE802154_CMD_CINFO_ALLOC_ADDR,
2215
16
                "Flag requesting the parent to allocate a short address for this device.", HFILL }},
2216
2217
16
            { &hf_zbee_nwk_cmd_rejoin_status,
2218
16
            { "Status",                 "zbee_nwk.cmd.rejoin_status", FT_UINT8, BASE_HEX,
2219
16
                VALS(zbee_nwk_rejoin_codes), 0x0, NULL, HFILL }},
2220
2221
16
            { &hf_zbee_nwk_cmd_link_last,
2222
16
            { "Last Frame",             "zbee_nwk.cmd.link.last", FT_BOOLEAN, 8, NULL,
2223
16
                ZBEE_NWK_CMD_LINK_OPTION_LAST_FRAME,
2224
16
                "Flag indicating the last in a series of link status commands.", HFILL }},
2225
2226
16
            { &hf_zbee_nwk_cmd_link_first,
2227
16
            { "First Frame",            "zbee_nwk.cmd.link.first", FT_BOOLEAN, 8, NULL,
2228
16
                ZBEE_NWK_CMD_LINK_OPTION_FIRST_FRAME,
2229
16
                "Flag indicating the first in a series of link status commands.", HFILL }},
2230
2231
16
            { &hf_zbee_nwk_cmd_link_count,
2232
16
            { "Link Status Count",      "zbee_nwk.cmd.link.count", FT_UINT8, BASE_DEC, NULL,
2233
16
                ZBEE_NWK_CMD_LINK_OPTION_COUNT_MASK, NULL, HFILL }},
2234
2235
16
            { &hf_zbee_nwk_cmd_link_address,
2236
16
            { "Address",      "zbee_nwk.cmd.link.address", FT_UINT16, BASE_HEX, NULL,
2237
16
                0x0, NULL, HFILL }},
2238
2239
16
            { &hf_zbee_nwk_cmd_link_incoming_cost,
2240
16
            { "Incoming Cost",      "zbee_nwk.cmd.link.incoming_cost", FT_UINT8, BASE_DEC, NULL,
2241
16
                ZBEE_NWK_CMD_LINK_INCOMMING_COST_MASK, NULL, HFILL }},
2242
2243
16
            { &hf_zbee_nwk_cmd_link_outgoing_cost,
2244
16
            { "Outgoing Cost",      "zbee_nwk.cmd.link.outgoing_cost", FT_UINT8, BASE_DEC, NULL,
2245
16
                ZBEE_NWK_CMD_LINK_OUTGOING_COST_MASK, NULL, HFILL }},
2246
2247
16
            { &hf_zbee_nwk_cmd_report_type,
2248
16
            { "Report Type",            "zbee_nwk.cmd.report.type", FT_UINT8, BASE_HEX,
2249
16
                VALS(zbee_nwk_report_types), ZBEE_NWK_CMD_NWK_REPORT_ID_MASK, NULL, HFILL }},
2250
2251
16
            { &hf_zbee_nwk_cmd_report_count,
2252
16
            { "Report Information Count",   "zbee_nwk.cmd.report.count", FT_UINT8, BASE_DEC, NULL,
2253
16
                ZBEE_NWK_CMD_NWK_REPORT_COUNT_MASK, NULL, HFILL }},
2254
2255
16
            { &hf_zbee_nwk_cmd_update_type,
2256
16
            { "Update Type",            "zbee_nwk.cmd.update.type", FT_UINT8, BASE_HEX,
2257
16
                VALS(zbee_nwk_update_types), ZBEE_NWK_CMD_NWK_UPDATE_ID_MASK, NULL, HFILL }},
2258
2259
16
            { &hf_zbee_nwk_cmd_update_count,
2260
16
            { "Update Information Count",   "zbee_nwk.cmd.update.count", FT_UINT8, BASE_DEC, NULL,
2261
16
                ZBEE_NWK_CMD_NWK_UPDATE_COUNT_MASK, NULL, HFILL }},
2262
2263
16
            { &hf_zbee_nwk_cmd_update_id,
2264
16
            { "Update ID",              "zbee_nwk.cmd.update.id", FT_UINT8, BASE_DEC, NULL, 0x0,
2265
16
                NULL, HFILL }},
2266
2267
16
            { &hf_zbee_nwk_panid,
2268
16
            { "PAN ID",        "zbee_nwk.panid", FT_UINT16, BASE_HEX, NULL, 0x0,
2269
16
                NULL, HFILL }},
2270
2271
16
            { &hf_zbee_zboss_nwk_cmd_key,
2272
16
            { "ZBOSS Key",        "zbee_nwk.zboss_key", FT_BYTES, BASE_NONE, NULL, 0x0,
2273
16
                NULL, HFILL }},
2274
2275
16
            { &hf_zbee_nwk_cmd_epid,
2276
16
            { "Extended PAN ID",        "zbee_nwk.cmd.epid", FT_EUI64, BASE_NONE, NULL, 0x0,
2277
16
                NULL, HFILL }},
2278
2279
16
            { &hf_zbee_nwk_cmd_end_device_timeout_request_enum,
2280
16
            { "Requested Timeout Enumeration",        "zbee_nwk.cmd.ed_tmo_req", FT_UINT8, BASE_DEC,
2281
16
              VALS(zbee_nwk_end_device_timeout_request), 0, NULL, HFILL }},
2282
2283
16
            { &hf_zbee_nwk_cmd_end_device_configuration,
2284
16
            { "End Device Configuration",        "zbee_nwk.cmd.ed_config", FT_UINT8, BASE_HEX, NULL, 0x0,
2285
16
                NULL, HFILL }},
2286
2287
16
            { &hf_zbee_nwk_cmd_end_device_timeout_resp_status,
2288
16
            { "Status",        "zbee_nwk.cmd.ed_tmo_rsp_status", FT_UINT8, BASE_DEC,
2289
16
              VALS(zbee_nwk_end_device_timeout_resp_status), 0, NULL, HFILL }},
2290
2291
16
            { &hf_zbee_nwk_cmd_end_device_timeout_resp_parent_info,
2292
16
            { "Parent Information",        "zbee_nwk.cmd.ed_prnt_info", FT_UINT8, BASE_HEX, NULL, 0x0,
2293
16
                NULL, HFILL }},
2294
2295
16
            { &hf_zbee_nwk_cmd_prnt_info_mac_data_poll_keepalive_supported,
2296
16
            { "MAC Data Poll Keepalive",           "zbee_nwk.cmd.ed_prnt_info.mac_data_poll_keepalive", FT_BOOLEAN, 8, NULL,
2297
16
              ZBEE_NWK_CMD_ED_TIMEO_RSP_PRNT_INFO_MAC_DATA_POLL_KEEPAL_SUPP,
2298
16
              NULL, HFILL }},
2299
2300
16
            { &hf_zbee_nwk_cmd_prnt_info_ed_to_req_keepalive_supported,
2301
16
            { "End Device Timeout Request Keepalive",           "zbee_nwk.cmd.ed_prnt_info.ed_tmo_req_keepalive", FT_BOOLEAN, 8, NULL,
2302
16
              ZBEE_NWK_CMD_ED_TIMEO_RSP_PRNT_INFO_ED_TIMOU_REQ_KEEPAL_SUPP,
2303
16
              NULL, HFILL }},
2304
2305
16
            { &hf_zbee_nwk_cmd_prnt_info_power_negotiation_supported,
2306
16
            { "Power Negotiation Supported",           "zbee_nwk.cmd.power_negotiation_supported", FT_BOOLEAN, 8, NULL,
2307
16
              ZBEE_NWK_CMD_ED_TIMEO_RSP_PRNT_INFO_PWR_NEG_SUPP,
2308
16
              NULL, HFILL }},
2309
2310
16
            { &hf_zbee_nwk_cmd_link_pwr_type,
2311
16
            { "Type",        "zbee_nwk.cmd.link_pwr_delta.type", FT_UINT8, BASE_HEX,
2312
16
                VALS(zbee_nwk_link_power_delta_types), ZBEE_NWK_CMD_NWK_LINK_PWR_DELTA_TYPE_MASK, NULL, HFILL }},
2313
2314
16
            { &hf_zbee_nwk_cmd_link_pwr_list_count,
2315
16
            { "Structure Count",        "zbee_nwk.cmd.link_pwr_delta.list_count", FT_UINT8, BASE_DEC, NULL, 0x0,
2316
16
              NULL, HFILL }},
2317
2318
16
            { &hf_zbee_nwk_cmd_link_pwr_device_address,
2319
16
            { "Device Address",      "zbee_nwk.cmd.link_pwr_delta.address", FT_UINT16, BASE_HEX, NULL,
2320
16
                0x0, NULL, HFILL }},
2321
2322
16
            { &hf_zbee_nwk_cmd_link_pwr_power_delta,
2323
16
            { "Power Delta",         "zbee_nwk.cmd.link_pwr_delta.power_delta", FT_INT8, BASE_DEC, NULL, 0x0,
2324
16
                    NULL, HFILL }},
2325
2326
16
            { &hf_zbee_nwk_cmd_association_type,
2327
16
              { "Association Type",        "zbee_nwk.cmd.association_type", FT_UINT8, BASE_HEX,
2328
16
                VALS(zbee_nwk_commissioning_types), 0x0, NULL, HFILL }},
2329
2330
16
            { &hf_zbee_beacon_protocol,
2331
16
            { "Protocol ID",            "zbee_beacon.protocol", FT_UINT8, BASE_DEC, NULL, 0x0,
2332
16
                NULL, HFILL }},
2333
2334
16
            { &hf_zbee_beacon_stack_profile,
2335
16
            { "Stack Profile",          "zbee_beacon.profile", FT_UINT16, BASE_HEX,
2336
16
                VALS(zbee_nwk_stack_profiles), ZBEE_NWK_BEACON_STACK_PROFILE, NULL, HFILL }},
2337
2338
16
            { &hf_zbee_beacon_version,
2339
16
            { "Protocol Version",       "zbee_beacon.version", FT_UINT16, BASE_DEC, NULL, ZBEE_NWK_BEACON_PROTOCOL_VERSION,
2340
16
                NULL, HFILL }},
2341
2342
16
            { &hf_zbee_beacon_router_capacity,
2343
16
            { "Router Capacity", "zbee_beacon.router", FT_BOOLEAN, 16, NULL, ZBEE_NWK_BEACON_ROUTER_CAPACITY,
2344
16
                "Whether the device can accept join requests from routing capable devices.", HFILL }},
2345
2346
16
            { &hf_zbee_beacon_depth,
2347
16
            { "Device Depth",           "zbee_beacon.depth", FT_UINT16, BASE_DEC, NULL, ZBEE_NWK_BEACON_NETWORK_DEPTH,
2348
16
                "The tree depth of the device, 0 indicates the network coordinator.", HFILL }},
2349
2350
16
            { &hf_zbee_beacon_end_device_capacity,
2351
16
            { "End Device Capacity",        "zbee_beacon.end_dev", FT_BOOLEAN, 16, NULL, ZBEE_NWK_BEACON_END_DEVICE_CAPACITY,
2352
16
                "Whether the device can accept join requests from ZigBee end devices.", HFILL }},
2353
2354
16
            { &hf_zbee_beacon_epid,
2355
16
            { "Extended PAN ID",        "zbee_beacon.ext_panid", FT_EUI64, BASE_NONE, NULL, 0x0,
2356
16
                "Extended PAN identifier.", HFILL }},
2357
2358
16
            { &hf_zbee_beacon_tx_offset,
2359
16
            { "Tx Offset",              "zbee_beacon.tx_offset", FT_UINT24, BASE_DEC, NULL, 0x0,
2360
16
                "The time difference between a device and its parent's beacon.", HFILL }},
2361
2362
16
            { &hf_zbee_beacon_update_id,
2363
16
            { "Update ID",              "zbee_beacon.update_id", FT_UINT8, BASE_DEC, NULL, 0x0,
2364
16
                NULL, HFILL }},
2365
2366
16
            { &hf_zbip_beacon_allow_join,
2367
16
            { "Allow Join",             "zbip_beacon.allow_join", FT_BOOLEAN, 8, NULL, ZBEE_IP_BEACON_ALLOW_JOIN,
2368
16
                NULL, HFILL }},
2369
2370
16
            { &hf_zbip_beacon_router_capacity,
2371
16
            { "Router Capacity",        "zbip_beacon.router", FT_BOOLEAN, 8, NULL, ZBEE_IP_BEACON_ROUTER_CAPACITY,
2372
16
                "Whether this device can accept new routers on the network.", HFILL }},
2373
2374
16
            { &hf_zbip_beacon_host_capacity,
2375
16
            { "Host Capacity",        "zbip_beacon.host", FT_BOOLEAN, 8, NULL, ZBEE_IP_BEACON_HOST_CAPACITY,
2376
16
                "Whether this device can accept new host on the network.", HFILL }},
2377
2378
16
            { &hf_zbip_beacon_unsecure,
2379
16
            { "Unsecure Network",     "zbip_beacon.unsecure", FT_BOOLEAN, 8, NULL, ZBEE_IP_BEACON_UNSECURE,
2380
16
                "Indicates that this network is not using link layer security.", HFILL }},
2381
2382
16
            { &hf_zbip_beacon_network_id,
2383
16
            { "Network ID",           "zbip_beacon.network_id", FT_STRING, BASE_NONE, NULL, 0x0,
2384
16
                "A string that uniquely identifies this network.", HFILL }},
2385
2386
16
            { &hf_ieee802154_zigbee_ie,
2387
16
            { "IE header",                       "zbee_nwk.zigbee_ie", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2388
2389
16
            { &hf_ieee802154_zigbee_ie_id,
2390
16
            { "Id",                              "zbee_nwk.zigbee_ie.id", FT_UINT16, BASE_HEX, VALS(ieee802154_zigbee_ie_names),
2391
16
                    ZBEE_ZIGBEE_IE_ID_MASK, NULL, HFILL }},
2392
2393
16
            { &hf_ieee802154_zigbee_ie_length,
2394
16
            { "Length",                           "zbee_nwk.zigbee_ie.length", FT_UINT16, BASE_DEC, NULL,
2395
16
                    ZBEE_ZIGBEE_IE_LENGTH_MASK, NULL, HFILL }},
2396
2397
16
            { &hf_ieee802154_zigbee_ie_tx_power,
2398
16
            { "Tx Power (dBm)",                  "zbee_nwk.zigbee_ie.tx_power", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
2399
2400
16
            { &hf_ieee802154_zigbee_ie_source_addr,
2401
16
            { "Source Address",                  "zbee_nwk.zigbee_ie.source_address", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2402
2403
2404
16
            { &hf_ieee802154_zigbee_rejoin_epid,
2405
16
            { "Extended PAN ID",                "zbee_nwk.zigbee_rejoin.ext_panid", FT_EUI64, BASE_NONE, NULL, 0x0,
2406
16
                "Extended PAN identifier", HFILL }},
2407
2408
16
            { &hf_ieee802154_zigbee_rejoin_source_addr,
2409
16
            { "Source Address",                  "zbee_nwk.zigbee_rejoin.source_address", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
2410
2411
2412
16
    };
2413
2414
    /*  NWK Layer subtrees */
2415
16
    static int *ett[] = {
2416
16
        &ett_zbee_nwk,
2417
16
        &ett_zbee_nwk_beacon,
2418
16
        &ett_zbee_nwk_fcf,
2419
16
        &ett_zbee_nwk_fcf_ext,
2420
16
        &ett_zbee_nwk_mcast,
2421
16
        &ett_zbee_nwk_route,
2422
16
        &ett_zbee_nwk_cmd,
2423
16
        &ett_zbee_nwk_cmd_options,
2424
16
        &ett_zbee_nwk_cmd_cinfo,
2425
16
        &ett_zbee_nwk_cmd_link,
2426
16
        &ett_zbee_nwk_cmd_ed_to_rsp_prnt_info,
2427
16
        &ett_zbee_nwk_cmd_link_pwr_struct,
2428
16
        &ett_zbee_nwk_zigbee_ie_fields,
2429
16
        &ett_zbee_nwk_ie_rejoin,
2430
16
        &ett_zbee_nwk_header,
2431
16
        &ett_zbee_nwk_header_ie,
2432
16
        &ett_zbee_nwk_beacon_bitfield,
2433
16
    };
2434
2435
16
    static ei_register_info ei[] = {
2436
16
        { &ei_zbee_nwk_missing_payload, { "zbee_nwk.missing_payload", PI_MALFORMED, PI_ERROR, "Missing Payload", EXPFILL }},
2437
16
    };
2438
2439
16
    expert_module_t* expert_zbee_nwk;
2440
2441
16
    register_init_routine(proto_init_zbee_nwk);
2442
16
    register_cleanup_routine(proto_cleanup_zbee_nwk);
2443
2444
    /* Register the protocol with Wireshark. */
2445
16
    proto_zbee_nwk = proto_register_protocol("ZigBee Network Layer", "ZigBee", ZBEE_PROTOABBREV_NWK);
2446
16
    proto_zbee_beacon = proto_register_protocol("ZigBee Beacon", "ZigBee Beacon", "zbee_beacon");
2447
16
    proto_zbip_beacon = proto_register_protocol("ZigBee IP Beacon", "ZigBee IP Beacon", "zbip_beacon");
2448
16
    proto_zbee_ie = proto_register_protocol("ZigBee IE", "ZigBee IE", "zbee_ie");
2449
16
    proto_register_field_array(proto_zbee_nwk, hf, array_length(hf));
2450
16
    proto_register_subtree_array(ett, array_length(ett));
2451
2452
16
    expert_zbee_nwk = expert_register_protocol(proto_zbee_nwk);
2453
16
    expert_register_field_array(expert_zbee_nwk, ei, array_length(ei));
2454
2455
    /* Register the dissectors with Wireshark. */
2456
16
    register_dissector(ZBEE_PROTOABBREV_NWK, dissect_zbee_nwk, proto_zbee_nwk);
2457
16
    register_dissector("zbee_beacon", dissect_zbee_beacon, proto_zbee_beacon);
2458
16
    register_dissector("zbip_beacon", dissect_zbip_beacon, proto_zbip_beacon);
2459
16
    register_dissector("zbee_ie", dissect_zbee_ie, proto_zbee_ie);
2460
2461
16
    zbee_nwk_address_type = address_type_dissector_register("AT_ZIGBEE", "ZigBee 16-bit address",
2462
16
            zbee_nwk_address_to_str, zbee_nwk_address_str_len, NULL, NULL, zbee_nwk_address_len, NULL, NULL);
2463
2464
    /* Register the Security dissector. */
2465
16
    zbee_security_register(NULL, proto_zbee_nwk);
2466
2467
16
    zbee_nwk_tap = register_tap(ZBEE_PROTOABBREV_NWK);
2468
2469
16
    register_conversation_table(proto_zbee_nwk, true, zbee_nwk_conversation_packet, zbee_nwk_endpoint_packet);
2470
16
    register_conversation_filter(ZBEE_PROTOABBREV_NWK, "ZigBee Network Layer", zbee_nwk_filter_valid, zbee_nwk_build_filter, NULL);
2471
16
} /* proto_register_zbee_nwk */
2472
2473
/**
2474
 *Registers the zigbee dissector with Wireshark.
2475
 *
2476
*/
2477
void proto_reg_handoff_zbee_nwk(void)
2478
16
{
2479
    /* Find the other dissectors we need. */
2480
16
    aps_handle      = find_dissector_add_dependency(ZBEE_PROTOABBREV_APS, proto_zbee_nwk);
2481
16
    zbee_gp_handle  = find_dissector_add_dependency(ZBEE_PROTOABBREV_NWK_GP, proto_zbee_nwk);
2482
2483
    /* Register our dissector with IEEE 802.15.4 */
2484
16
    dissector_add_for_decode_as(IEEE802154_PROTOABBREV_WPAN_PANID, find_dissector(ZBEE_PROTOABBREV_NWK));
2485
16
    heur_dissector_add(IEEE802154_PROTOABBREV_WPAN_BEACON, dissect_zbee_beacon_heur, "ZigBee Beacon", "zbee_wpan_beacon", proto_zbee_beacon, HEURISTIC_ENABLE);
2486
16
    heur_dissector_add(IEEE802154_PROTOABBREV_WPAN_BEACON, dissect_zbip_beacon_heur, "ZigBee IP Beacon", "zbip_wpan_beacon", proto_zbip_beacon, HEURISTIC_ENABLE);
2487
16
    heur_dissector_add(IEEE802154_PROTOABBREV_WPAN, dissect_zbee_nwk_heur, "ZigBee Network Layer over IEEE 802.15.4", "zbee_nwk_wpan", proto_zbee_nwk, HEURISTIC_ENABLE);
2488
2489
16
    proto_ieee802154 = proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN);
2490
2491
16
} /* proto_reg_handoff_zbee */
2492
2493
static void free_keyring_key(void *key)
2494
0
{
2495
0
    g_free(key);
2496
0
}
2497
2498
static void free_keyring_val(void *a)
2499
0
{
2500
0
    GSList **slist = (GSList **)a;
2501
0
    g_slist_free_full(*slist, g_free);
2502
0
    g_free(slist);
2503
0
}
2504
2505
/**
2506
 *Init routine for the nwk dissector. Creates a
2507
 *
2508
*/
2509
static void
2510
proto_init_zbee_nwk(void)
2511
16
{
2512
16
    zbee_nwk_map.short_table = g_hash_table_new(ieee802154_short_addr_hash, ieee802154_short_addr_equal);
2513
16
    zbee_nwk_map.long_table = g_hash_table_new(ieee802154_long_addr_hash, ieee802154_long_addr_equal);
2514
16
    zbee_table_nwk_keyring  = g_hash_table_new_full(g_int_hash, g_int_equal, free_keyring_key, free_keyring_val);
2515
16
} /* proto_init_zbee_nwk */
2516
2517
static void
2518
proto_cleanup_zbee_nwk(void)
2519
0
{
2520
0
    g_hash_table_destroy(zbee_nwk_map.short_table);
2521
0
    g_hash_table_destroy(zbee_nwk_map.long_table);
2522
0
    g_hash_table_destroy(zbee_table_nwk_keyring);
2523
0
}
2524
2525
/*
2526
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2527
 *
2528
 * Local variables:
2529
 * c-basic-offset: 4
2530
 * tab-width: 8
2531
 * indent-tabs-mode: nil
2532
 * End:
2533
 *
2534
 * vi: set shiftwidth=4 tabstop=8 expandtab:
2535
 * :indentSize=4:tabSize=8:noTabs=true:
2536
 */