Coverage Report

Created: 2025-02-15 06:25

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