Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-lorawan.c
Line
Count
Source
1
/* packet-lorawan.c
2
 * Dissector routines for the LoRaWAN protocol
3
 * By Erik de Jong <erikdejong@gmail.com>
4
 * Copyright 2017 Erik de Jong
5
 * Copyright 2022 Ales Povalac <alpov@alpov.net>
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
#include "config.h"
15
#include <math.h>
16
#include <epan/packet.h>
17
#include <epan/expert.h>
18
#include <epan/prefs.h>
19
#include <epan/uat.h>
20
#include <epan/strutil.h>
21
#include <epan/crc16-tvb.h> /* For CRC verification */
22
#include <epan/unit_strings.h>
23
24
#include <wsutil/array.h>
25
#include <wsutil/wsgcrypt.h>
26
27
void proto_reg_handoff_lorawan(void);
28
void proto_register_lorawan(void);
29
30
static dissector_handle_t lorawan_handle;
31
32
static int proto_lorawan;
33
static int hf_lorawan_msgtype_type;
34
static int hf_lorawan_mac_header_type;
35
static int hf_lorawan_mac_header_ftype_type;
36
static int hf_lorawan_mac_header_rfu_type;
37
static int hf_lorawan_mac_header_major_type;
38
static int hf_lorawan_mac_commands_type;
39
static int hf_lorawan_mac_command_uplink_type;
40
static int hf_lorawan_mac_command_downlink_type;
41
static int hf_lorawan_mac_command_down_link_check_ans_type;
42
static int hf_lorawan_mac_command_down_link_check_ans_margin_type;
43
static int hf_lorawan_mac_command_down_link_check_ans_gwcnt_type;
44
static int hf_lorawan_mac_command_down_link_adr_req_datarate_type;
45
static int hf_lorawan_mac_command_down_link_adr_req_txpower_type;
46
static int hf_lorawan_mac_command_down_link_adr_req_channel_type;
47
static int hf_lorawan_mac_command_down_link_adr_req_channel1_type;
48
static int hf_lorawan_mac_command_down_link_adr_req_channel2_type;
49
static int hf_lorawan_mac_command_down_link_adr_req_channel3_type;
50
static int hf_lorawan_mac_command_down_link_adr_req_channel4_type;
51
static int hf_lorawan_mac_command_down_link_adr_req_channel5_type;
52
static int hf_lorawan_mac_command_down_link_adr_req_channel6_type;
53
static int hf_lorawan_mac_command_down_link_adr_req_channel7_type;
54
static int hf_lorawan_mac_command_down_link_adr_req_channel8_type;
55
static int hf_lorawan_mac_command_down_link_adr_req_channel9_type;
56
static int hf_lorawan_mac_command_down_link_adr_req_channel10_type;
57
static int hf_lorawan_mac_command_down_link_adr_req_channel11_type;
58
static int hf_lorawan_mac_command_down_link_adr_req_channel12_type;
59
static int hf_lorawan_mac_command_down_link_adr_req_channel13_type;
60
static int hf_lorawan_mac_command_down_link_adr_req_channel14_type;
61
static int hf_lorawan_mac_command_down_link_adr_req_channel15_type;
62
static int hf_lorawan_mac_command_down_link_adr_req_channel16_type;
63
static int hf_lorawan_mac_command_down_link_adr_req_channel_mask_control_type;
64
static int hf_lorawan_mac_command_down_link_adr_req_repetitions_type;
65
static int hf_lorawan_mac_command_up_link_adr_ans_txpower_type;
66
static int hf_lorawan_mac_command_up_link_adr_ans_datarate_type;
67
static int hf_lorawan_mac_command_up_link_adr_ans_channel_mask_type;
68
static int hf_lorawan_mac_command_down_dutycycle_type;
69
static int hf_lorawan_mac_command_down_rx_setup_req_rx1droffset_type;
70
static int hf_lorawan_mac_command_down_rx_setup_req_rx2datarate_type;
71
static int hf_lorawan_mac_command_down_rx_setup_req_frequency_type;
72
static int hf_lorawan_mac_command_up_rx_setup_ans_type;
73
static int hf_lorawan_mac_command_up_rx_setup_ans_rx1droffset_type;
74
static int hf_lorawan_mac_command_up_rx_setup_ans_rx2datarate_type;
75
static int hf_lorawan_mac_command_up_rx_setup_ans_frequency_type;
76
static int hf_lorawan_mac_command_up_device_status_ans_battery_type;
77
static int hf_lorawan_mac_command_up_device_status_ans_margin_type;
78
static int hf_lorawan_mac_command_down_new_channel_req_index_type;
79
static int hf_lorawan_mac_command_down_new_channel_req_frequency_type;
80
static int hf_lorawan_mac_command_down_new_channel_req_drrange_max_type;
81
static int hf_lorawan_mac_command_down_new_channel_req_drrange_min_type;
82
static int hf_lorawan_mac_command_up_new_channel_ans_type;
83
static int hf_lorawan_mac_command_up_new_channel_ans_datarate_type;
84
static int hf_lorawan_mac_command_up_new_channel_ans_frequency_type;
85
static int hf_lorawan_mac_command_down_rx_timing_req_delay_type;
86
static int hf_lorawan_mac_command_up_di_channel_ans_type;
87
static int hf_lorawan_mac_command_up_ping_slot_info_req_type;
88
static int hf_lorawan_mac_command_up_ping_slot_channel_ans_type;
89
static int hf_lorawan_mac_command_up_beacon_freq_ans_type;
90
static int hf_lorawan_mac_command_down_tx_param_setup_req_type;
91
static int hf_lorawan_mac_command_down_di_channel_req_type;
92
static int hf_lorawan_mac_command_down_device_time_ans_type;
93
static int hf_lorawan_mac_command_down_ping_slot_channel_req_type;
94
static int hf_lorawan_mac_command_down_beacon_freq_req_type;
95
static int hf_lorawan_join_request_type;
96
static int hf_lorawan_join_request_joineui_type;
97
static int hf_lorawan_join_request_deveui_type;
98
static int hf_lorawan_join_request_devnonce_type;
99
static int hf_lorawan_join_accept_type;
100
static int hf_lorawan_join_accept_joinnonce_type;
101
static int hf_lorawan_join_accept_netid_type;
102
static int hf_lorawan_join_accept_devaddr_type;
103
static int hf_lorawan_join_accept_dlsettings_type;
104
static int hf_lorawan_join_accept_dlsettings_rx1droffset_type;
105
static int hf_lorawan_join_accept_dlsettings_rx2dr_type;
106
static int hf_lorawan_join_accept_rxdelay_type;
107
static int hf_lorawan_join_accept_cflist_type;
108
static int hf_lorawan_frame_header_type;
109
static int hf_lorawan_frame_header_address_type;
110
static int hf_lorawan_frame_header_frame_control_adr_type;
111
static int hf_lorawan_frame_header_frame_control_adrackreq_type;
112
static int hf_lorawan_frame_header_frame_control_ack_type;
113
static int hf_lorawan_frame_header_frame_control_fpending_type;
114
static int hf_lorawan_frame_header_frame_control_foptslen_type;
115
static int hf_lorawan_frame_header_frame_control_type;
116
static int hf_lorawan_frame_header_frame_counter_type;
117
static int hf_lorawan_frame_fport_type;
118
static int hf_lorawan_frame_payload_type;
119
static int hf_lorawan_frame_payload_decrypted_type;
120
static int hf_lorawan_mic_type;
121
static int hf_lorawan_mic_status_type;
122
static int hf_lorawan_beacon_rfu1_type;
123
static int hf_lorawan_beacon_time_type;
124
static int hf_lorawan_beacon_crc1_type;
125
static int hf_lorawan_beacon_crc1_status_type;
126
static int hf_lorawan_beacon_gwspecific_type;
127
static int hf_lorawan_beacon_gwspecific_infodesc_type;
128
static int hf_lorawan_beacon_gwspecific_lat_type;
129
static int hf_lorawan_beacon_gwspecific_lng_type;
130
static int hf_lorawan_beacon_rfu2_type;
131
static int hf_lorawan_beacon_crc2_type;
132
static int hf_lorawan_beacon_crc2_status_type;
133
134
static int * const hfx_lorawan_mac_command_link_check_ans[] = {
135
  &hf_lorawan_mac_command_up_link_adr_ans_txpower_type,
136
  &hf_lorawan_mac_command_up_link_adr_ans_datarate_type,
137
  &hf_lorawan_mac_command_up_link_adr_ans_channel_mask_type,
138
  NULL
139
};
140
static int * const hfx_lorawan_mac_command_link_adr_req_channel[] = {
141
  &hf_lorawan_mac_command_down_link_adr_req_channel1_type,
142
  &hf_lorawan_mac_command_down_link_adr_req_channel2_type,
143
  &hf_lorawan_mac_command_down_link_adr_req_channel3_type,
144
  &hf_lorawan_mac_command_down_link_adr_req_channel4_type,
145
  &hf_lorawan_mac_command_down_link_adr_req_channel5_type,
146
  &hf_lorawan_mac_command_down_link_adr_req_channel6_type,
147
  &hf_lorawan_mac_command_down_link_adr_req_channel7_type,
148
  &hf_lorawan_mac_command_down_link_adr_req_channel8_type,
149
  &hf_lorawan_mac_command_down_link_adr_req_channel9_type,
150
  &hf_lorawan_mac_command_down_link_adr_req_channel10_type,
151
  &hf_lorawan_mac_command_down_link_adr_req_channel11_type,
152
  &hf_lorawan_mac_command_down_link_adr_req_channel12_type,
153
  &hf_lorawan_mac_command_down_link_adr_req_channel13_type,
154
  &hf_lorawan_mac_command_down_link_adr_req_channel14_type,
155
  &hf_lorawan_mac_command_down_link_adr_req_channel15_type,
156
  &hf_lorawan_mac_command_down_link_adr_req_channel16_type,
157
  NULL
158
};
159
static int * const hfx_lorawan_mac_command_rx_setup_ans[] = {
160
  &hf_lorawan_mac_command_up_rx_setup_ans_rx1droffset_type,
161
  &hf_lorawan_mac_command_up_rx_setup_ans_rx2datarate_type,
162
  &hf_lorawan_mac_command_up_rx_setup_ans_frequency_type,
163
  NULL
164
};
165
static int * const hfx_lorawan_mac_command_new_channel_ans[] = {
166
  &hf_lorawan_mac_command_up_new_channel_ans_datarate_type,
167
  &hf_lorawan_mac_command_up_new_channel_ans_frequency_type,
168
  NULL
169
};
170
171
static int * const hfx_lorawan_frame_header_frame_control[] = {
172
  &hf_lorawan_frame_header_frame_control_adr_type,
173
  &hf_lorawan_frame_header_frame_control_adrackreq_type,
174
  &hf_lorawan_frame_header_frame_control_ack_type,
175
  &hf_lorawan_frame_header_frame_control_fpending_type,
176
  &hf_lorawan_frame_header_frame_control_foptslen_type,
177
  NULL
178
};
179
180
static int * const hfx_lorawan_join_accept_dlsettings[] = {
181
  &hf_lorawan_join_accept_dlsettings_rx1droffset_type,
182
  &hf_lorawan_join_accept_dlsettings_rx2dr_type,
183
  NULL
184
};
185
186
static int ett_lorawan;
187
static int ett_lorawan_mac_header;
188
static int ett_lorawan_mac_commands;
189
static int ett_lorawan_mac_command;
190
static int ett_lorawan_mac_command_link_check_ans;
191
static int ett_lorawan_mac_command_link_adr_req_channel;
192
static int ett_lorawan_mac_command_rx_setup_ans;
193
static int ett_lorawan_mac_command_new_channel_ans;
194
static int ett_lorawan_join_request;
195
static int ett_lorawan_join_accept;
196
static int ett_lorawan_join_accept_dlsettings;
197
static int ett_lorawan_frame_header;
198
static int ett_lorawan_frame_header_control;
199
static int ett_lorawan_frame_payload_decrypted;
200
static int ett_lorawan_beacon;
201
static int ett_lorawan_beacon_gwspecific;
202
203
14
#define LORAWAN_MAC_FTYPE_MASK            0xE0
204
0
#define LORAWAN_MAC_FTYPE(ftype)          (((ftype) & LORAWAN_MAC_FTYPE_MASK) >> 5)
205
206
0
#define LORAWAN_MAC_FTYPE_JOINREQUEST         0
207
0
#define LORAWAN_MAC_FTYPE_JOINACCEPT          1
208
0
#define LORAWAN_MAC_FTYPE_UNCONFIRMEDDATAUP       2
209
0
#define LORAWAN_MAC_FTYPE_UNCONFIRMEDDATADOWN       3
210
0
#define LORAWAN_MAC_FTYPE_CONFIRMEDDATAUP       4
211
0
#define LORAWAN_MAC_FTYPE_CONFIRMEDDATADOWN       5
212
0
#define LORAWAN_MAC_FTYPE_RFU           6
213
#define LORAWAN_MAC_FTYPE_PROPRIETARY         7
214
0
#define LORAWAN_MAC_BEACON            0xFFF0
215
216
14
#define LORAWAN_MAC_RFU_MASK            0x1C
217
218
14
#define LORAWAN_MAC_MAJOR_MASK            0x03
219
0
#define LORAWAN_MAC_MAJOR(major)          ((major) & LORAWAN_MAC_MAJOR_MASK)
220
221
0
#define LORAWAN_MAC_MAJOR_R1            0
222
223
0
#define LORAWAN_MAC_COMMAND_UP_LINK_CHECK_REQ       0x02
224
0
#define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS       0x03
225
0
#define LORAWAN_MAC_COMMAND_UP_DUTY_ANS         0x04
226
0
#define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS       0x05
227
0
#define LORAWAN_MAC_COMMAND_UP_DEV_STATUS_ANS       0x06
228
0
#define LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS        0x07
229
0
#define LORAWAN_MAC_COMMAND_UP_RX_TIMING_ANS        0x08
230
0
#define LORAWAN_MAC_COMMAND_UP_TX_PARAM_SETUP_ANS     0x09
231
0
#define LORAWAN_MAC_COMMAND_UP_DI_CHANNEL_ANS       0x0A
232
0
#define LORAWAN_MAC_COMMAND_UP_DEVICE_TIME_REQ        0x0D
233
0
#define LORAWAN_MAC_COMMAND_UP_PING_SLOT_INFO_REQ     0x10
234
0
#define LORAWAN_MAC_COMMAND_UP_PING_SLOT_CHANNEL_ANS      0x11
235
0
#define LORAWAN_MAC_COMMAND_UP_BEACON_TIMING_REQ      0x12
236
0
#define LORAWAN_MAC_COMMAND_UP_BEACON_FREQ_ANS        0x13
237
238
0
#define LORAWAN_MAC_COMMAND_DOWN_LINK_CHECK_ANS       0x02
239
0
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ       0x03
240
0
#define LORAWAN_MAC_COMMAND_DOWN_DUTY_REQ       0x04
241
0
#define LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_REQ       0x05
242
0
#define LORAWAN_MAC_COMMAND_DOWN_DEV_STATUS_REQ       0x06
243
0
#define LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ      0x07
244
0
#define LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ        0x08
245
0
#define LORAWAN_MAC_COMMAND_DOWN_TX_PARAM_SETUP_REQ     0x09
246
0
#define LORAWAN_MAC_COMMAND_DOWN_DI_CHANNEL_REQ       0x0A
247
0
#define LORAWAN_MAC_COMMAND_DOWN_DEVICE_TIME_ANS      0x0D
248
0
#define LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_INFO_ANS     0x10
249
0
#define LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_CHANNEL_REQ      0x11
250
0
#define LORAWAN_MAC_COMMAND_DOWN_BEACON_TIMING_ANS      0x12
251
0
#define LORAWAN_MAC_COMMAND_DOWN_BEACON_FREQ_REQ      0x13
252
253
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_DATARATE_MASK   0xF0
254
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_TXPOWER_MASK    0x0F
255
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_1_MASK    0x0001
256
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_2_MASK    0x0002
257
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_3_MASK    0x0004
258
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_4_MASK    0x0008
259
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_5_MASK    0x0010
260
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_6_MASK    0x0020
261
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_7_MASK    0x0040
262
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_8_MASK    0x0080
263
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_9_MASK    0x0100
264
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_10_MASK   0x0200
265
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_11_MASK   0x0400
266
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_12_MASK   0x0800
267
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_13_MASK   0x1000
268
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_14_MASK   0x2000
269
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_15_MASK   0x4000
270
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_16_MASK   0x8000
271
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHMASKCNTL_MASK   0x70
272
14
#define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_NBREP_MASK    0x0F
273
14
#define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_TXPOWER_MASK    0x04
274
14
#define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_DATARATE_MASK   0x02
275
14
#define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_CHANNEL_MASK    0x01
276
14
#define LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX1DROFFSET_MASK    0x70
277
14
#define LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX2DATARATE_MASK    0x0F
278
14
#define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_TXPOWER_MASK    0x04
279
14
#define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_DATARATE_MASK   0x02
280
14
#define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_CHANNEL_MASK    0x01
281
14
#define LORAWAN_MAC_COMMAND_UP_DEVICE_STATUS_ANS_MARGIN_MASK    0x3F
282
14
#define LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MAX_MASK 0xF0
283
14
#define LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MIN_MASK 0x0F
284
14
#define LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_DATARATE_MASK    0x02
285
14
#define LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_FREQUENCY_MASK   0x01
286
14
#define LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ_DELAY_MASK   0x0F
287
288
14
#define LORAWAN_JOIN_ACCEPT_RX1DROFFSET_MASK        0x70
289
14
#define LORAWAN_JOIN_ACCEPT_RX2DR_MASK          0x0F
290
291
14
#define LORAWAN_FRAME_FOPTSLEN_MASK         0x0F
292
293
0
#define LORAWAN_AES_BLOCK_LENGTH          16
294
0
#define LORAWAN_AES_PADDEDSIZE(length)          (LORAWAN_AES_BLOCK_LENGTH * ((length + LORAWAN_AES_BLOCK_LENGTH - 1) / LORAWAN_AES_BLOCK_LENGTH))
295
296
static expert_field ei_lorawan_missing_keys;
297
static expert_field ei_lorawan_decrypting_error;
298
static expert_field ei_lorawan_mic;
299
static expert_field ei_lorawan_length_error;
300
static expert_field ei_lorawan_mhdr_error;
301
302
static const value_string lorawan_ftypenames[] = {
303
  { LORAWAN_MAC_FTYPE_JOINREQUEST,    "Join Request" },
304
  { LORAWAN_MAC_FTYPE_JOINACCEPT,     "Join Accept" },
305
  { LORAWAN_MAC_FTYPE_UNCONFIRMEDDATAUP,    "Unconfirmed Data Up" },
306
  { LORAWAN_MAC_FTYPE_UNCONFIRMEDDATADOWN,  "Unconfirmed Data Down" },
307
  { LORAWAN_MAC_FTYPE_CONFIRMEDDATAUP,    "Confirmed Data Up" },
308
  { LORAWAN_MAC_FTYPE_CONFIRMEDDATADOWN,    "Confirmed Data Down" },
309
  { LORAWAN_MAC_FTYPE_RFU,      "RFU" },
310
  { LORAWAN_MAC_FTYPE_PROPRIETARY,    "Proprietary" },
311
  // TODO: having this here makes no sense.
312
  //  It's value doesn't fit into 3 bits, and is only ever looked up with a hardcoded key...
313
  { LORAWAN_MAC_BEACON,         "Class-B Beacon" },
314
  { 0, NULL }
315
};
316
317
static const value_string lorawan_majornames[] = {
318
  { LORAWAN_MAC_MAJOR_R1,       "LoRaWAN R1" },
319
  { 0, NULL }
320
};
321
322
static const value_string lorawan_mac_uplink_commandnames[] = {
323
  { LORAWAN_MAC_COMMAND_UP_LINK_CHECK_REQ,  "Network validation request" },
324
  { LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS,    "Data rate adjustment response" },
325
  { LORAWAN_MAC_COMMAND_UP_DUTY_ANS,    "Duty-cycle rate set response" },
326
  { LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS,    "Reception slots set response" },
327
  { LORAWAN_MAC_COMMAND_UP_DEV_STATUS_ANS,  "Status response" },
328
  { LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS, "Channel creation/modification response" },
329
  { LORAWAN_MAC_COMMAND_UP_RX_TIMING_ANS,   "Reception slots timing set response" },
330
  { LORAWAN_MAC_COMMAND_UP_TX_PARAM_SETUP_ANS,  "End-device transmit parameters response" },
331
  { LORAWAN_MAC_COMMAND_UP_DI_CHANNEL_ANS,  "Channel DI response" },
332
  { LORAWAN_MAC_COMMAND_UP_DEVICE_TIME_REQ, "End-device time request" },
333
  { LORAWAN_MAC_COMMAND_UP_PING_SLOT_INFO_REQ,  "Class-B ping-slot periodicity request" },
334
  { LORAWAN_MAC_COMMAND_UP_PING_SLOT_CHANNEL_ANS, "Class-B ping-slot frequency response" },
335
  { LORAWAN_MAC_COMMAND_UP_BEACON_TIMING_REQ, "Class-B beacon timing request" },
336
  { LORAWAN_MAC_COMMAND_UP_BEACON_FREQ_ANS, "Class-B beacon frequency response" },
337
  { 0, NULL }
338
};
339
340
static const value_string lorawan_mac_downlink_commandnames[] = {
341
  { LORAWAN_MAC_COMMAND_DOWN_LINK_CHECK_ANS,  "Network validation response" },
342
  { LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ,  "Data rate adjustment request" },
343
  { LORAWAN_MAC_COMMAND_DOWN_DUTY_REQ,    "Duty-cycle rate set request" },
344
  { LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_REQ,  "Reception slots set request" },
345
  { LORAWAN_MAC_COMMAND_DOWN_DEV_STATUS_REQ,  "Status request" },
346
  { LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ, "Channel creation/modification request" },
347
  { LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ, "Reception slots timing set request" },
348
  { LORAWAN_MAC_COMMAND_DOWN_TX_PARAM_SETUP_REQ,  "End-device transmit parameters request" },
349
  { LORAWAN_MAC_COMMAND_DOWN_DI_CHANNEL_REQ,  "Channel DI request" },
350
  { LORAWAN_MAC_COMMAND_DOWN_DEVICE_TIME_ANS, "End-device time response" },
351
  { LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_INFO_ANS,  "Class-B ping-slot periodicity response" },
352
  { LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_CHANNEL_REQ, "Class-B ping-slot frequency request" },
353
  { LORAWAN_MAC_COMMAND_DOWN_BEACON_TIMING_ANS, "Class-B beacon timing response" },
354
  { LORAWAN_MAC_COMMAND_DOWN_BEACON_FREQ_REQ, "Class-B beacon frequency request" },
355
  { 0, NULL }
356
};
357
358
359
typedef struct _root_keys_t {
360
  char    *deveui_string;
361
  char    *appkey_string;
362
  GByteArray  *deveui;
363
  GByteArray  *appkey;
364
} root_key_t;
365
366
typedef struct _session_keys_t {
367
  char    *dev_addr_string;
368
  char    *nwkskey_string;
369
  char    *appskey_string;
370
  uint32_t    dev_addr;
371
  GByteArray  *nwkskey;
372
  GByteArray  *appskey;
373
} session_key_t;
374
375
static root_key_t *root_keys;
376
static session_key_t *session_keys;
377
static unsigned root_num_keys;
378
static unsigned session_num_keys;
379
380
static void
381
byte_array_reverse(GByteArray *arr)
382
0
{
383
0
  for (unsigned i = 0; i < arr->len / 2; i++) {
384
0
    int8_t b = arr->data[i];
385
0
    arr->data[i] = arr->data[(arr->len - 1) - i];
386
0
    arr->data[(arr->len - 1) - i] = b;
387
0
  }
388
0
}
389
390
static bool
391
root_keys_update_cb(void *r, char **err)
392
0
{
393
0
  root_key_t *rec = (root_key_t *)r;
394
395
0
  if (rec->deveui_string == NULL) {
396
0
    *err = g_strdup("End-device identifier can't be empty");
397
0
    return false;
398
0
  }
399
0
  if (!rec->deveui) {
400
0
    rec->deveui = g_byte_array_new();
401
0
  }
402
0
  if (!hex_str_to_bytes(rec->deveui_string, rec->deveui, false)) {
403
0
    *err = g_strdup("End-device identifier must be hexadecimal");
404
0
    return false;
405
0
  }
406
0
  if (rec->deveui->len != 8) {
407
0
    *err = g_strdup("End-device identifier must be 8 bytes hexadecimal");
408
0
    return false;
409
0
  }
410
0
  byte_array_reverse(rec->deveui);
411
412
0
  if (rec->appkey_string == NULL) {
413
0
    *err = g_strdup("Application key can't be empty");
414
0
    return false;
415
0
  }
416
0
  if (!rec->appkey) {
417
0
    rec->appkey = g_byte_array_new();
418
0
  }
419
0
  if (!hex_str_to_bytes(rec->appkey_string, rec->appkey, false)) {
420
0
    *err = g_strdup("Application key must be hexadecimal");
421
0
    return false;
422
0
  }
423
0
  if (rec->appkey->len != 16) {
424
0
    *err = g_strdup("Application key must be 16 bytes hexadecimal");
425
0
    return false;
426
0
  }
427
428
0
  *err = NULL;
429
0
  return true;
430
0
}
431
432
static void *
433
root_keys_copy_cb(void *n, const void *o, size_t siz _U_)
434
0
{
435
0
  root_key_t *new_rec = (root_key_t*)n;
436
0
  const root_key_t *old_rec = (const root_key_t*)o;
437
438
0
  if (old_rec->deveui_string) {
439
0
    new_rec->deveui_string = g_strdup(old_rec->deveui_string);
440
0
    new_rec->deveui = g_byte_array_new();
441
0
    hex_str_to_bytes(new_rec->deveui_string, new_rec->deveui, false);
442
0
    byte_array_reverse(new_rec->deveui);
443
0
  } else {
444
0
    new_rec->deveui_string = NULL;
445
0
    new_rec->deveui = NULL;
446
0
  }
447
448
0
  if (old_rec->appkey_string) {
449
0
    new_rec->appkey_string = g_strdup(old_rec->appkey_string);
450
0
    new_rec->appkey = g_byte_array_new();
451
0
    hex_str_to_bytes(new_rec->appkey_string, new_rec->appkey, false);
452
0
  }
453
0
  else {
454
0
    new_rec->appkey_string = NULL;
455
0
    new_rec->appkey = NULL;
456
0
  }
457
458
0
  return new_rec;
459
0
}
460
461
static void
462
root_keys_free_cb(void *r)
463
0
{
464
0
  root_key_t *rec = (root_key_t*)r;
465
466
0
  g_free(rec->deveui_string);
467
0
  g_byte_array_free(rec->deveui, true);
468
0
  g_free(rec->appkey_string);
469
0
  g_byte_array_free(rec->appkey, true);
470
0
}
471
472
static bool
473
session_keys_update_cb(void *r, char **err)
474
0
{
475
0
  session_key_t *rec = (session_key_t*)r;
476
477
0
  if (rec->dev_addr_string == NULL) {
478
0
    *err = g_strdup("Device address can't be empty");
479
0
    return false;
480
0
  }
481
0
  GByteArray *addr = g_byte_array_new();
482
0
  if (!hex_str_to_bytes(rec->dev_addr_string, addr, false)) {
483
0
    g_byte_array_free(addr, true);
484
0
    *err = g_strdup("Device address must be hexadecimal");
485
0
    return false;
486
0
  }
487
0
  if (addr->len != 4) {
488
0
    g_byte_array_free(addr, true);
489
0
    *err = g_strdup("Device address must be 4 bytes hexadecimal");
490
0
    return false;
491
0
  }
492
0
  byte_array_reverse(addr);
493
0
  memcpy(&rec->dev_addr, addr->data, sizeof(rec->dev_addr));
494
0
  g_byte_array_free(addr, true);
495
496
0
  if (rec->nwkskey_string == NULL) {
497
0
    *err = g_strdup("Network session key can't be empty");
498
0
    return false;
499
0
  }
500
0
  if (!rec->nwkskey) {
501
0
    rec->nwkskey = g_byte_array_new();
502
0
  }
503
0
  if (!hex_str_to_bytes(rec->nwkskey_string, rec->nwkskey, false)) {
504
0
    *err = g_strdup("Network session key must be hexadecimal");
505
0
    return false;
506
0
  }
507
0
  if (rec->nwkskey->len != 16) {
508
0
    *err = g_strdup("Network session key must be 16 bytes hexadecimal");
509
0
    return false;
510
0
  }
511
512
0
  if (rec->appskey_string == NULL) {
513
0
    *err = g_strdup("Application session key can't be empty");
514
0
    return false;
515
0
  }
516
0
  if (!rec->appskey) {
517
0
    rec->appskey = g_byte_array_new();
518
0
  }
519
0
  if (!hex_str_to_bytes(rec->appskey_string, rec->appskey, false)) {
520
0
    *err = g_strdup("Application session key must be hexadecimal");
521
0
    return false;
522
0
  }
523
0
  if (rec->appskey->len != 16) {
524
0
    *err = g_strdup("Application session key must be 16 bytes hexadecimal");
525
0
    return false;
526
0
  }
527
528
0
  *err = NULL;
529
0
  return true;
530
0
}
531
532
static void *
533
session_keys_copy_cb(void *n, const void *o, size_t siz _U_)
534
0
{
535
0
  session_key_t *new_rec = (session_key_t*)n;
536
0
  const session_key_t *old_rec = (const session_key_t*)o;
537
538
0
  if (old_rec->dev_addr_string) {
539
0
    new_rec->dev_addr_string = g_strdup(old_rec->dev_addr_string);
540
0
    GByteArray *addr = g_byte_array_new();
541
0
    if (hex_str_to_bytes(new_rec->dev_addr_string, addr, false)) {
542
0
      if (addr->len == 4) {
543
0
        byte_array_reverse(addr);
544
0
        memcpy(&new_rec->dev_addr, addr->data, sizeof(new_rec->dev_addr));
545
0
      } else {
546
0
        new_rec->dev_addr = 0;
547
0
      }
548
0
    }
549
0
    g_byte_array_free(addr, true);
550
0
  } else {
551
0
    new_rec->dev_addr_string = NULL;
552
0
    new_rec->dev_addr = 0;
553
0
  }
554
555
0
  if (old_rec->nwkskey_string) {
556
0
    new_rec->nwkskey_string = g_strdup(old_rec->nwkskey_string);
557
0
    new_rec->nwkskey = g_byte_array_new();
558
0
    hex_str_to_bytes(new_rec->nwkskey_string, new_rec->nwkskey, false);
559
0
  } else {
560
0
    new_rec->nwkskey_string = NULL;
561
0
    new_rec->nwkskey = NULL;
562
0
  }
563
564
0
  if (old_rec->appskey_string) {
565
0
    new_rec->appskey_string = g_strdup(old_rec->appskey_string);
566
0
    new_rec->appskey = g_byte_array_new();
567
0
    hex_str_to_bytes(new_rec->appskey_string, new_rec->appskey, false);
568
0
  } else {
569
0
    new_rec->appskey_string = NULL;
570
0
    new_rec->appskey = NULL;
571
0
  }
572
573
0
  return new_rec;
574
0
}
575
576
static void
577
session_keys_free_cb(void *r)
578
0
{
579
0
  session_key_t *rec = (session_key_t*)r;
580
581
0
  g_free(rec->dev_addr_string);
582
0
  g_free(rec->nwkskey_string);
583
0
  g_byte_array_free(rec->nwkskey, true);
584
0
  g_free(rec->appskey_string);
585
0
  g_byte_array_free(rec->appskey, true);
586
0
}
587
588
UAT_CSTRING_CB_DEF(root_keys, deveui_string, root_key_t)
589
UAT_CSTRING_CB_DEF(root_keys, appkey_string, root_key_t)
590
UAT_CSTRING_CB_DEF(session_keys, dev_addr_string, session_key_t)
591
UAT_CSTRING_CB_DEF(session_keys, nwkskey_string, session_key_t)
592
UAT_CSTRING_CB_DEF(session_keys, appskey_string, session_key_t)
593
594
static session_key_t *
595
get_session_key(uint32_t dev_addr)
596
0
{
597
0
  unsigned i;
598
0
  for (i = 0; i < session_num_keys; i++) {
599
0
    if (session_keys[i].dev_addr == dev_addr) {
600
0
      return &session_keys[i];
601
0
    }
602
0
  }
603
0
  return NULL;
604
0
}
605
606
static root_key_t *
607
get_root_key(const uint8_t *deveui)
608
0
{
609
0
  unsigned i;
610
0
  for (i = 0; i < root_num_keys; i++) {
611
0
    if (root_keys[i].deveui != NULL && memcmp(root_keys[i].deveui->data, deveui, 8) == 0) {
612
0
      return &root_keys[i];
613
0
    }
614
0
  }
615
0
  return NULL;
616
0
}
617
618
static uint32_t
619
calculate_mic(const uint8_t *in, uint8_t length, const uint8_t *key)
620
0
{
621
  /*
622
   * cmac = aes128_cmac(key, in)
623
   * MIC = cmac[0..3]
624
   */
625
0
  gcry_mac_hd_t mac_hd;
626
0
  uint32_t mac;
627
0
  size_t read_digest_length = 4;
628
629
0
  if (gcry_mac_open(&mac_hd, GCRY_MAC_CMAC_AES, 0, NULL)) {
630
0
    return 0;
631
0
  }
632
0
  if (gcry_mac_setkey(mac_hd, key, 16)) {
633
0
    gcry_mac_close(mac_hd);
634
0
    return 0;
635
0
  }
636
  /* Pass in the message */
637
0
  if (gcry_mac_write(mac_hd, in, length)) {
638
0
    gcry_mac_close(mac_hd);
639
0
    return 0;
640
0
  }
641
  /* Read out the digest */
642
0
  if (gcry_mac_read(mac_hd, &mac, &read_digest_length)) {
643
0
    gcry_mac_close(mac_hd);
644
0
    return 0;
645
0
  }
646
  /* Now close the mac handle */
647
0
  gcry_mac_close(mac_hd);
648
0
  return mac;
649
0
}
650
651
static nstime_t
652
gps_to_utctime(const uint32_t gpstime)
653
0
{
654
0
  nstime_t utctime;
655
0
  utctime.secs = (uint64_t)gpstime;
656
0
  utctime.secs += 315964800; /* difference between Unix epoch and GPS epoch */
657
0
  utctime.secs -= 18; /* leap seconds valid after 2017-01-01 */
658
0
  utctime.nsecs = 0;
659
0
  return utctime;
660
0
}
661
662
static void
663
cf_coords_lat_custom(char *buffer, uint32_t value)
664
0
{
665
0
  int32_t coord_int = (value < 0x00800000) ? ((int32_t)value) : ((int32_t)value - 0x01000000);
666
0
  double coord_double = coord_int * 90. / 0x00800000;
667
668
0
  snprintf(buffer, ITEM_LABEL_LENGTH, "%.5f%c", fabs(coord_double), (coord_double >= 0) ? 'N' : 'S');
669
0
}
670
671
static void
672
cf_coords_lng_custom(char *buffer, uint32_t value)
673
0
{
674
0
  int32_t coord_int = (value < 0x00800000) ? ((int32_t)value) : ((int32_t)value - 0x01000000);
675
0
  double coord_double = coord_int * 180. / 0x00800000;
676
677
0
  snprintf(buffer, ITEM_LABEL_LENGTH, "%.5f%c", fabs(coord_double), (coord_double >= 0) ? 'E' : 'W');
678
0
}
679
680
static bool
681
aes128_lorawan_encrypt(const uint8_t *key, const uint8_t *data_in, uint8_t *data_out, int length)
682
0
{
683
0
  gcry_cipher_hd_t cipher;
684
0
  if (gcry_cipher_open(&cipher, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0)) {
685
0
    return false;
686
0
  }
687
0
  if (gcry_cipher_setkey(cipher, key, LORAWAN_AES_BLOCK_LENGTH)) {
688
0
    gcry_cipher_close(cipher);
689
0
    return false;
690
0
  }
691
0
  if (gcry_cipher_encrypt(cipher, data_out, length, data_in, length)) {
692
0
    gcry_cipher_close(cipher);
693
0
    return false;
694
0
  }
695
0
  gcry_cipher_close(cipher);
696
0
  return true;
697
0
}
698
699
/* length should be a multiple of 16, in should be padded to get to a multiple of 16 */
700
static bool
701
decrypt_lorawan_frame_payload(const uint8_t *in, int length, uint8_t *out, const uint8_t * key, uint8_t dir, uint32_t dev_addr, uint32_t fcnt)
702
0
{
703
0
  gcry_cipher_hd_t cipher;
704
0
  uint8_t iv[LORAWAN_AES_BLOCK_LENGTH] = {0x01, 0x00, 0x00, 0x00, 0x00, dir, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
705
0
  memcpy(iv + 6, &dev_addr, 4);
706
0
  memcpy(iv + 10, &fcnt, 4);
707
0
  if (gcry_cipher_open(&cipher, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
708
0
    return false;
709
0
  }
710
0
  if (gcry_cipher_setkey(cipher, key, LORAWAN_AES_BLOCK_LENGTH)) {
711
0
    gcry_cipher_close(cipher);
712
0
    return false;
713
0
  }
714
0
  if (gcry_cipher_setctr(cipher, iv, 16)) {
715
0
    gcry_cipher_close(cipher);
716
0
    return false;
717
0
  }
718
0
  if (gcry_cipher_encrypt(cipher, out, length, in, length)) {
719
0
    gcry_cipher_close(cipher);
720
0
    return false;
721
0
  }
722
0
  gcry_cipher_close(cipher);
723
0
  return true;
724
0
}
725
726
static int
727
dissect_lorawan_mac_commands(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, bool uplink)
728
0
{
729
0
  proto_item *ti, *tf;
730
0
  proto_tree *mac_command_tree, *field_tree;
731
0
  uint8_t command;
732
0
  int32_t current_offset = 0;
733
734
0
  ti = proto_tree_add_item(tree, hf_lorawan_mac_commands_type, tvb, 0, -1, ENC_NA);
735
0
  mac_command_tree = proto_item_add_subtree(ti, ett_lorawan_mac_commands);
736
737
0
  do {
738
0
    command = tvb_get_uint8(tvb, current_offset);
739
0
    if (uplink) {
740
0
      tf = proto_tree_add_item(mac_command_tree, hf_lorawan_mac_command_uplink_type, tvb, current_offset, 1, ENC_NA);
741
0
      current_offset++;
742
0
      proto_item_append_text(tf, " (%s)", val_to_str_const(command, lorawan_mac_uplink_commandnames, "RFU"));
743
0
      switch (command) {
744
0
        case LORAWAN_MAC_COMMAND_UP_LINK_CHECK_REQ:
745
0
        case LORAWAN_MAC_COMMAND_UP_DUTY_ANS:
746
0
        case LORAWAN_MAC_COMMAND_UP_RX_TIMING_ANS:
747
0
        case LORAWAN_MAC_COMMAND_UP_TX_PARAM_SETUP_ANS:
748
0
        case LORAWAN_MAC_COMMAND_UP_DEVICE_TIME_REQ:
749
0
        case LORAWAN_MAC_COMMAND_UP_BEACON_TIMING_REQ:
750
          /* No payload */
751
0
        break;
752
0
        case LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS:
753
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
754
0
          proto_tree_add_bitmask(field_tree, tvb, current_offset, hf_lorawan_mac_command_down_link_check_ans_type, ett_lorawan_mac_command_link_check_ans, hfx_lorawan_mac_command_link_check_ans, ENC_NA);
755
0
          current_offset++;
756
0
        break;
757
0
        case LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS:
758
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
759
0
          proto_tree_add_bitmask(field_tree, tvb, current_offset, hf_lorawan_mac_command_up_rx_setup_ans_type, ett_lorawan_mac_command_rx_setup_ans, hfx_lorawan_mac_command_rx_setup_ans, ENC_NA);
760
0
          current_offset++;
761
0
        break;
762
0
        case LORAWAN_MAC_COMMAND_UP_DEV_STATUS_ANS:
763
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
764
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_device_status_ans_battery_type, tvb, current_offset, 1, ENC_NA);
765
0
          current_offset++;
766
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_device_status_ans_margin_type, tvb, current_offset, 1, ENC_NA);
767
0
          current_offset++;
768
0
        break;
769
0
        case LORAWAN_MAC_COMMAND_UP_DI_CHANNEL_ANS:
770
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
771
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_di_channel_ans_type, tvb, current_offset, 1, ENC_NA);
772
0
          current_offset++;
773
0
        break;
774
0
        case LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS:
775
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
776
0
          proto_tree_add_bitmask(field_tree, tvb, current_offset, hf_lorawan_mac_command_up_new_channel_ans_type, ett_lorawan_mac_command_new_channel_ans, hfx_lorawan_mac_command_new_channel_ans, ENC_NA);
777
0
          current_offset++;
778
0
        break;
779
0
        case LORAWAN_MAC_COMMAND_UP_PING_SLOT_INFO_REQ:
780
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
781
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_ping_slot_info_req_type, tvb, current_offset, 1, ENC_NA);
782
0
          current_offset++;
783
0
        break;
784
0
        case LORAWAN_MAC_COMMAND_UP_PING_SLOT_CHANNEL_ANS:
785
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
786
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_ping_slot_channel_ans_type, tvb, current_offset, 1, ENC_NA);
787
0
          current_offset++;
788
0
        break;
789
0
        case LORAWAN_MAC_COMMAND_UP_BEACON_FREQ_ANS:
790
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
791
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_beacon_freq_ans_type, tvb, current_offset, 1, ENC_NA);
792
0
          current_offset++;
793
0
        break;
794
0
        default:
795
          /* End on unknown mac command because command lengths are not explicitly given */
796
0
          return tvb_captured_length(tvb);
797
0
        break;
798
0
      }
799
0
    } else {
800
0
      tf = proto_tree_add_item(mac_command_tree, hf_lorawan_mac_command_downlink_type, tvb, current_offset, 1, ENC_NA);
801
0
      current_offset++;
802
0
      proto_item_append_text(tf, " (%s)", val_to_str_const(command, lorawan_mac_downlink_commandnames, "RFU"));
803
0
      switch (command) {
804
0
        case LORAWAN_MAC_COMMAND_DOWN_LINK_CHECK_ANS:
805
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
806
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_check_ans_margin_type, tvb, current_offset, 1, ENC_NA);
807
0
          current_offset++;
808
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_check_ans_gwcnt_type, tvb, current_offset, 1, ENC_NA);
809
0
          current_offset++;
810
0
        break;
811
0
        case LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ:
812
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
813
          /* Region specific */
814
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_adr_req_datarate_type, tvb, current_offset, 1, ENC_NA);
815
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_adr_req_txpower_type, tvb, current_offset, 1, ENC_NA);
816
0
          current_offset++;
817
0
          proto_tree_add_bitmask(field_tree, tvb, current_offset, hf_lorawan_mac_command_down_link_adr_req_channel_type, ett_lorawan_mac_command_link_adr_req_channel, hfx_lorawan_mac_command_link_adr_req_channel, ENC_LITTLE_ENDIAN);
818
0
          current_offset += 2;
819
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_adr_req_channel_mask_control_type, tvb, current_offset, 1, ENC_NA);
820
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_adr_req_repetitions_type, tvb, current_offset, 1, ENC_NA);
821
0
          current_offset++;
822
0
        break;
823
0
        case LORAWAN_MAC_COMMAND_DOWN_DUTY_REQ:
824
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
825
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_dutycycle_type, tvb, current_offset, 1, ENC_NA);
826
0
          current_offset++;
827
0
        break;
828
0
        case LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_REQ:
829
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
830
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_rx_setup_req_rx1droffset_type, tvb, current_offset, 1, ENC_NA);
831
          /* Region specific */
832
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_rx_setup_req_rx2datarate_type, tvb, current_offset, 1, ENC_NA);
833
0
          current_offset++;
834
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_rx_setup_req_frequency_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
835
0
          current_offset += 3;
836
0
        break;
837
0
        case LORAWAN_MAC_COMMAND_DOWN_DEV_STATUS_REQ:
838
0
        case LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_INFO_ANS:
839
          /* No payload */
840
0
        break;
841
0
        case LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ:
842
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
843
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_new_channel_req_index_type, tvb, current_offset, 1, ENC_NA);
844
0
          current_offset++;
845
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_new_channel_req_frequency_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
846
0
          current_offset += 3;
847
          /* Region specific */
848
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_new_channel_req_drrange_max_type, tvb, current_offset, 1, ENC_NA);
849
          /* Region specific */
850
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_new_channel_req_drrange_min_type, tvb, current_offset, 1, ENC_NA);
851
0
          current_offset++;
852
0
        break;
853
0
        case LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ:
854
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
855
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_rx_timing_req_delay_type, tvb, current_offset, 1, ENC_NA);
856
0
          current_offset++;
857
0
        break;
858
0
        case LORAWAN_MAC_COMMAND_DOWN_TX_PARAM_SETUP_REQ:
859
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
860
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_tx_param_setup_req_type, tvb, current_offset, 1, ENC_NA);
861
0
          current_offset++;
862
0
        break;
863
0
        case LORAWAN_MAC_COMMAND_DOWN_DI_CHANNEL_REQ:
864
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
865
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_di_channel_req_type, tvb, current_offset, 4, ENC_NA);
866
0
          current_offset += 4;
867
0
        break;
868
0
        case LORAWAN_MAC_COMMAND_DOWN_DEVICE_TIME_ANS:
869
0
        case LORAWAN_MAC_COMMAND_DOWN_BEACON_TIMING_ANS:
870
          /* The time provided is the GPS time at the end of the uplink transmission. The
871
           * command has a 5-octet payload defined as follows:
872
           *   32-bit unsigned integer: seconds since epoch
873
           *   8-bit unsigned integer: fractional-second in 1/256s increments
874
           */
875
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
876
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_device_time_ans_type, tvb, current_offset, 5, ENC_NA);
877
0
          current_offset += 5;
878
0
        break;
879
0
        case LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_CHANNEL_REQ:
880
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
881
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_ping_slot_channel_req_type, tvb, current_offset, 4, ENC_NA);
882
0
          current_offset += 4;
883
0
        break;
884
0
        case LORAWAN_MAC_COMMAND_DOWN_BEACON_FREQ_REQ:
885
0
          field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
886
0
          proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_beacon_freq_req_type, tvb, current_offset, 3, ENC_NA);
887
0
          current_offset += 3;
888
0
        break;
889
0
        default:
890
          /* End on unknown mac command because command lengths are not explicitly given */
891
0
          return tvb_captured_length(tvb);
892
0
        break;
893
0
      }
894
0
    }
895
0
  } while (tvb_captured_length_remaining(tvb, current_offset));
896
0
  return tvb_captured_length(tvb);
897
0
}
898
899
static int
900
dissect_lorawan_beacon(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_)
901
0
{
902
0
  proto_item *ti;
903
0
  proto_tree *gwspecific_tree;
904
0
  int32_t current_offset = 0;
905
0
  unsigned length = tvb_reported_length(tvb);
906
0
  uint16_t calc_crc1, calc_crc2;
907
0
  nstime_t utctime;
908
909
0
  proto_tree_add_string(tree, hf_lorawan_msgtype_type, tvb, current_offset, 0, val_to_str_const(LORAWAN_MAC_BEACON, lorawan_ftypenames, "RFU"));
910
911
0
  if (length == 17) {
912
0
    calc_crc1 = crc16_r3_ccitt_tvb(tvb, 0, 6);
913
0
    calc_crc2 = crc16_r3_ccitt_tvb(tvb, 8, 7);
914
0
    proto_tree_add_item(tree, hf_lorawan_beacon_rfu1_type, tvb, current_offset, 2, ENC_NA);
915
0
    current_offset += 2;
916
0
  } else {
917
0
    calc_crc1 = crc16_r3_ccitt_tvb(tvb, 0, 7);
918
0
    calc_crc2 = crc16_r3_ccitt_tvb(tvb, 9, 8);
919
0
    proto_tree_add_item(tree, hf_lorawan_beacon_rfu1_type, tvb, current_offset, 3, ENC_NA);
920
0
    current_offset += 3;
921
0
  }
922
0
  utctime = gps_to_utctime(tvb_get_uint32(tvb, current_offset, ENC_LITTLE_ENDIAN));
923
0
  proto_tree_add_time(tree, hf_lorawan_beacon_time_type, tvb, current_offset, 4, &utctime);
924
0
  current_offset += 4;
925
0
  proto_tree_add_checksum(tree, tvb, current_offset, hf_lorawan_beacon_crc1_type, hf_lorawan_beacon_crc1_status_type, NULL, pinfo, calc_crc1, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY);
926
0
  current_offset += 2;
927
928
0
  ti = proto_tree_add_item(tree, hf_lorawan_beacon_gwspecific_type, tvb, current_offset, 7, ENC_NA);
929
0
  gwspecific_tree = proto_item_add_subtree(ti, ett_lorawan_beacon_gwspecific);
930
0
  proto_tree_add_item(gwspecific_tree, hf_lorawan_beacon_gwspecific_infodesc_type, tvb, current_offset, 1, ENC_NA);
931
0
  current_offset++;
932
0
  proto_tree_add_item(gwspecific_tree, hf_lorawan_beacon_gwspecific_lat_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
933
0
  current_offset += 3;
934
0
  proto_tree_add_item(gwspecific_tree, hf_lorawan_beacon_gwspecific_lng_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
935
0
  current_offset += 3;
936
937
0
  if (length == 19) {
938
0
    proto_tree_add_item(tree, hf_lorawan_beacon_rfu2_type, tvb, current_offset, 1, ENC_NA);
939
0
    current_offset++;
940
0
  }
941
0
  proto_tree_add_checksum(tree, tvb, current_offset, hf_lorawan_beacon_crc2_type, hf_lorawan_beacon_crc2_status_type, NULL, pinfo, calc_crc2, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY);
942
943
0
  return tvb_captured_length(tvb);
944
0
}
945
946
static int
947
dissect_lorawan_join_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_)
948
0
{
949
0
  proto_item *tf;
950
0
  proto_tree *field_tree;
951
0
  int32_t current_offset = 1;
952
953
0
  tf = proto_tree_add_item(tree, hf_lorawan_join_request_type, tvb, current_offset, 18, ENC_NA);
954
0
  field_tree = proto_item_add_subtree(tf, ett_lorawan_join_request);
955
0
  proto_tree_add_item(field_tree, hf_lorawan_join_request_joineui_type, tvb, current_offset, 8, ENC_LITTLE_ENDIAN);
956
0
  current_offset += 8;
957
0
  proto_tree_add_item(field_tree, hf_lorawan_join_request_deveui_type, tvb, current_offset, 8, ENC_LITTLE_ENDIAN);
958
0
  current_offset += 8;
959
0
  proto_tree_add_item(field_tree, hf_lorawan_join_request_devnonce_type, tvb, current_offset, 2, ENC_LITTLE_ENDIAN);
960
0
  current_offset += 2;
961
962
  /* MIC
963
   * cmac = aes128_cmac(AppKey, msg)
964
   * MIC = cmac[0..3]
965
   */
966
0
  root_key_t *root_key = get_root_key(tvb_get_ptr(tvb, current_offset - 10, 8));
967
0
  if (root_key) {
968
0
    proto_tree_add_checksum(tree, tvb, current_offset, hf_lorawan_mic_type, hf_lorawan_mic_status_type, &ei_lorawan_mic, pinfo,
969
0
      calculate_mic(tvb_get_ptr(tvb, 0, current_offset), current_offset, root_key->appkey->data), ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY);
970
0
  } else {
971
0
    proto_item *checksum_item = proto_tree_add_checksum(tree, tvb, current_offset, hf_lorawan_mic_type, hf_lorawan_mic_status_type, NULL, pinfo,
972
0
      0, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
973
0
    expert_add_info(pinfo, checksum_item, &ei_lorawan_missing_keys);
974
0
  }
975
976
0
  return tvb_captured_length(tvb);
977
0
}
978
979
static int
980
dissect_lorawan_join_accept(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_)
981
0
{
982
0
  proto_item *tf;
983
0
  proto_tree *field_tree;
984
0
  int32_t current_offset = 1;
985
0
  root_key_t *root_key = NULL;
986
987
0
  int length = tvb_captured_length_remaining(tvb, current_offset);
988
0
  tf = proto_tree_add_item(tree, hf_lorawan_join_accept_type, tvb, current_offset, 12, ENC_NA);
989
0
  field_tree = proto_item_add_subtree(tf, ett_lorawan_join_accept);
990
991
  /* Join-Accept may be either 16B or 32B long (including MIC) */
992
0
  if (length != 16 && length != 32) {
993
0
    expert_add_info(pinfo, field_tree, &ei_lorawan_length_error);
994
0
    proto_tree_add_item(tree, hf_lorawan_frame_payload_type, tvb, current_offset, tvb_captured_length_remaining(tvb, current_offset), ENC_NA);
995
0
    return tvb_captured_length(tvb);
996
0
  }
997
998
  /* Iterate through all available root keys for Join-Accept */
999
0
  uint8_t *decrypted_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, length);
1000
0
  uint8_t *mic_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, length - 4 + 1);
1001
0
  uint32_t mic_check;
1002
0
  for (unsigned key_idx = 0; key_idx < root_num_keys; key_idx++) {
1003
0
    if (aes128_lorawan_encrypt(root_keys[key_idx].appkey->data, tvb_get_ptr(tvb, current_offset, length), decrypted_buffer, length)) {
1004
0
      mic_buffer[0] = tvb_get_uint8(tvb, current_offset - 1); // unencrypted MHDR
1005
0
      memcpy(&mic_buffer[1], decrypted_buffer, length - 4); // decrypted Join-Accept
1006
0
      memcpy(&mic_check, &decrypted_buffer[length - 4], 4); // decrypted MIC
1007
1008
      // check for valid MIC of payload decrypted using current AppKey
1009
0
      if (calculate_mic(mic_buffer, length - 4 + 1, root_keys[key_idx].appkey->data) == mic_check) {
1010
0
        root_key = &root_keys[key_idx];
1011
0
        break;
1012
0
      }
1013
0
    }
1014
0
  }
1015
1016
0
  if (root_key) {
1017
0
    tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, decrypted_buffer, length, length);
1018
0
    add_new_data_source(pinfo, next_tvb, "Decrypted payload");
1019
0
    current_offset = 0;
1020
1021
0
    proto_tree_add_item(field_tree, hf_lorawan_join_accept_joinnonce_type, next_tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
1022
0
    current_offset += 3;
1023
0
    proto_tree_add_item(field_tree, hf_lorawan_join_accept_netid_type, next_tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
1024
0
    current_offset += 3;
1025
0
    proto_tree_add_item(field_tree, hf_lorawan_join_accept_devaddr_type, next_tvb, current_offset, 4, ENC_LITTLE_ENDIAN);
1026
0
    current_offset += 4;
1027
0
    proto_tree_add_bitmask(field_tree, next_tvb, current_offset, hf_lorawan_join_accept_dlsettings_type, ett_lorawan_join_accept_dlsettings, hfx_lorawan_join_accept_dlsettings, ENC_NA);
1028
0
    current_offset++;
1029
0
    proto_tree_add_item(field_tree, hf_lorawan_join_accept_rxdelay_type, next_tvb, current_offset, 1, ENC_NA);
1030
0
    current_offset++;
1031
0
    if (tvb_captured_length(next_tvb) - current_offset > 4) {
1032
0
      proto_tree_add_item(field_tree, hf_lorawan_join_accept_cflist_type, next_tvb, current_offset, 16, ENC_NA);
1033
0
      current_offset += 16;
1034
0
      proto_item_set_len(tf, proto_item_get_len(tf) + 16);
1035
0
    }
1036
1037
0
    proto_tree_add_checksum(tree, next_tvb, current_offset, hf_lorawan_mic_type, hf_lorawan_mic_status_type, &ei_lorawan_mic, pinfo, 0, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY | PROTO_CHECKSUM_ZERO);
1038
0
  } else {
1039
0
    expert_add_info(pinfo, field_tree, &ei_lorawan_missing_keys);
1040
0
    proto_tree_add_item(tree, hf_lorawan_frame_payload_type, tvb, current_offset, tvb_captured_length_remaining(tvb, current_offset), ENC_NA);
1041
0
  }
1042
1043
0
  return tvb_captured_length(tvb);
1044
0
}
1045
1046
static int
1047
dissect_lorawan_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, bool uplink)
1048
0
{
1049
0
  proto_item *ti = NULL, *tf;
1050
0
  proto_tree *field_tree;
1051
0
  int32_t current_offset = 1;
1052
0
  uint8_t fopts_length = (tvb_get_uint8(tvb, current_offset + 4) & LORAWAN_FRAME_FOPTSLEN_MASK);
1053
0
  uint8_t fport = 0;
1054
1055
  /* Frame header */
1056
0
  tf = proto_tree_add_item(tree, hf_lorawan_frame_header_type, tvb, current_offset, 7 + fopts_length, ENC_NA);
1057
0
  field_tree = proto_item_add_subtree(tf, ett_lorawan_frame_header);
1058
0
  proto_tree_add_item(field_tree, hf_lorawan_frame_header_address_type, tvb, current_offset, 4, ENC_LITTLE_ENDIAN);
1059
0
  uint32_t dev_address = tvb_get_uint32(tvb, current_offset, ENC_LITTLE_ENDIAN);
1060
0
  current_offset += 4;
1061
0
  proto_tree_add_bitmask(field_tree, tvb, current_offset, hf_lorawan_frame_header_frame_control_type, ett_lorawan_frame_header_control, hfx_lorawan_frame_header_frame_control, ENC_NA);
1062
0
  current_offset++;
1063
0
  proto_tree_add_item(field_tree, hf_lorawan_frame_header_frame_counter_type, tvb, current_offset, 2, ENC_LITTLE_ENDIAN);
1064
0
  uint32_t fcnt = tvb_get_uint16(tvb, current_offset, ENC_LITTLE_ENDIAN);
1065
0
  current_offset += 2;
1066
1067
  /*
1068
   * If fopts_length > 0 then MAC commands are present in fopts field and port cannot be 0
1069
   * If fopts_length == 0 then port can be any value
1070
   * If port == 0 then MAC commands are in frame payload
1071
   */
1072
1073
0
  if (fopts_length > 0) {
1074
0
    tvbuff_t *next_tvb = tvb_new_subset_length(tvb, current_offset, fopts_length);
1075
0
    current_offset += dissect_lorawan_mac_commands(next_tvb, pinfo, tree, uplink);
1076
0
  }
1077
1078
0
  if (tvb_captured_length_remaining(tvb, current_offset) > 4) {
1079
    /* FPort present */
1080
0
    proto_tree_add_item(tree, hf_lorawan_frame_fport_type, tvb, current_offset, 1, ENC_NA);
1081
0
    fport = tvb_get_uint8(tvb, current_offset);
1082
0
    current_offset++;
1083
0
  }
1084
1085
0
  if ((fopts_length > 0) && (fport == 0)) {
1086
    /* TODO?: error, not allowed */
1087
0
  }
1088
1089
0
  uint8_t frmpayload_length = tvb_captured_length_remaining(tvb, current_offset) - 4;
1090
0
  if (frmpayload_length > 0) {
1091
0
    ti = proto_tree_add_item(tree, hf_lorawan_frame_payload_type, tvb, current_offset, frmpayload_length, ENC_NA);
1092
0
  }
1093
1094
0
  session_key_t *session_key = get_session_key(dev_address);
1095
0
  if (session_key && frmpayload_length > 0) {
1096
0
    uint8_t padded_length = LORAWAN_AES_PADDEDSIZE(frmpayload_length);
1097
0
    uint8_t *decrypted_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, padded_length);
1098
0
    uint8_t *encrypted_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, padded_length);
1099
0
    tvb_memcpy(tvb, encrypted_buffer, current_offset, frmpayload_length);
1100
0
    if (decrypt_lorawan_frame_payload(encrypted_buffer, padded_length, decrypted_buffer, (fport == 0) ? session_key->nwkskey->data : session_key->appskey->data, !uplink, dev_address, fcnt)) {
1101
0
      tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, decrypted_buffer, frmpayload_length, frmpayload_length);
1102
0
      add_new_data_source(pinfo, next_tvb, "Decrypted payload");
1103
0
      proto_tree *frame_payload_decrypted_tree = proto_item_add_subtree(ti, ett_lorawan_frame_payload_decrypted);
1104
0
      if (fport == 0) {
1105
0
        current_offset += dissect_lorawan_mac_commands(next_tvb, pinfo, tree, uplink);
1106
0
      } else {
1107
        /*
1108
         * fport values 0x01 - 0xDF are application specific
1109
         * fport values 0xE0 - 0xFF are reserved for future extensions
1110
         */
1111
0
        proto_tree_add_bytes(frame_payload_decrypted_tree, hf_lorawan_frame_payload_decrypted_type, next_tvb, 0, frmpayload_length, decrypted_buffer);
1112
0
        current_offset += frmpayload_length;
1113
0
      }
1114
0
    } else {
1115
0
      proto_tree_add_expert_format(tree, pinfo, &ei_lorawan_decrypting_error, tvb, current_offset, 4, "Decrypting error");
1116
0
      current_offset += frmpayload_length;
1117
0
    }
1118
0
  } else {
1119
0
    current_offset += frmpayload_length;
1120
0
  }
1121
1122
  /*
1123
   * MIC
1124
   * cmac = aes128_cmac(NwkSKey, B0 | msg)
1125
   * MIC = cmac[0..3]
1126
   * B0 = 0x49 | 0x00 | 0x00 | 0x00 | 0x00 | dir | devAddr | fcntup/fcntdown | len(msg)
1127
   */
1128
0
  if (session_key) {
1129
0
    int frame_length = current_offset;
1130
0
    uint8_t *msg = (uint8_t *)wmem_alloc0(pinfo->pool, frame_length + 16);
1131
0
    msg[0] = 0x49;
1132
0
    msg[5] = uplink ? 0 : 1;
1133
0
    memcpy(msg + 6, &dev_address, 4);
1134
0
    memcpy(msg + 10, &fcnt, 4);
1135
0
    msg[15] = frame_length;
1136
0
    tvb_memcpy(tvb, msg + 16, 0, frame_length);
1137
0
    proto_tree_add_checksum(tree, tvb, current_offset, hf_lorawan_mic_type, hf_lorawan_mic_status_type, &ei_lorawan_mic, pinfo, calculate_mic(msg, frame_length + 16, session_key->nwkskey->data), ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY);
1138
0
  } else {
1139
0
    proto_item *checksum_item = proto_tree_add_checksum(tree, tvb, current_offset, hf_lorawan_mic_type, hf_lorawan_mic_status_type, NULL, pinfo,
1140
0
      0, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
1141
0
    expert_add_info(pinfo, checksum_item, &ei_lorawan_missing_keys);
1142
0
  }
1143
1144
0
  return tvb_captured_length(tvb);
1145
0
}
1146
1147
static int
1148
dissect_lorawan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
1149
0
{
1150
0
  proto_item *ti, *tf;
1151
0
  proto_tree *lorawan_tree, *field_tree;
1152
0
  int32_t current_offset = 0;
1153
1154
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "LoRaWAN");
1155
0
  col_clear(pinfo->cinfo,COL_INFO);
1156
0
  ti = proto_tree_add_item(tree, proto_lorawan, tvb, 0, -1, ENC_NA);
1157
0
  lorawan_tree = proto_item_add_subtree(ti, ett_lorawan);
1158
1159
  /* Detect and dissect Class-B beacon frames
1160
   * common mark: beacon is 17B or 19B long and begins with 2 bytes of zeroed RFU
1161
   */
1162
0
  uint16_t classb_rfu = tvb_get_uint16(tvb, current_offset, ENC_LITTLE_ENDIAN);
1163
0
  unsigned classb_length = tvb_reported_length(tvb);
1164
0
  if (classb_rfu == 0x0000 && (classb_length == 17 || classb_length == 19)) {
1165
0
    return dissect_lorawan_beacon(tvb, pinfo, lorawan_tree);
1166
0
  }
1167
1168
  /* MAC header */
1169
0
  uint8_t mac_ftype = LORAWAN_MAC_FTYPE(tvb_get_uint8(tvb, current_offset));
1170
0
  proto_tree_add_string(lorawan_tree, hf_lorawan_msgtype_type, tvb, current_offset, 0, val_to_str_const(mac_ftype, lorawan_ftypenames, "RFU"));
1171
0
  tf = proto_tree_add_item(lorawan_tree, hf_lorawan_mac_header_type, tvb, current_offset, 1, ENC_NA);
1172
0
  proto_item_append_text(tf, " (Message Type: %s, Major Version: %s)",
1173
0
               val_to_str_const(mac_ftype, lorawan_ftypenames, "RFU"),
1174
0
               val_to_str_const(LORAWAN_MAC_MAJOR(tvb_get_uint8(tvb, current_offset)), lorawan_majornames, "RFU"));
1175
1176
  /* Validate MHDR fields for LoRaWAN packet, do not dissect malformed packets */
1177
0
  if ((tvb_get_uint8(tvb, current_offset) & (LORAWAN_MAC_MAJOR_MASK | LORAWAN_MAC_RFU_MASK)) != LORAWAN_MAC_MAJOR_R1) {
1178
0
    expert_add_info(pinfo, lorawan_tree, &ei_lorawan_mhdr_error);
1179
0
    mac_ftype = LORAWAN_MAC_FTYPE_RFU;
1180
0
  }
1181
1182
0
  field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_header);
1183
0
  proto_tree_add_item(field_tree, hf_lorawan_mac_header_ftype_type, tvb, current_offset, 1, ENC_NA);
1184
0
  proto_tree_add_item(field_tree, hf_lorawan_mac_header_rfu_type, tvb, current_offset, 1, ENC_NA);
1185
0
  proto_tree_add_item(field_tree, hf_lorawan_mac_header_major_type, tvb, current_offset, 1, ENC_NA);
1186
0
  current_offset++;
1187
1188
0
  switch (mac_ftype) {
1189
0
    case LORAWAN_MAC_FTYPE_JOINREQUEST:
1190
0
      return dissect_lorawan_join_request(tvb, pinfo, lorawan_tree);
1191
1192
0
    case LORAWAN_MAC_FTYPE_JOINACCEPT:
1193
0
      return dissect_lorawan_join_accept(tvb, pinfo, lorawan_tree);
1194
1195
0
    case LORAWAN_MAC_FTYPE_UNCONFIRMEDDATAUP:
1196
0
    case LORAWAN_MAC_FTYPE_CONFIRMEDDATAUP:
1197
0
      return dissect_lorawan_data(tvb, pinfo, lorawan_tree, true /*uplink*/);
1198
1199
0
    case LORAWAN_MAC_FTYPE_UNCONFIRMEDDATADOWN:
1200
0
    case LORAWAN_MAC_FTYPE_CONFIRMEDDATADOWN:
1201
0
      return dissect_lorawan_data(tvb, pinfo, lorawan_tree, false /*downlink*/);
1202
1203
0
    default: /* LORAWAN_MAC_FTYPE_RFU or LORAWAN_MAC_FTYPE_PROPRIETARY */
1204
0
      proto_tree_add_item(lorawan_tree, hf_lorawan_frame_payload_type, tvb, current_offset, tvb_captured_length_remaining(tvb, current_offset), ENC_NA);
1205
0
      return tvb_captured_length(tvb);
1206
0
  }
1207
0
}
1208
1209
void
1210
proto_register_lorawan(void)
1211
14
{
1212
14
  static hf_register_info hf[] = {
1213
14
  { &hf_lorawan_msgtype_type,
1214
14
    { "Message type", "lorawan.msgtype",
1215
14
    FT_STRING, BASE_NONE,
1216
14
    NULL, 0x0,
1217
14
    NULL, HFILL }
1218
14
  },
1219
14
  { &hf_lorawan_mac_header_type,
1220
14
    { "MAC Header", "lorawan.mhdr",
1221
14
    FT_NONE, BASE_NONE,
1222
14
    NULL, 0x0,
1223
14
    "[MHDR] MAC Header", HFILL }
1224
14
  },
1225
14
  { &hf_lorawan_mac_header_ftype_type,
1226
14
    { "Message Type", "lorawan.mhdr.ftype",
1227
14
    FT_UINT8, BASE_DEC,
1228
14
    VALS(lorawan_ftypenames), LORAWAN_MAC_FTYPE_MASK,
1229
14
    "[FType] Message Type", HFILL }
1230
14
  },
1231
14
  { &hf_lorawan_mac_header_rfu_type,
1232
14
    { "RFU", "lorawan.mhdr.rfu",
1233
14
    FT_UINT8, BASE_DEC,
1234
14
    NULL, LORAWAN_MAC_RFU_MASK,
1235
14
    "[RFU]", HFILL }
1236
14
  },
1237
14
  { &hf_lorawan_mac_header_major_type,
1238
14
    { "Major Version", "lorawan.mhdr.major",
1239
14
    FT_UINT8, BASE_DEC,
1240
14
    VALS(lorawan_majornames), LORAWAN_MAC_MAJOR_MASK,
1241
14
    "[Major] Major Version", HFILL }
1242
14
  },
1243
14
  { &hf_lorawan_mac_commands_type,
1244
14
    { "MAC Commands", "lorawan.mac_commands",
1245
14
    FT_NONE, BASE_NONE,
1246
14
    NULL, 0x0,
1247
14
    NULL, HFILL }
1248
14
  },
1249
14
  { &hf_lorawan_mac_command_uplink_type,
1250
14
    { "Uplink Command", "lorawan.mac_command_uplink",
1251
14
    FT_UINT8, BASE_DEC,
1252
14
    VALS(lorawan_mac_uplink_commandnames), 0x0,
1253
14
    NULL, HFILL }
1254
14
  },
1255
14
  { &hf_lorawan_mac_command_downlink_type,
1256
14
    { "Downlink Command", "lorawan.mac_command_downlink",
1257
14
    FT_UINT8, BASE_DEC,
1258
14
    VALS(lorawan_mac_downlink_commandnames), 0x0,
1259
14
    NULL, HFILL }
1260
14
  },
1261
14
  { &hf_lorawan_mac_command_down_link_check_ans_type,
1262
14
    { "Link Check Answer", "lorawan.link_check_answer",
1263
14
    FT_UINT8, BASE_HEX,
1264
14
    NULL, 0x0,
1265
14
    NULL, HFILL }
1266
14
  },
1267
14
  { &hf_lorawan_mac_command_down_link_check_ans_margin_type,
1268
14
    { "Demodulation Margin", "lorawan.link_check_answer.margin",
1269
14
    FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
1270
14
    UNS(&units_decibels), 0x0,
1271
14
    NULL, HFILL }
1272
14
  },
1273
14
  { &hf_lorawan_mac_command_down_link_check_ans_gwcnt_type,
1274
14
    { "Gateway Count", "lorawan.link_check_answer.gwcnt",
1275
14
    FT_UINT8, BASE_DEC,
1276
14
    NULL, 0x0,
1277
14
    NULL, HFILL }
1278
14
  },
1279
14
  { &hf_lorawan_mac_command_down_link_adr_req_datarate_type,
1280
14
    { "Data Rate", "lorawan.link_adr_request.datarate",
1281
14
    FT_UINT8, BASE_DEC,
1282
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_DATARATE_MASK,
1283
14
    NULL, HFILL }
1284
14
  },
1285
14
  { &hf_lorawan_mac_command_down_link_adr_req_txpower_type,
1286
14
    { "Transmit Power", "lorawan.link_adr_request.txpower",
1287
14
    FT_UINT8, BASE_DEC,
1288
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_TXPOWER_MASK,
1289
14
    NULL, HFILL }
1290
14
  },
1291
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel_type,
1292
14
    { "Channel 1", "lorawan.link_adr_request.channel",
1293
14
    FT_UINT16, BASE_HEX,
1294
14
    NULL, 0x0,
1295
14
    NULL, HFILL }
1296
14
  },
1297
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel1_type,
1298
14
    { "Channel 1", "lorawan.link_adr_request.channel.1",
1299
14
    FT_BOOLEAN, 16,
1300
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_1_MASK,
1301
14
    NULL, HFILL }
1302
14
  },
1303
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel2_type,
1304
14
    { "Channel 2", "lorawan.link_adr_request.channel.2",
1305
14
    FT_BOOLEAN, 16,
1306
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_2_MASK,
1307
14
    NULL, HFILL }
1308
14
  },
1309
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel3_type,
1310
14
    { "Channel 3", "lorawan.link_adr_request.channel.3",
1311
14
    FT_BOOLEAN, 16,
1312
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_3_MASK,
1313
14
    NULL, HFILL }
1314
14
  },
1315
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel4_type,
1316
14
    { "Channel 4", "lorawan.link_adr_request.channel.4",
1317
14
    FT_BOOLEAN, 16,
1318
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_4_MASK,
1319
14
    NULL, HFILL }
1320
14
  },
1321
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel5_type,
1322
14
    { "Channel 5", "lorawan.link_adr_request.channel.5",
1323
14
    FT_BOOLEAN, 16,
1324
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_5_MASK,
1325
14
    NULL, HFILL }
1326
14
  },
1327
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel6_type,
1328
14
    { "Channel 6", "lorawan.link_adr_request.channel.6",
1329
14
    FT_BOOLEAN, 16,
1330
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_6_MASK,
1331
14
    NULL, HFILL }
1332
14
  },
1333
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel7_type,
1334
14
    { "Channel 7", "lorawan.link_adr_request.channel.7",
1335
14
    FT_BOOLEAN, 16,
1336
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_7_MASK,
1337
14
    NULL, HFILL }
1338
14
  },
1339
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel8_type,
1340
14
    { "Channel 8", "lorawan.link_adr_request.channel.8",
1341
14
    FT_BOOLEAN, 16,
1342
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_8_MASK,
1343
14
    NULL, HFILL }
1344
14
  },
1345
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel9_type,
1346
14
    { "Channel 9", "lorawan.link_adr_request.channel.9",
1347
14
    FT_BOOLEAN, 16,
1348
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_9_MASK,
1349
14
    NULL, HFILL }
1350
14
  },
1351
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel10_type,
1352
14
    { "Channel 10", "lorawan.link_adr_request.channel.10",
1353
14
    FT_BOOLEAN, 16,
1354
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_10_MASK,
1355
14
    NULL, HFILL }
1356
14
  },
1357
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel11_type,
1358
14
    { "Channel 11", "lorawan.link_adr_request.channel.11",
1359
14
    FT_BOOLEAN, 16,
1360
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_11_MASK,
1361
14
    NULL, HFILL }
1362
14
  },
1363
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel12_type,
1364
14
    { "Channel 12", "lorawan.link_adr_request.channel.12",
1365
14
    FT_BOOLEAN, 16,
1366
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_12_MASK,
1367
14
    NULL, HFILL }
1368
14
  },
1369
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel13_type,
1370
14
    { "Channel 13", "lorawan.link_adr_request.channel.13",
1371
14
    FT_BOOLEAN, 16,
1372
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_13_MASK,
1373
14
    NULL, HFILL }
1374
14
  },
1375
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel14_type,
1376
14
    { "Channel 14", "lorawan.link_adr_request.channel.14",
1377
14
    FT_BOOLEAN, 16,
1378
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_14_MASK,
1379
14
    NULL, HFILL }
1380
14
  },
1381
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel15_type,
1382
14
    { "Channel 15", "lorawan.link_adr_request.channel.15",
1383
14
    FT_BOOLEAN, 16,
1384
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_15_MASK,
1385
14
    NULL, HFILL }
1386
14
  },
1387
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel16_type,
1388
14
    { "Channel 16", "lorawan.link_adr_request.channel.16",
1389
14
    FT_BOOLEAN, 16,
1390
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_16_MASK,
1391
14
    NULL, HFILL }
1392
14
  },
1393
14
  { &hf_lorawan_mac_command_down_link_adr_req_channel_mask_control_type,
1394
14
    { "Channel Mask Control", "lorawan.link_adr_request.chmaskctl",
1395
14
    FT_UINT8, BASE_DEC,
1396
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHMASKCNTL_MASK,
1397
14
    NULL, HFILL }
1398
14
  },
1399
14
  { &hf_lorawan_mac_command_down_link_adr_req_repetitions_type,
1400
14
    { "Number Of Repetitions", "lorawan.link_adr_request.nbrep",
1401
14
    FT_UINT8, BASE_DEC,
1402
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_NBREP_MASK,
1403
14
    NULL, HFILL }
1404
14
  },
1405
14
  { &hf_lorawan_mac_command_up_link_adr_ans_txpower_type,
1406
14
    { "Transmit Power Ack", "lorawan.link_adr_response.txpower",
1407
14
    FT_BOOLEAN, 8,
1408
14
    NULL, LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_TXPOWER_MASK,
1409
14
    NULL, HFILL }
1410
14
  },
1411
14
  { &hf_lorawan_mac_command_up_link_adr_ans_datarate_type,
1412
14
    { "Data Rate Ack", "lorawan.link_adr_response.datarate",
1413
14
    FT_BOOLEAN, 8,
1414
14
    NULL, LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_DATARATE_MASK,
1415
14
    NULL, HFILL }
1416
14
  },
1417
14
  { &hf_lorawan_mac_command_up_link_adr_ans_channel_mask_type,
1418
14
    { "Channel Mask Ack", "lorawan.link_adr_response.channelmask",
1419
14
    FT_BOOLEAN, 8,
1420
14
    NULL, LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_CHANNEL_MASK,
1421
14
    NULL, HFILL }
1422
14
  },
1423
14
  { &hf_lorawan_mac_command_down_dutycycle_type,
1424
14
    { "Duty Cycle", "lorawan.dutycycle_request.dutycycle",
1425
14
    FT_UINT8, BASE_DEC,
1426
14
    NULL, 0x0,
1427
14
    NULL, HFILL }
1428
14
  },
1429
14
  { &hf_lorawan_mac_command_down_rx_setup_req_rx1droffset_type,
1430
14
    { "RX1 Datarate Offset", "lorawan.rx_setup_request.rx1droffset",
1431
14
    FT_UINT8, BASE_DEC,
1432
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX1DROFFSET_MASK,
1433
14
    NULL, HFILL }
1434
14
  },
1435
14
  { &hf_lorawan_mac_command_down_rx_setup_req_rx2datarate_type,
1436
14
    { "RX2 Datarate", "lorawan.rx_setup_request.rx2datarate",
1437
14
    FT_UINT8, BASE_DEC,
1438
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX2DATARATE_MASK,
1439
14
    NULL, HFILL }
1440
14
  },
1441
14
  { &hf_lorawan_mac_command_down_rx_setup_req_frequency_type,
1442
14
    { "Frequency", "lorawan.rx_setup_request.frequency",
1443
14
    FT_UINT24, BASE_DEC|BASE_UNIT_STRING,
1444
14
    UNS(&units_hz), 0x0,
1445
14
    NULL, HFILL }
1446
14
  },
1447
14
  { &hf_lorawan_mac_command_up_rx_setup_ans_type,
1448
14
    { "RX Setup Response", "lorawan.rx_setup_response",
1449
14
    FT_UINT8, BASE_HEX,
1450
14
    NULL, 0x0,
1451
14
    NULL, HFILL }
1452
14
  },
1453
14
  { &hf_lorawan_mac_command_up_rx_setup_ans_rx1droffset_type,
1454
14
    { "RX1 Datarate Offset Ack", "lorawan.rx_setup_response.rx1droffset",
1455
14
    FT_BOOLEAN, 8,
1456
14
    NULL, LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_TXPOWER_MASK,
1457
14
    NULL, HFILL }
1458
14
  },
1459
14
  { &hf_lorawan_mac_command_up_rx_setup_ans_rx2datarate_type,
1460
14
    { "RX2 Datarate Ack", "lorawan.rx_setup_response.rx2datarate",
1461
14
    FT_BOOLEAN, 8,
1462
14
    NULL, LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_DATARATE_MASK,
1463
14
    NULL, HFILL }
1464
14
  },
1465
14
  { &hf_lorawan_mac_command_up_rx_setup_ans_frequency_type,
1466
14
    { "Frequency Ack", "lorawan.rx_setup_response.frequency",
1467
14
    FT_BOOLEAN, 8,
1468
14
    NULL, LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_CHANNEL_MASK,
1469
14
    NULL, HFILL }
1470
14
  },
1471
14
  { &hf_lorawan_mac_command_up_device_status_ans_battery_type,
1472
14
    { "Battery Level", "lorawan.device_status_response.battery",
1473
14
    FT_UINT8, BASE_DEC,
1474
14
    NULL, 0x0,
1475
14
    NULL, HFILL }
1476
14
  },
1477
14
  { &hf_lorawan_mac_command_up_device_status_ans_margin_type,
1478
14
    { "Margin", "lorawan.device_status_response.margin",
1479
14
    FT_UINT8, BASE_DEC,
1480
14
    NULL, LORAWAN_MAC_COMMAND_UP_DEVICE_STATUS_ANS_MARGIN_MASK,
1481
14
    NULL, HFILL }
1482
14
  },
1483
14
  { &hf_lorawan_mac_command_down_new_channel_req_index_type,
1484
14
    { "Index", "lorawan.new_channel_request.index",
1485
14
    FT_UINT8, BASE_DEC,
1486
14
    NULL, 0x0,
1487
14
    NULL, HFILL }
1488
14
  },
1489
14
  { &hf_lorawan_mac_command_down_new_channel_req_frequency_type,
1490
14
    { "Frequency", "lorawan.new_channel_request.frequency",
1491
14
    FT_UINT24, BASE_DEC|BASE_UNIT_STRING,
1492
14
    UNS(&units_hz), 0x0,
1493
14
    NULL, HFILL }
1494
14
  },
1495
14
  { &hf_lorawan_mac_command_down_new_channel_req_drrange_max_type,
1496
14
    { "Maximum Data Rate", "lorawan.new_channel_request.drrange_max",
1497
14
    FT_UINT8, BASE_DEC,
1498
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MAX_MASK,
1499
14
    NULL, HFILL }
1500
14
  },
1501
14
  { &hf_lorawan_mac_command_down_new_channel_req_drrange_min_type,
1502
14
    { "Minimum Data Rate", "lorawan.new_channel_request.drrange_min",
1503
14
    FT_UINT8, BASE_DEC,
1504
14
    NULL, LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MIN_MASK,
1505
14
    NULL, HFILL }
1506
14
  },
1507
14
  { &hf_lorawan_mac_command_up_new_channel_ans_type,
1508
14
    { "New Channel Response", "lorawan.new_channel_response",
1509
14
    FT_UINT8, BASE_HEX,
1510
14
    NULL, 0x0,
1511
14
    NULL, HFILL }
1512
14
  },
1513
14
  { &hf_lorawan_mac_command_up_new_channel_ans_datarate_type,
1514
14
    { "Datarate Ack", "lorawan.new_channel_response.datarate",
1515
14
    FT_BOOLEAN, 8,
1516
14
    NULL, LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_DATARATE_MASK,
1517
14
    NULL, HFILL }
1518
14
  },
1519
14
  { &hf_lorawan_mac_command_up_new_channel_ans_frequency_type,
1520
14
    { "Frequency Ack", "lorawan.new_channel_response.frequency",
1521
14
    FT_BOOLEAN, 8,
1522
14
    NULL, LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_FREQUENCY_MASK,
1523
14
    NULL, HFILL }
1524
14
  },
1525
14
  { &hf_lorawan_mac_command_down_rx_timing_req_delay_type,
1526
14
    { "Delay", "lorawan.rx_timing_request.delay",
1527
14
    FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
1528
14
    UNS(&units_seconds), LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ_DELAY_MASK,
1529
14
    NULL, HFILL }
1530
14
  },
1531
14
  { &hf_lorawan_mac_command_up_di_channel_ans_type,
1532
14
    { "Status", "lorawan.di_channel_response",
1533
14
    FT_BYTES, BASE_NONE,
1534
14
    NULL, 0x0,
1535
14
    NULL, HFILL }
1536
14
  },
1537
14
  { &hf_lorawan_mac_command_up_ping_slot_info_req_type,
1538
14
    { "PingSlotParam", "lorawan.ping_slot_info_request",
1539
14
    FT_BYTES, BASE_NONE,
1540
14
    NULL, 0x0,
1541
14
    NULL, HFILL }
1542
14
  },
1543
14
  { &hf_lorawan_mac_command_up_ping_slot_channel_ans_type,
1544
14
    { "Status", "lorawan.ping_slot_channel_response",
1545
14
    FT_BYTES, BASE_NONE,
1546
14
    NULL, 0x0,
1547
14
    NULL, HFILL }
1548
14
  },
1549
14
  { &hf_lorawan_mac_command_up_beacon_freq_ans_type,
1550
14
    { "Status", "lorawan.beacon_freq_response",
1551
14
    FT_BYTES, BASE_NONE,
1552
14
    NULL, 0x0,
1553
14
    NULL, HFILL }
1554
14
  },
1555
14
  { &hf_lorawan_mac_command_down_tx_param_setup_req_type,
1556
14
    { "DwellTime, EIRP", "lorawan.tx_param_setup_request",
1557
14
    FT_BYTES, BASE_NONE,
1558
14
    NULL, 0x0,
1559
14
    NULL, HFILL }
1560
14
  },
1561
14
  { &hf_lorawan_mac_command_down_di_channel_req_type,
1562
14
    { "ChIndex, Frequency", "lorawan.di_channel_request",
1563
14
    FT_BYTES, BASE_NONE,
1564
14
    NULL, 0x0,
1565
14
    NULL, HFILL }
1566
14
  },
1567
14
  { &hf_lorawan_mac_command_down_device_time_ans_type,
1568
14
    { "DeviceTimeAns", "lorawan.device_time_response",
1569
14
    FT_BYTES, BASE_NONE,
1570
14
    NULL, 0x0,
1571
14
    NULL, HFILL }
1572
14
  },
1573
14
  { &hf_lorawan_mac_command_down_ping_slot_channel_req_type,
1574
14
    { "Frequency, DR", "lorawan.ping_slot_channel_request",
1575
14
    FT_BYTES, BASE_NONE,
1576
14
    NULL, 0x0,
1577
14
    NULL, HFILL }
1578
14
  },
1579
14
  { &hf_lorawan_mac_command_down_beacon_freq_req_type,
1580
14
    { "Frequency", "lorawan.beacon_freq_request",
1581
14
    FT_BYTES, BASE_NONE,
1582
14
    NULL, 0x0,
1583
14
    NULL, HFILL }
1584
14
  },
1585
14
  { &hf_lorawan_join_request_type,
1586
14
    { "Join Request", "lorawan.join_request",
1587
14
    FT_NONE, BASE_NONE,
1588
14
    NULL, 0x0,
1589
14
    NULL, HFILL }
1590
14
  },
1591
14
  { &hf_lorawan_join_request_joineui_type,
1592
14
    { "Join-Server identifier", "lorawan.join_request.joineui",
1593
14
    FT_EUI64, BASE_NONE,
1594
14
    NULL, 0x0,
1595
14
    "[JoinEUI] Join-Server identifier", HFILL }
1596
14
  },
1597
14
  { &hf_lorawan_join_request_deveui_type,
1598
14
    { "End-device identifier", "lorawan.join_request.deveui",
1599
14
    FT_EUI64, BASE_NONE,
1600
14
    NULL, 0x0,
1601
14
    "[DevEUI] End-device identifier", HFILL }
1602
14
  },
1603
14
  { &hf_lorawan_join_request_devnonce_type,
1604
14
    { "Device Nonce", "lorawan.join_request.devnonce",
1605
14
    FT_UINT16, BASE_DEC,
1606
14
    NULL, 0x0,
1607
14
    "[DevNonce] Device Nonce", HFILL }
1608
14
  },
1609
14
  { &hf_lorawan_join_accept_type,
1610
14
    { "Join Accept", "lorawan.join_accept",
1611
14
    FT_NONE, BASE_NONE,
1612
14
    NULL, 0x0,
1613
14
    NULL, HFILL }
1614
14
  },
1615
14
  { &hf_lorawan_join_accept_joinnonce_type,
1616
14
    { "Join-Server nonce", "lorawan.join_accept.joinnonce",
1617
14
    FT_UINT24, BASE_HEX,
1618
14
    NULL, 0x0,
1619
14
    "[JoinNonce] Join-Server nonce", HFILL }
1620
14
  },
1621
14
  { &hf_lorawan_join_accept_netid_type,
1622
14
    { "Network identifier", "lorawan.join_accept.netid",
1623
14
    FT_UINT24, BASE_HEX,
1624
14
    NULL, 0x0,
1625
14
    "[NetID] Network identifier", HFILL }
1626
14
  },
1627
14
  { &hf_lorawan_join_accept_devaddr_type,
1628
14
    { "Device Address", "lorawan.join_accept.devaddr",
1629
14
    FT_UINT32, BASE_HEX,
1630
14
    NULL, 0x0,
1631
14
    "[DevAddr] Device Address", HFILL }
1632
14
  },
1633
14
  { &hf_lorawan_join_accept_dlsettings_type,
1634
14
    { "Downlink configuration", "lorawan.join_accept.dlsettings",
1635
14
    FT_UINT8, BASE_HEX,
1636
14
    NULL, 0x0,
1637
14
    "[DLSettings] Downlink configuration", HFILL }
1638
14
  },
1639
14
  { &hf_lorawan_join_accept_dlsettings_rx1droffset_type,
1640
14
    { "RX1 Data rate offset", "lorawan.join_accept.dlsettings.rx1droffset",
1641
14
    FT_UINT8, BASE_DEC,
1642
14
    NULL, LORAWAN_JOIN_ACCEPT_RX1DROFFSET_MASK,
1643
14
    "[RX1DROffset] RX1 Data rate offset", HFILL }
1644
14
  },
1645
14
  { &hf_lorawan_join_accept_dlsettings_rx2dr_type,
1646
14
    { "RX2 Data rate", "lorawan.join_accept.dlsettings.rx2datarate",
1647
14
    FT_UINT8, BASE_DEC,
1648
14
    NULL, LORAWAN_JOIN_ACCEPT_RX2DR_MASK,
1649
14
    "[RX2DataRate] RX2 Data rate", HFILL }
1650
14
  },
1651
14
  { &hf_lorawan_join_accept_rxdelay_type,
1652
14
    { "Delay between TX and RX", "lorawan.join_accept.rxdelay",
1653
14
    FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
1654
14
    UNS(&units_seconds), 0x0,
1655
14
    "[RXDelay] Delay between TX and RX", HFILL }
1656
14
  },
1657
14
  { &hf_lorawan_join_accept_cflist_type,
1658
14
    { "List of network parameters", "lorawan.join_accept.cflist",
1659
14
    FT_BYTES, BASE_NONE,
1660
14
    NULL, 0x0,
1661
14
    "[CFList] List of network parameters", HFILL }
1662
14
  },
1663
14
  { &hf_lorawan_frame_header_type,
1664
14
    { "Frame Header", "lorawan.fhdr",
1665
14
    FT_NONE, BASE_NONE,
1666
14
    NULL, 0x0,
1667
14
    "[FHDR] Frame Header", HFILL }
1668
14
  },
1669
14
  { &hf_lorawan_frame_header_address_type,
1670
14
    { "Device Address", "lorawan.fhdr.devaddr",
1671
14
    FT_UINT32, BASE_HEX,
1672
14
    NULL, 0x0,
1673
14
    "[DevAddr] Device Address", HFILL }
1674
14
  },
1675
14
  { &hf_lorawan_frame_header_frame_control_type,
1676
14
    { "Frame Control", "lorawan.fhdr.fctrl",
1677
14
    FT_UINT8, BASE_HEX,
1678
14
    NULL, 0x0,
1679
14
    "[FCtrl] Frame Control", HFILL }
1680
14
  },
1681
14
  { &hf_lorawan_frame_header_frame_control_adr_type,
1682
14
    { "Adaptive Data Rate", "lorawan.fhdr.fctrl.adr",
1683
14
    FT_BOOLEAN, 8,
1684
14
    NULL, 0x80,
1685
14
    "[ADR] Adaptive Data Rate", HFILL }
1686
14
  },
1687
14
  { &hf_lorawan_frame_header_frame_control_adrackreq_type,
1688
14
    { "ADR Acknowledgement Request", "lorawan.fhdr.fctrl.adrackreq",
1689
14
    FT_BOOLEAN, 8,
1690
14
    NULL, 0x40,
1691
14
    "[ADRACKReq] ADR Acknowledgement Request(up) / RFU(down)", HFILL}
1692
14
  },
1693
14
  { &hf_lorawan_frame_header_frame_control_ack_type,
1694
14
    { "Acknowledgement", "lorawan.fhdr.fctrl.ack",
1695
14
    FT_BOOLEAN, 8,
1696
14
    NULL, 0x20,
1697
14
    "[ACK] Acknowledgement", HFILL }
1698
14
  },
1699
14
  { &hf_lorawan_frame_header_frame_control_fpending_type,
1700
14
    { "ClassB Enabled / Frame Pending", "lorawan.fhdr.fctrl.fpending",
1701
14
    FT_BOOLEAN, 8,
1702
14
    NULL, 0x10,
1703
14
    "[FPending/ClassB] ClassB Enabled (up) / Frame Pending (down)", HFILL }
1704
14
  },
1705
14
  { &hf_lorawan_frame_header_frame_control_foptslen_type,
1706
14
    { "Frame Options Length", "lorawan.fhdr.fctrl.foptslen",
1707
14
    FT_UINT8, BASE_DEC,
1708
14
    NULL, LORAWAN_FRAME_FOPTSLEN_MASK,
1709
14
    "[FOptsLen] Frame Options Length", HFILL }
1710
14
  },
1711
14
  { &hf_lorawan_frame_header_frame_counter_type,
1712
14
    { "Frame Counter", "lorawan.fhdr.fcnt",
1713
14
    FT_UINT16, BASE_DEC,
1714
14
    NULL, 0x0,
1715
14
    "[FCnt] Frame Counter", HFILL }
1716
14
  },
1717
14
  { &hf_lorawan_frame_fport_type,
1718
14
    { "Port", "lorawan.fport",
1719
14
    FT_UINT8, BASE_HEX,
1720
14
    NULL, 0x0,
1721
14
    "[FPort] Port", HFILL }
1722
14
  },
1723
14
  { &hf_lorawan_frame_payload_type,
1724
14
    { "Frame Payload", "lorawan.frmpayload",
1725
14
    FT_BYTES, BASE_NONE,
1726
14
    NULL, 0x0,
1727
14
    "[FRMPayload] Frame Payload", HFILL }
1728
14
  },
1729
14
  { &hf_lorawan_frame_payload_decrypted_type,
1730
14
    { "Decrypted Frame Payload", "lorawan.frmpayload_decrypted",
1731
14
    FT_BYTES, BASE_NONE,
1732
14
    NULL, 0x0,
1733
14
    NULL, HFILL }
1734
14
  },
1735
14
  { &hf_lorawan_mic_type,
1736
14
    { "Message Integrity Code", "lorawan.mic",
1737
14
    FT_UINT32, BASE_HEX,
1738
14
    NULL, 0x0,
1739
14
    "[MIC] Message Integrity Code", HFILL }
1740
14
  },
1741
14
  { &hf_lorawan_mic_status_type,
1742
14
    { "Message Integrity Code Status", "lorawan.mic.status",
1743
14
    FT_UINT8, BASE_NONE,
1744
14
    VALS(proto_checksum_vals), 0x0,
1745
14
    NULL, HFILL }
1746
14
  },
1747
14
  { &hf_lorawan_beacon_rfu1_type,
1748
14
    { "RFU", "lorawan.beacon.rfu1",
1749
14
    FT_BYTES, BASE_NONE,
1750
14
    NULL, 0x0,
1751
14
    "[RFU]", HFILL}
1752
14
  },
1753
14
  { &hf_lorawan_beacon_time_type,
1754
14
    { "Timestamp", "lorawan.beacon.time",
1755
14
    FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1756
14
    NULL, 0x0,
1757
14
    "[Time] Timestamp", HFILL}
1758
14
  },
1759
14
  { &hf_lorawan_beacon_crc1_type,
1760
14
    { "CRC of Timestamp", "lorawan.beacon.crc1",
1761
14
    FT_UINT16, BASE_HEX,
1762
14
    NULL, 0x0,
1763
14
    "[CRC] CRC of Timestamp", HFILL }
1764
14
  },
1765
14
  { &hf_lorawan_beacon_crc1_status_type,
1766
14
    { "Beacon Timestamp CRC Status", "lorawan.beacon.crc1.status",
1767
14
    FT_UINT8, BASE_NONE,
1768
14
    VALS(proto_checksum_vals), 0x0,
1769
14
    NULL, HFILL }
1770
14
  },
1771
14
  { &hf_lorawan_beacon_gwspecific_type,
1772
14
    { "Gateway specific part", "lorawan.beacon.gwspecific",
1773
14
    FT_NONE, BASE_NONE,
1774
14
    NULL, 0x0,
1775
14
    "[GwSpecific] Gateway specific part", HFILL }
1776
14
  },
1777
14
  { &hf_lorawan_beacon_gwspecific_infodesc_type,
1778
14
    { "Information descriptor", "lorawan.beacon.gwspecific.infodesc",
1779
14
    FT_UINT8, BASE_DEC,
1780
14
    NULL, 0x0,
1781
14
    "[InfoDesc] Information descriptor", HFILL }
1782
14
  },
1783
14
  { &hf_lorawan_beacon_gwspecific_lat_type,
1784
14
    { "GPS latitude", "lorawan.beacon.gwspecific.lat",
1785
14
    FT_UINT24, BASE_CUSTOM,
1786
14
    CF_FUNC(cf_coords_lat_custom), 0x0,
1787
14
    "[Lat] GPS latitude", HFILL }
1788
14
  },
1789
14
  { &hf_lorawan_beacon_gwspecific_lng_type,
1790
14
    { "GPS longitude", "lorawan.beacon.gwspecific.lng",
1791
14
    FT_UINT24, BASE_CUSTOM,
1792
14
    CF_FUNC(cf_coords_lng_custom), 0x0,
1793
14
    "[Lng] GPS longitude", HFILL }
1794
14
  },
1795
14
  { &hf_lorawan_beacon_rfu2_type,
1796
14
    { "RFU", "lorawan.beacon.rfu2",
1797
14
    FT_BYTES, BASE_NONE,
1798
14
    NULL, 0x0,
1799
14
    "[RFU]", HFILL }
1800
14
  },
1801
14
  { &hf_lorawan_beacon_crc2_type,
1802
14
    { "CRC of GwSpecific", "lorawan.beacon.crc2",
1803
14
    FT_UINT16, BASE_HEX,
1804
14
    NULL, 0x0,
1805
14
    "[CRC] CRC of GwSpecific", HFILL }
1806
14
  },
1807
14
  { &hf_lorawan_beacon_crc2_status_type,
1808
14
    { "Beacon GwSpecific CRC Status", "lorawan.beacon.crc2.status",
1809
14
    FT_UINT8, BASE_NONE,
1810
14
    VALS(proto_checksum_vals), 0x0,
1811
14
    NULL, HFILL }
1812
14
  },
1813
14
  };
1814
1815
  /* Setup protocol subtree array */
1816
14
  static int *ett[] = {
1817
14
    &ett_lorawan,
1818
14
    &ett_lorawan_mac_header,
1819
14
    &ett_lorawan_mac_commands,
1820
14
    &ett_lorawan_mac_command,
1821
14
    &ett_lorawan_mac_command_link_check_ans,
1822
14
    &ett_lorawan_mac_command_link_adr_req_channel,
1823
14
    &ett_lorawan_mac_command_rx_setup_ans,
1824
14
    &ett_lorawan_mac_command_new_channel_ans,
1825
14
    &ett_lorawan_join_request,
1826
14
    &ett_lorawan_join_accept,
1827
14
    &ett_lorawan_join_accept_dlsettings,
1828
14
    &ett_lorawan_frame_header,
1829
14
    &ett_lorawan_frame_header_control,
1830
14
    &ett_lorawan_frame_payload_decrypted,
1831
14
    &ett_lorawan_beacon,
1832
14
    &ett_lorawan_beacon_gwspecific,
1833
14
  };
1834
1835
14
  static ei_register_info ei[] = {
1836
14
    { &ei_lorawan_missing_keys, { "lorawan.missing_keys", PI_PROTOCOL, PI_NOTE, "Missing encryption keys", EXPFILL }},
1837
14
    { &ei_lorawan_decrypting_error, { "lorawan.decrypting_error", PI_DECRYPTION, PI_ERROR, "Error decrypting payload", EXPFILL }},
1838
14
    { &ei_lorawan_mic, { "lorawan.mic_bad.expert", PI_CHECKSUM, PI_WARN, "Bad MIC", EXPFILL }},
1839
14
    { &ei_lorawan_length_error, { "lorawan.length_error", PI_MALFORMED, PI_ERROR, "Field length is not according to LoRaWAN standard", EXPFILL }},
1840
14
    { &ei_lorawan_mhdr_error, { "lorawan.mhdr_error", PI_MALFORMED, PI_ERROR, "LoRaWAN MAC Header malformed", EXPFILL }},
1841
14
  };
1842
1843
14
  expert_module_t* expert_lorawan;
1844
1845
14
  proto_lorawan = proto_register_protocol (
1846
14
    "LoRaWAN Protocol", /* name */
1847
14
    "LoRaWAN",    /* short name */
1848
14
    "lorawan"   /* abbrev */
1849
14
  );
1850
1851
14
  lorawan_handle = register_dissector("lorawan", dissect_lorawan, proto_lorawan);
1852
1853
14
  proto_register_field_array(proto_lorawan, hf, array_length(hf));
1854
14
  proto_register_subtree_array(ett, array_length(ett));
1855
1856
14
  expert_lorawan = expert_register_protocol(proto_lorawan);
1857
14
  expert_register_field_array(expert_lorawan, ei, array_length(ei));
1858
1859
14
  static uat_field_t root_keys_uat_fields[] = {
1860
14
    UAT_FLD_CSTRING(root_keys, deveui_string, "DevEUI", "LoRaWAN End-device Identifier"),
1861
14
    UAT_FLD_CSTRING(root_keys, appkey_string, "AppKey", "LoRaWAN Application Key"),
1862
14
    UAT_END_FIELDS
1863
14
  };
1864
14
  static uat_field_t session_keys_uat_fields[] = {
1865
14
    UAT_FLD_CSTRING(session_keys, dev_addr_string, "DevAddr", "LoRaWAN Device Address"),
1866
14
    UAT_FLD_CSTRING(session_keys, nwkskey_string, "NwkSKey", "LoRaWAN Network Session Key"),
1867
14
    UAT_FLD_CSTRING(session_keys, appskey_string, "AppSKey", "LoRaWAN Application Session Key"),
1868
14
    UAT_END_FIELDS
1869
14
  };
1870
1871
14
  uat_t *root_keys_uat = uat_new("LoRaWAN Root Keys",
1872
14
    sizeof(root_key_t),
1873
14
    "root_keys_lorawan",
1874
14
    true,
1875
14
    &root_keys,
1876
14
    &root_num_keys,
1877
14
    UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
1878
14
    NULL,
1879
14
    root_keys_copy_cb,
1880
14
    root_keys_update_cb,
1881
14
    root_keys_free_cb,
1882
14
    NULL,
1883
14
    NULL,
1884
14
    root_keys_uat_fields
1885
14
  );
1886
14
  uat_t *session_keys_uat = uat_new("LoRaWAN Session Keys",
1887
14
    sizeof(session_key_t),
1888
14
    "session_keys_lorawan",
1889
14
    true,
1890
14
    &session_keys,
1891
14
    &session_num_keys,
1892
14
    UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
1893
14
    NULL,
1894
14
    session_keys_copy_cb,
1895
14
    session_keys_update_cb,
1896
14
    session_keys_free_cb,
1897
14
    NULL,
1898
14
    NULL,
1899
14
    session_keys_uat_fields
1900
14
  );
1901
1902
14
  module_t *lorawan_module;
1903
14
  lorawan_module = prefs_register_protocol(proto_lorawan, NULL);
1904
14
  prefs_register_uat_preference(lorawan_module, "root_keys_lorawan", "LoRaWAN Root Keys",
1905
14
    "A table to define root encryption keys for LoRaWAN devices, used for Join Request/Accept",
1906
14
    root_keys_uat);
1907
14
  prefs_register_uat_preference(lorawan_module, "session_keys_lorawan", "LoRaWAN Session Keys",
1908
14
    "A table to define session encryption keys for LoRaWAN devices, used for Data Up/Down",
1909
14
    session_keys_uat);
1910
14
}
1911
1912
void
1913
proto_reg_handoff_lorawan(void)
1914
14
{
1915
14
  dissector_add_uint("loratap.syncword", 0x34, lorawan_handle);
1916
14
  dissector_add_for_decode_as("udp.port", lorawan_handle);
1917
14
}
1918
1919
/*
1920
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1921
 *
1922
 * Local variables:
1923
 * c-basic-offset: 8
1924
 * tab-width: 8
1925
 * indent-tabs-mode: t
1926
 * End:
1927
 *
1928
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1929
 * :indentSize=8:tabSize=8:noTabs=false:
1930
 */