Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-lorawan.c
blobee06de5fc7c6bc09d74cf21b6a53fd94b3df1364
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>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
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>
24 #include <wsutil/array.h>
25 #include <wsutil/wsgcrypt.h>
27 void proto_reg_handoff_lorawan(void);
28 void proto_register_lorawan(void);
30 static dissector_handle_t lorawan_handle;
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;
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
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
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
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
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
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
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;
203 #define LORAWAN_MAC_FTYPE_MASK 0xE0
204 #define LORAWAN_MAC_FTYPE(ftype) (((ftype) & LORAWAN_MAC_FTYPE_MASK) >> 5)
206 #define LORAWAN_MAC_FTYPE_JOINREQUEST 0
207 #define LORAWAN_MAC_FTYPE_JOINACCEPT 1
208 #define LORAWAN_MAC_FTYPE_UNCONFIRMEDDATAUP 2
209 #define LORAWAN_MAC_FTYPE_UNCONFIRMEDDATADOWN 3
210 #define LORAWAN_MAC_FTYPE_CONFIRMEDDATAUP 4
211 #define LORAWAN_MAC_FTYPE_CONFIRMEDDATADOWN 5
212 #define LORAWAN_MAC_FTYPE_RFU 6
213 #define LORAWAN_MAC_FTYPE_PROPRIETARY 7
214 #define LORAWAN_MAC_BEACON 0xFFF0
216 #define LORAWAN_MAC_RFU_MASK 0x1C
218 #define LORAWAN_MAC_MAJOR_MASK 0x03
219 #define LORAWAN_MAC_MAJOR(major) ((major) & LORAWAN_MAC_MAJOR_MASK)
221 #define LORAWAN_MAC_MAJOR_R1 0
223 #define LORAWAN_MAC_COMMAND_UP_LINK_CHECK_REQ 0x02
224 #define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS 0x03
225 #define LORAWAN_MAC_COMMAND_UP_DUTY_ANS 0x04
226 #define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS 0x05
227 #define LORAWAN_MAC_COMMAND_UP_DEV_STATUS_ANS 0x06
228 #define LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS 0x07
229 #define LORAWAN_MAC_COMMAND_UP_RX_TIMING_ANS 0x08
230 #define LORAWAN_MAC_COMMAND_UP_TX_PARAM_SETUP_ANS 0x09
231 #define LORAWAN_MAC_COMMAND_UP_DI_CHANNEL_ANS 0x0A
232 #define LORAWAN_MAC_COMMAND_UP_DEVICE_TIME_REQ 0x0D
233 #define LORAWAN_MAC_COMMAND_UP_PING_SLOT_INFO_REQ 0x10
234 #define LORAWAN_MAC_COMMAND_UP_PING_SLOT_CHANNEL_ANS 0x11
235 #define LORAWAN_MAC_COMMAND_UP_BEACON_TIMING_REQ 0x12
236 #define LORAWAN_MAC_COMMAND_UP_BEACON_FREQ_ANS 0x13
238 #define LORAWAN_MAC_COMMAND_DOWN_LINK_CHECK_ANS 0x02
239 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ 0x03
240 #define LORAWAN_MAC_COMMAND_DOWN_DUTY_REQ 0x04
241 #define LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_REQ 0x05
242 #define LORAWAN_MAC_COMMAND_DOWN_DEV_STATUS_REQ 0x06
243 #define LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ 0x07
244 #define LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ 0x08
245 #define LORAWAN_MAC_COMMAND_DOWN_TX_PARAM_SETUP_REQ 0x09
246 #define LORAWAN_MAC_COMMAND_DOWN_DI_CHANNEL_REQ 0x0A
247 #define LORAWAN_MAC_COMMAND_DOWN_DEVICE_TIME_ANS 0x0D
248 #define LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_INFO_ANS 0x10
249 #define LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_CHANNEL_REQ 0x11
250 #define LORAWAN_MAC_COMMAND_DOWN_BEACON_TIMING_ANS 0x12
251 #define LORAWAN_MAC_COMMAND_DOWN_BEACON_FREQ_REQ 0x13
253 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_DATARATE_MASK 0xF0
254 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_TXPOWER_MASK 0x0F
255 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_1_MASK 0x0001
256 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_2_MASK 0x0002
257 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_3_MASK 0x0004
258 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_4_MASK 0x0008
259 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_5_MASK 0x0010
260 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_6_MASK 0x0020
261 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_7_MASK 0x0040
262 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_8_MASK 0x0080
263 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_9_MASK 0x0100
264 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_10_MASK 0x0200
265 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_11_MASK 0x0400
266 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_12_MASK 0x0800
267 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_13_MASK 0x1000
268 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_14_MASK 0x2000
269 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_15_MASK 0x4000
270 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_16_MASK 0x8000
271 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHMASKCNTL_MASK 0x70
272 #define LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_NBREP_MASK 0x0F
273 #define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_TXPOWER_MASK 0x04
274 #define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_DATARATE_MASK 0x02
275 #define LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_CHANNEL_MASK 0x01
276 #define LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX1DROFFSET_MASK 0x70
277 #define LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX2DATARATE_MASK 0x0F
278 #define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_TXPOWER_MASK 0x04
279 #define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_DATARATE_MASK 0x02
280 #define LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_CHANNEL_MASK 0x01
281 #define LORAWAN_MAC_COMMAND_UP_DEVICE_STATUS_ANS_MARGIN_MASK 0x3F
282 #define LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MAX_MASK 0xF0
283 #define LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MIN_MASK 0x0F
284 #define LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_DATARATE_MASK 0x02
285 #define LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_FREQUENCY_MASK 0x01
286 #define LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ_DELAY_MASK 0x0F
288 #define LORAWAN_JOIN_ACCEPT_RX1DROFFSET_MASK 0x70
289 #define LORAWAN_JOIN_ACCEPT_RX2DR_MASK 0x0F
291 #define LORAWAN_FRAME_FOPTSLEN_MASK 0x0F
293 #define LORAWAN_AES_BLOCK_LENGTH 16
294 #define LORAWAN_AES_PADDEDSIZE(length) (LORAWAN_AES_BLOCK_LENGTH * ((length + LORAWAN_AES_BLOCK_LENGTH - 1) / LORAWAN_AES_BLOCK_LENGTH))
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;
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 }
317 static const value_string lorawan_majornames[] = {
318 { LORAWAN_MAC_MAJOR_R1, "LoRaWAN R1" },
319 { 0, NULL }
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 }
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 }
359 typedef struct _root_keys_t {
360 char *deveui_string;
361 char *appkey_string;
362 GByteArray *deveui;
363 GByteArray *appkey;
364 } root_key_t;
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;
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;
380 static void
381 byte_array_reverse(GByteArray *arr)
383 for (unsigned i = 0; i < arr->len / 2; i++) {
384 int8_t b = arr->data[i];
385 arr->data[i] = arr->data[(arr->len - 1) - i];
386 arr->data[(arr->len - 1) - i] = b;
390 static bool
391 root_keys_update_cb(void *r, char **err)
393 root_key_t *rec = (root_key_t *)r;
395 if (rec->deveui_string == NULL) {
396 *err = g_strdup("End-device identifier can't be empty");
397 return false;
399 if (!rec->deveui) {
400 rec->deveui = g_byte_array_new();
402 if (!hex_str_to_bytes(rec->deveui_string, rec->deveui, false)) {
403 *err = g_strdup("End-device identifier must be hexadecimal");
404 return false;
406 if (rec->deveui->len != 8) {
407 *err = g_strdup("End-device identifier must be 8 bytes hexadecimal");
408 return false;
410 byte_array_reverse(rec->deveui);
412 if (rec->appkey_string == NULL) {
413 *err = g_strdup("Application key can't be empty");
414 return false;
416 if (!rec->appkey) {
417 rec->appkey = g_byte_array_new();
419 if (!hex_str_to_bytes(rec->appkey_string, rec->appkey, false)) {
420 *err = g_strdup("Application key must be hexadecimal");
421 return false;
423 if (rec->appkey->len != 16) {
424 *err = g_strdup("Application key must be 16 bytes hexadecimal");
425 return false;
428 *err = NULL;
429 return true;
432 static void *
433 root_keys_copy_cb(void *n, const void *o, size_t siz _U_)
435 root_key_t *new_rec = (root_key_t*)n;
436 const root_key_t *old_rec = (const root_key_t*)o;
438 if (old_rec->deveui_string) {
439 new_rec->deveui_string = g_strdup(old_rec->deveui_string);
440 new_rec->deveui = g_byte_array_new();
441 hex_str_to_bytes(new_rec->deveui_string, new_rec->deveui, false);
442 byte_array_reverse(new_rec->deveui);
443 } else {
444 new_rec->deveui_string = NULL;
445 new_rec->deveui = NULL;
448 if (old_rec->appkey_string) {
449 new_rec->appkey_string = g_strdup(old_rec->appkey_string);
450 new_rec->appkey = g_byte_array_new();
451 hex_str_to_bytes(new_rec->appkey_string, new_rec->appkey, false);
453 else {
454 new_rec->appkey_string = NULL;
455 new_rec->appkey = NULL;
458 return new_rec;
461 static void
462 root_keys_free_cb(void *r)
464 root_key_t *rec = (root_key_t*)r;
466 g_free(rec->deveui_string);
467 g_byte_array_free(rec->deveui, true);
468 g_free(rec->appkey_string);
469 g_byte_array_free(rec->appkey, true);
472 static bool
473 session_keys_update_cb(void *r, char **err)
475 session_key_t *rec = (session_key_t*)r;
477 if (rec->dev_addr_string == NULL) {
478 *err = g_strdup("Device address can't be empty");
479 return false;
481 GByteArray *addr = g_byte_array_new();
482 if (!hex_str_to_bytes(rec->dev_addr_string, addr, false)) {
483 g_byte_array_free(addr, true);
484 *err = g_strdup("Device address must be hexadecimal");
485 return false;
487 if (addr->len != 4) {
488 g_byte_array_free(addr, true);
489 *err = g_strdup("Device address must be 4 bytes hexadecimal");
490 return false;
492 byte_array_reverse(addr);
493 memcpy(&rec->dev_addr, addr->data, sizeof(rec->dev_addr));
494 g_byte_array_free(addr, true);
496 if (rec->nwkskey_string == NULL) {
497 *err = g_strdup("Network session key can't be empty");
498 return false;
500 if (!rec->nwkskey) {
501 rec->nwkskey = g_byte_array_new();
503 if (!hex_str_to_bytes(rec->nwkskey_string, rec->nwkskey, false)) {
504 *err = g_strdup("Network session key must be hexadecimal");
505 return false;
507 if (rec->nwkskey->len != 16) {
508 *err = g_strdup("Network session key must be 16 bytes hexadecimal");
509 return false;
512 if (rec->appskey_string == NULL) {
513 *err = g_strdup("Application session key can't be empty");
514 return false;
516 if (!rec->appskey) {
517 rec->appskey = g_byte_array_new();
519 if (!hex_str_to_bytes(rec->appskey_string, rec->appskey, false)) {
520 *err = g_strdup("Application session key must be hexadecimal");
521 return false;
523 if (rec->appskey->len != 16) {
524 *err = g_strdup("Application session key must be 16 bytes hexadecimal");
525 return false;
528 *err = NULL;
529 return true;
532 static void *
533 session_keys_copy_cb(void *n, const void *o, size_t siz _U_)
535 session_key_t *new_rec = (session_key_t*)n;
536 const session_key_t *old_rec = (const session_key_t*)o;
538 if (old_rec->dev_addr_string) {
539 new_rec->dev_addr_string = g_strdup(old_rec->dev_addr_string);
540 GByteArray *addr = g_byte_array_new();
541 if (hex_str_to_bytes(new_rec->dev_addr_string, addr, false)) {
542 if (addr->len == 4) {
543 byte_array_reverse(addr);
544 memcpy(&new_rec->dev_addr, addr->data, sizeof(new_rec->dev_addr));
545 } else {
546 new_rec->dev_addr = 0;
549 g_byte_array_free(addr, true);
550 } else {
551 new_rec->dev_addr_string = NULL;
552 new_rec->dev_addr = 0;
555 if (old_rec->nwkskey_string) {
556 new_rec->nwkskey_string = g_strdup(old_rec->nwkskey_string);
557 new_rec->nwkskey = g_byte_array_new();
558 hex_str_to_bytes(new_rec->nwkskey_string, new_rec->nwkskey, false);
559 } else {
560 new_rec->nwkskey_string = NULL;
561 new_rec->nwkskey = NULL;
564 if (old_rec->appskey_string) {
565 new_rec->appskey_string = g_strdup(old_rec->appskey_string);
566 new_rec->appskey = g_byte_array_new();
567 hex_str_to_bytes(new_rec->appskey_string, new_rec->appskey, false);
568 } else {
569 new_rec->appskey_string = NULL;
570 new_rec->appskey = NULL;
573 return new_rec;
576 static void
577 session_keys_free_cb(void *r)
579 session_key_t *rec = (session_key_t*)r;
581 g_free(rec->dev_addr_string);
582 g_free(rec->nwkskey_string);
583 g_byte_array_free(rec->nwkskey, true);
584 g_free(rec->appskey_string);
585 g_byte_array_free(rec->appskey, true);
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)
594 static session_key_t *
595 get_session_key(uint32_t dev_addr)
597 unsigned i;
598 for (i = 0; i < session_num_keys; i++) {
599 if (session_keys[i].dev_addr == dev_addr) {
600 return &session_keys[i];
603 return NULL;
606 static root_key_t *
607 get_root_key(const uint8_t *deveui)
609 unsigned i;
610 for (i = 0; i < root_num_keys; i++) {
611 if (root_keys[i].deveui != NULL && memcmp(root_keys[i].deveui->data, deveui, 8) == 0) {
612 return &root_keys[i];
615 return NULL;
618 static uint32_t
619 calculate_mic(const uint8_t *in, uint8_t length, const uint8_t *key)
622 * cmac = aes128_cmac(key, in)
623 * MIC = cmac[0..3]
625 gcry_mac_hd_t mac_hd;
626 uint32_t mac;
627 size_t read_digest_length = 4;
629 if (gcry_mac_open(&mac_hd, GCRY_MAC_CMAC_AES, 0, NULL)) {
630 return 0;
632 if (gcry_mac_setkey(mac_hd, key, 16)) {
633 gcry_mac_close(mac_hd);
634 return 0;
636 /* Pass in the message */
637 if (gcry_mac_write(mac_hd, in, length)) {
638 gcry_mac_close(mac_hd);
639 return 0;
641 /* Read out the digest */
642 if (gcry_mac_read(mac_hd, &mac, &read_digest_length)) {
643 gcry_mac_close(mac_hd);
644 return 0;
646 /* Now close the mac handle */
647 gcry_mac_close(mac_hd);
648 return mac;
651 static nstime_t
652 gps_to_utctime(const uint32_t gpstime)
654 nstime_t utctime;
655 utctime.secs = (uint64_t)gpstime;
656 utctime.secs += 315964800; /* difference between Unix epoch and GPS epoch */
657 utctime.secs -= 18; /* leap seconds valid after 2017-01-01 */
658 utctime.nsecs = 0;
659 return utctime;
662 static void
663 cf_coords_lat_custom(char *buffer, uint32_t value)
665 int32_t coord_int = (value < 0x00800000) ? ((int32_t)value) : ((int32_t)value - 0x01000000);
666 double coord_double = coord_int * 90. / 0x00800000;
668 snprintf(buffer, ITEM_LABEL_LENGTH, "%.5f%c", fabs(coord_double), (coord_double >= 0) ? 'N' : 'S');
671 static void
672 cf_coords_lng_custom(char *buffer, uint32_t value)
674 int32_t coord_int = (value < 0x00800000) ? ((int32_t)value) : ((int32_t)value - 0x01000000);
675 double coord_double = coord_int * 180. / 0x00800000;
677 snprintf(buffer, ITEM_LABEL_LENGTH, "%.5f%c", fabs(coord_double), (coord_double >= 0) ? 'E' : 'W');
680 static bool
681 aes128_lorawan_encrypt(const uint8_t *key, const uint8_t *data_in, uint8_t *data_out, int length)
683 gcry_cipher_hd_t cipher;
684 if (gcry_cipher_open(&cipher, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0)) {
685 return false;
687 if (gcry_cipher_setkey(cipher, key, LORAWAN_AES_BLOCK_LENGTH)) {
688 gcry_cipher_close(cipher);
689 return false;
691 if (gcry_cipher_encrypt(cipher, data_out, length, data_in, length)) {
692 gcry_cipher_close(cipher);
693 return false;
695 gcry_cipher_close(cipher);
696 return true;
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)
703 gcry_cipher_hd_t cipher;
704 uint8_t iv[LORAWAN_AES_BLOCK_LENGTH] = {0x01, 0x00, 0x00, 0x00, 0x00, dir, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
705 memcpy(iv + 6, &dev_addr, 4);
706 memcpy(iv + 10, &fcnt, 4);
707 if (gcry_cipher_open(&cipher, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
708 return false;
710 if (gcry_cipher_setkey(cipher, key, LORAWAN_AES_BLOCK_LENGTH)) {
711 gcry_cipher_close(cipher);
712 return false;
714 if (gcry_cipher_setctr(cipher, iv, 16)) {
715 gcry_cipher_close(cipher);
716 return false;
718 if (gcry_cipher_encrypt(cipher, out, length, in, length)) {
719 gcry_cipher_close(cipher);
720 return false;
722 gcry_cipher_close(cipher);
723 return true;
726 static int
727 dissect_lorawan_mac_commands(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, bool uplink)
729 proto_item *ti, *tf;
730 proto_tree *mac_command_tree, *field_tree;
731 uint8_t command;
732 int32_t current_offset = 0;
734 ti = proto_tree_add_item(tree, hf_lorawan_mac_commands_type, tvb, 0, -1, ENC_NA);
735 mac_command_tree = proto_item_add_subtree(ti, ett_lorawan_mac_commands);
737 do {
738 command = tvb_get_uint8(tvb, current_offset);
739 if (uplink) {
740 tf = proto_tree_add_item(mac_command_tree, hf_lorawan_mac_command_uplink_type, tvb, current_offset, 1, ENC_NA);
741 current_offset++;
742 proto_item_append_text(tf, " (%s)", val_to_str_const(command, lorawan_mac_uplink_commandnames, "RFU"));
743 switch (command) {
744 case LORAWAN_MAC_COMMAND_UP_LINK_CHECK_REQ:
745 case LORAWAN_MAC_COMMAND_UP_DUTY_ANS:
746 case LORAWAN_MAC_COMMAND_UP_RX_TIMING_ANS:
747 case LORAWAN_MAC_COMMAND_UP_TX_PARAM_SETUP_ANS:
748 case LORAWAN_MAC_COMMAND_UP_DEVICE_TIME_REQ:
749 case LORAWAN_MAC_COMMAND_UP_BEACON_TIMING_REQ:
750 /* No payload */
751 break;
752 case LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS:
753 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
754 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 current_offset++;
756 break;
757 case LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS:
758 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
759 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 current_offset++;
761 break;
762 case LORAWAN_MAC_COMMAND_UP_DEV_STATUS_ANS:
763 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
764 proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_device_status_ans_battery_type, tvb, current_offset, 1, ENC_NA);
765 current_offset++;
766 proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_device_status_ans_margin_type, tvb, current_offset, 1, ENC_NA);
767 current_offset++;
768 break;
769 case LORAWAN_MAC_COMMAND_UP_DI_CHANNEL_ANS:
770 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
771 proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_di_channel_ans_type, tvb, current_offset, 1, ENC_NA);
772 current_offset++;
773 break;
774 case LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS:
775 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
776 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 current_offset++;
778 break;
779 case LORAWAN_MAC_COMMAND_UP_PING_SLOT_INFO_REQ:
780 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
781 proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_ping_slot_info_req_type, tvb, current_offset, 1, ENC_NA);
782 current_offset++;
783 break;
784 case LORAWAN_MAC_COMMAND_UP_PING_SLOT_CHANNEL_ANS:
785 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
786 proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_ping_slot_channel_ans_type, tvb, current_offset, 1, ENC_NA);
787 current_offset++;
788 break;
789 case LORAWAN_MAC_COMMAND_UP_BEACON_FREQ_ANS:
790 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
791 proto_tree_add_item(field_tree, hf_lorawan_mac_command_up_beacon_freq_ans_type, tvb, current_offset, 1, ENC_NA);
792 current_offset++;
793 break;
794 default:
795 /* End on unknown mac command because command lengths are not explicitly given */
796 return tvb_captured_length(tvb);
797 break;
799 } else {
800 tf = proto_tree_add_item(mac_command_tree, hf_lorawan_mac_command_downlink_type, tvb, current_offset, 1, ENC_NA);
801 current_offset++;
802 proto_item_append_text(tf, " (%s)", val_to_str_const(command, lorawan_mac_downlink_commandnames, "RFU"));
803 switch (command) {
804 case LORAWAN_MAC_COMMAND_DOWN_LINK_CHECK_ANS:
805 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
806 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_check_ans_margin_type, tvb, current_offset, 1, ENC_NA);
807 current_offset++;
808 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_check_ans_gwcnt_type, tvb, current_offset, 1, ENC_NA);
809 current_offset++;
810 break;
811 case LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ:
812 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
813 /* Region specific */
814 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_adr_req_datarate_type, tvb, current_offset, 1, ENC_NA);
815 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_adr_req_txpower_type, tvb, current_offset, 1, ENC_NA);
816 current_offset++;
817 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 current_offset += 2;
819 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 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_link_adr_req_repetitions_type, tvb, current_offset, 1, ENC_NA);
821 current_offset++;
822 break;
823 case LORAWAN_MAC_COMMAND_DOWN_DUTY_REQ:
824 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
825 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_dutycycle_type, tvb, current_offset, 1, ENC_NA);
826 current_offset++;
827 break;
828 case LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_REQ:
829 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
830 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 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_rx_setup_req_rx2datarate_type, tvb, current_offset, 1, ENC_NA);
833 current_offset++;
834 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_rx_setup_req_frequency_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
835 current_offset += 3;
836 break;
837 case LORAWAN_MAC_COMMAND_DOWN_DEV_STATUS_REQ:
838 case LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_INFO_ANS:
839 /* No payload */
840 break;
841 case LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ:
842 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
843 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_new_channel_req_index_type, tvb, current_offset, 1, ENC_NA);
844 current_offset++;
845 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_new_channel_req_frequency_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
846 current_offset += 3;
847 /* Region specific */
848 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 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_new_channel_req_drrange_min_type, tvb, current_offset, 1, ENC_NA);
851 current_offset++;
852 break;
853 case LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ:
854 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
855 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_rx_timing_req_delay_type, tvb, current_offset, 1, ENC_NA);
856 current_offset++;
857 break;
858 case LORAWAN_MAC_COMMAND_DOWN_TX_PARAM_SETUP_REQ:
859 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
860 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_tx_param_setup_req_type, tvb, current_offset, 1, ENC_NA);
861 current_offset++;
862 break;
863 case LORAWAN_MAC_COMMAND_DOWN_DI_CHANNEL_REQ:
864 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
865 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_di_channel_req_type, tvb, current_offset, 4, ENC_NA);
866 current_offset += 4;
867 break;
868 case LORAWAN_MAC_COMMAND_DOWN_DEVICE_TIME_ANS:
869 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
875 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
876 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_device_time_ans_type, tvb, current_offset, 5, ENC_NA);
877 current_offset += 5;
878 break;
879 case LORAWAN_MAC_COMMAND_DOWN_PING_SLOT_CHANNEL_REQ:
880 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
881 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_ping_slot_channel_req_type, tvb, current_offset, 4, ENC_NA);
882 current_offset += 4;
883 break;
884 case LORAWAN_MAC_COMMAND_DOWN_BEACON_FREQ_REQ:
885 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_command);
886 proto_tree_add_item(field_tree, hf_lorawan_mac_command_down_beacon_freq_req_type, tvb, current_offset, 3, ENC_NA);
887 current_offset += 3;
888 break;
889 default:
890 /* End on unknown mac command because command lengths are not explicitly given */
891 return tvb_captured_length(tvb);
892 break;
895 } while (tvb_captured_length_remaining(tvb, current_offset));
896 return tvb_captured_length(tvb);
899 static int
900 dissect_lorawan_beacon(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_)
902 proto_item *ti;
903 proto_tree *gwspecific_tree;
904 int32_t current_offset = 0;
905 unsigned length = tvb_reported_length(tvb);
906 uint16_t calc_crc1, calc_crc2;
907 nstime_t utctime;
909 proto_tree_add_string(tree, hf_lorawan_msgtype_type, tvb, current_offset, 0, val_to_str_const(LORAWAN_MAC_BEACON, lorawan_ftypenames, "RFU"));
911 if (length == 17) {
912 calc_crc1 = crc16_r3_ccitt_tvb(tvb, 0, 6);
913 calc_crc2 = crc16_r3_ccitt_tvb(tvb, 8, 7);
914 proto_tree_add_item(tree, hf_lorawan_beacon_rfu1_type, tvb, current_offset, 2, ENC_NA);
915 current_offset += 2;
916 } else {
917 calc_crc1 = crc16_r3_ccitt_tvb(tvb, 0, 7);
918 calc_crc2 = crc16_r3_ccitt_tvb(tvb, 9, 8);
919 proto_tree_add_item(tree, hf_lorawan_beacon_rfu1_type, tvb, current_offset, 3, ENC_NA);
920 current_offset += 3;
922 utctime = gps_to_utctime(tvb_get_uint32(tvb, current_offset, ENC_LITTLE_ENDIAN));
923 proto_tree_add_time(tree, hf_lorawan_beacon_time_type, tvb, current_offset, 4, &utctime);
924 current_offset += 4;
925 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 current_offset += 2;
928 ti = proto_tree_add_item(tree, hf_lorawan_beacon_gwspecific_type, tvb, current_offset, 7, ENC_NA);
929 gwspecific_tree = proto_item_add_subtree(ti, ett_lorawan_beacon_gwspecific);
930 proto_tree_add_item(gwspecific_tree, hf_lorawan_beacon_gwspecific_infodesc_type, tvb, current_offset, 1, ENC_NA);
931 current_offset++;
932 proto_tree_add_item(gwspecific_tree, hf_lorawan_beacon_gwspecific_lat_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
933 current_offset += 3;
934 proto_tree_add_item(gwspecific_tree, hf_lorawan_beacon_gwspecific_lng_type, tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
935 current_offset += 3;
937 if (length == 19) {
938 proto_tree_add_item(tree, hf_lorawan_beacon_rfu2_type, tvb, current_offset, 1, ENC_NA);
939 current_offset++;
941 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);
943 return tvb_captured_length(tvb);
946 static int
947 dissect_lorawan_join_request(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_)
949 proto_item *tf;
950 proto_tree *field_tree;
951 int32_t current_offset = 1;
953 tf = proto_tree_add_item(tree, hf_lorawan_join_request_type, tvb, current_offset, 18, ENC_NA);
954 field_tree = proto_item_add_subtree(tf, ett_lorawan_join_request);
955 proto_tree_add_item(field_tree, hf_lorawan_join_request_joineui_type, tvb, current_offset, 8, ENC_LITTLE_ENDIAN);
956 current_offset += 8;
957 proto_tree_add_item(field_tree, hf_lorawan_join_request_deveui_type, tvb, current_offset, 8, ENC_LITTLE_ENDIAN);
958 current_offset += 8;
959 proto_tree_add_item(field_tree, hf_lorawan_join_request_devnonce_type, tvb, current_offset, 2, ENC_LITTLE_ENDIAN);
960 current_offset += 2;
962 /* MIC
963 * cmac = aes128_cmac(AppKey, msg)
964 * MIC = cmac[0..3]
966 root_key_t *root_key = get_root_key(tvb_get_ptr(tvb, current_offset - 10, 8));
967 if (root_key) {
968 proto_tree_add_checksum(tree, tvb, current_offset, hf_lorawan_mic_type, hf_lorawan_mic_status_type, &ei_lorawan_mic, pinfo,
969 calculate_mic(tvb_get_ptr(tvb, 0, current_offset), current_offset, root_key->appkey->data), ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY);
970 } else {
971 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, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
973 expert_add_info(pinfo, checksum_item, &ei_lorawan_missing_keys);
976 return tvb_captured_length(tvb);
979 static int
980 dissect_lorawan_join_accept(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_)
982 proto_item *tf;
983 proto_tree *field_tree;
984 int32_t current_offset = 1;
985 root_key_t *root_key = NULL;
987 int length = tvb_captured_length_remaining(tvb, current_offset);
988 tf = proto_tree_add_item(tree, hf_lorawan_join_accept_type, tvb, current_offset, 12, ENC_NA);
989 field_tree = proto_item_add_subtree(tf, ett_lorawan_join_accept);
991 /* Join-Accept may be either 16B or 32B long (including MIC) */
992 if (length != 16 && length != 32) {
993 expert_add_info(pinfo, field_tree, &ei_lorawan_length_error);
994 proto_tree_add_item(tree, hf_lorawan_frame_payload_type, tvb, current_offset, tvb_captured_length_remaining(tvb, current_offset), ENC_NA);
995 return tvb_captured_length(tvb);
998 /* Iterate through all available root keys for Join-Accept */
999 uint8_t *decrypted_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, length);
1000 uint8_t *mic_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, length - 4 + 1);
1001 uint32_t mic_check;
1002 for (unsigned key_idx = 0; key_idx < root_num_keys; key_idx++) {
1003 if (aes128_lorawan_encrypt(root_keys[key_idx].appkey->data, tvb_get_ptr(tvb, current_offset, length), decrypted_buffer, length)) {
1004 mic_buffer[0] = tvb_get_uint8(tvb, current_offset - 1); // unencrypted MHDR
1005 memcpy(&mic_buffer[1], decrypted_buffer, length - 4); // decrypted Join-Accept
1006 memcpy(&mic_check, &decrypted_buffer[length - 4], 4); // decrypted MIC
1008 // check for valid MIC of payload decrypted using current AppKey
1009 if (calculate_mic(mic_buffer, length - 4 + 1, root_keys[key_idx].appkey->data) == mic_check) {
1010 root_key = &root_keys[key_idx];
1011 break;
1016 if (root_key) {
1017 tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, decrypted_buffer, length, length);
1018 add_new_data_source(pinfo, next_tvb, "Decrypted payload");
1019 current_offset = 0;
1021 proto_tree_add_item(field_tree, hf_lorawan_join_accept_joinnonce_type, next_tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
1022 current_offset += 3;
1023 proto_tree_add_item(field_tree, hf_lorawan_join_accept_netid_type, next_tvb, current_offset, 3, ENC_LITTLE_ENDIAN);
1024 current_offset += 3;
1025 proto_tree_add_item(field_tree, hf_lorawan_join_accept_devaddr_type, next_tvb, current_offset, 4, ENC_LITTLE_ENDIAN);
1026 current_offset += 4;
1027 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 current_offset++;
1029 proto_tree_add_item(field_tree, hf_lorawan_join_accept_rxdelay_type, next_tvb, current_offset, 1, ENC_NA);
1030 current_offset++;
1031 if (tvb_captured_length(next_tvb) - current_offset > 4) {
1032 proto_tree_add_item(field_tree, hf_lorawan_join_accept_cflist_type, next_tvb, current_offset, 16, ENC_NA);
1033 current_offset += 16;
1034 proto_item_set_len(tf, proto_item_get_len(tf) + 16);
1037 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 } else {
1039 expert_add_info(pinfo, field_tree, &ei_lorawan_missing_keys);
1040 proto_tree_add_item(tree, hf_lorawan_frame_payload_type, tvb, current_offset, tvb_captured_length_remaining(tvb, current_offset), ENC_NA);
1043 return tvb_captured_length(tvb);
1046 static int
1047 dissect_lorawan_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, bool uplink)
1049 proto_item *ti = NULL, *tf;
1050 proto_tree *field_tree;
1051 int32_t current_offset = 1;
1052 uint8_t fopts_length = (tvb_get_uint8(tvb, current_offset + 4) & LORAWAN_FRAME_FOPTSLEN_MASK);
1053 uint8_t fport = 0;
1055 /* Frame header */
1056 tf = proto_tree_add_item(tree, hf_lorawan_frame_header_type, tvb, current_offset, 7 + fopts_length, ENC_NA);
1057 field_tree = proto_item_add_subtree(tf, ett_lorawan_frame_header);
1058 proto_tree_add_item(field_tree, hf_lorawan_frame_header_address_type, tvb, current_offset, 4, ENC_LITTLE_ENDIAN);
1059 uint32_t dev_address = tvb_get_uint32(tvb, current_offset, ENC_LITTLE_ENDIAN);
1060 current_offset += 4;
1061 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 current_offset++;
1063 proto_tree_add_item(field_tree, hf_lorawan_frame_header_frame_counter_type, tvb, current_offset, 2, ENC_LITTLE_ENDIAN);
1064 uint32_t fcnt = tvb_get_uint16(tvb, current_offset, ENC_LITTLE_ENDIAN);
1065 current_offset += 2;
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
1073 if (fopts_length > 0) {
1074 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, current_offset, fopts_length);
1075 current_offset += dissect_lorawan_mac_commands(next_tvb, pinfo, tree, uplink);
1078 if (tvb_captured_length_remaining(tvb, current_offset) > 4) {
1079 /* FPort present */
1080 proto_tree_add_item(tree, hf_lorawan_frame_fport_type, tvb, current_offset, 1, ENC_NA);
1081 fport = tvb_get_uint8(tvb, current_offset);
1082 current_offset++;
1085 if ((fopts_length > 0) && (fport == 0)) {
1086 /* TODO?: error, not allowed */
1089 uint8_t frmpayload_length = tvb_captured_length_remaining(tvb, current_offset) - 4;
1090 if (frmpayload_length > 0) {
1091 ti = proto_tree_add_item(tree, hf_lorawan_frame_payload_type, tvb, current_offset, frmpayload_length, ENC_NA);
1094 session_key_t *session_key = get_session_key(dev_address);
1095 if (session_key && frmpayload_length > 0) {
1096 uint8_t padded_length = LORAWAN_AES_PADDEDSIZE(frmpayload_length);
1097 uint8_t *decrypted_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, padded_length);
1098 uint8_t *encrypted_buffer = (uint8_t *)wmem_alloc0(pinfo->pool, padded_length);
1099 tvb_memcpy(tvb, encrypted_buffer, current_offset, frmpayload_length);
1100 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 tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, decrypted_buffer, frmpayload_length, frmpayload_length);
1102 add_new_data_source(pinfo, next_tvb, "Decrypted payload");
1103 proto_tree *frame_payload_decrypted_tree = proto_item_add_subtree(ti, ett_lorawan_frame_payload_decrypted);
1104 if (fport == 0) {
1105 current_offset += dissect_lorawan_mac_commands(next_tvb, pinfo, tree, uplink);
1106 } else {
1108 * fport values 0x01 - 0xDF are application specific
1109 * fport values 0xE0 - 0xFF are reserved for future extensions
1111 proto_tree_add_bytes(frame_payload_decrypted_tree, hf_lorawan_frame_payload_decrypted_type, next_tvb, 0, frmpayload_length, decrypted_buffer);
1112 current_offset += frmpayload_length;
1114 } else {
1115 proto_tree_add_expert_format(tree, pinfo, &ei_lorawan_decrypting_error, tvb, current_offset, 4, "Decrypting error");
1116 current_offset += frmpayload_length;
1118 } else {
1119 current_offset += frmpayload_length;
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)
1128 if (session_key) {
1129 int frame_length = current_offset;
1130 uint8_t *msg = (uint8_t *)wmem_alloc0(pinfo->pool, frame_length + 16);
1131 msg[0] = 0x49;
1132 msg[5] = uplink ? 0 : 1;
1133 memcpy(msg + 6, &dev_address, 4);
1134 memcpy(msg + 10, &fcnt, 4);
1135 msg[15] = frame_length;
1136 tvb_memcpy(tvb, msg + 16, 0, frame_length);
1137 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 } else {
1139 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, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
1141 expert_add_info(pinfo, checksum_item, &ei_lorawan_missing_keys);
1144 return tvb_captured_length(tvb);
1147 static int
1148 dissect_lorawan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
1150 proto_item *ti, *tf;
1151 proto_tree *lorawan_tree, *field_tree;
1152 int32_t current_offset = 0;
1154 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LoRaWAN");
1155 col_clear(pinfo->cinfo,COL_INFO);
1156 ti = proto_tree_add_item(tree, proto_lorawan, tvb, 0, -1, ENC_NA);
1157 lorawan_tree = proto_item_add_subtree(ti, ett_lorawan);
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
1162 uint16_t classb_rfu = tvb_get_uint16(tvb, current_offset, ENC_LITTLE_ENDIAN);
1163 unsigned classb_length = tvb_reported_length(tvb);
1164 if (classb_rfu == 0x0000 && (classb_length == 17 || classb_length == 19)) {
1165 return dissect_lorawan_beacon(tvb, pinfo, lorawan_tree);
1168 /* MAC header */
1169 uint8_t mac_ftype = LORAWAN_MAC_FTYPE(tvb_get_uint8(tvb, current_offset));
1170 proto_tree_add_string(lorawan_tree, hf_lorawan_msgtype_type, tvb, current_offset, 0, val_to_str_const(mac_ftype, lorawan_ftypenames, "RFU"));
1171 tf = proto_tree_add_item(lorawan_tree, hf_lorawan_mac_header_type, tvb, current_offset, 1, ENC_NA);
1172 proto_item_append_text(tf, " (Message Type: %s, Major Version: %s)",
1173 val_to_str_const(mac_ftype, lorawan_ftypenames, "RFU"),
1174 val_to_str_const(LORAWAN_MAC_MAJOR(tvb_get_uint8(tvb, current_offset)), lorawan_majornames, "RFU"));
1176 /* Validate MHDR fields for LoRaWAN packet, do not dissect malformed packets */
1177 if ((tvb_get_uint8(tvb, current_offset) & (LORAWAN_MAC_MAJOR_MASK | LORAWAN_MAC_RFU_MASK)) != LORAWAN_MAC_MAJOR_R1) {
1178 expert_add_info(pinfo, lorawan_tree, &ei_lorawan_mhdr_error);
1179 mac_ftype = LORAWAN_MAC_FTYPE_RFU;
1182 field_tree = proto_item_add_subtree(tf, ett_lorawan_mac_header);
1183 proto_tree_add_item(field_tree, hf_lorawan_mac_header_ftype_type, tvb, current_offset, 1, ENC_NA);
1184 proto_tree_add_item(field_tree, hf_lorawan_mac_header_rfu_type, tvb, current_offset, 1, ENC_NA);
1185 proto_tree_add_item(field_tree, hf_lorawan_mac_header_major_type, tvb, current_offset, 1, ENC_NA);
1186 current_offset++;
1188 switch (mac_ftype) {
1189 case LORAWAN_MAC_FTYPE_JOINREQUEST:
1190 return dissect_lorawan_join_request(tvb, pinfo, lorawan_tree);
1192 case LORAWAN_MAC_FTYPE_JOINACCEPT:
1193 return dissect_lorawan_join_accept(tvb, pinfo, lorawan_tree);
1195 case LORAWAN_MAC_FTYPE_UNCONFIRMEDDATAUP:
1196 case LORAWAN_MAC_FTYPE_CONFIRMEDDATAUP:
1197 return dissect_lorawan_data(tvb, pinfo, lorawan_tree, true /*uplink*/);
1199 case LORAWAN_MAC_FTYPE_UNCONFIRMEDDATADOWN:
1200 case LORAWAN_MAC_FTYPE_CONFIRMEDDATADOWN:
1201 return dissect_lorawan_data(tvb, pinfo, lorawan_tree, false /*downlink*/);
1203 default: /* LORAWAN_MAC_FTYPE_RFU or LORAWAN_MAC_FTYPE_PROPRIETARY */
1204 proto_tree_add_item(lorawan_tree, hf_lorawan_frame_payload_type, tvb, current_offset, tvb_captured_length_remaining(tvb, current_offset), ENC_NA);
1205 return tvb_captured_length(tvb);
1209 void
1210 proto_register_lorawan(void)
1212 static hf_register_info hf[] = {
1213 { &hf_lorawan_msgtype_type,
1214 { "Message type", "lorawan.msgtype",
1215 FT_STRING, BASE_NONE,
1216 NULL, 0x0,
1217 NULL, HFILL }
1219 { &hf_lorawan_mac_header_type,
1220 { "MAC Header", "lorawan.mhdr",
1221 FT_NONE, BASE_NONE,
1222 NULL, 0x0,
1223 "[MHDR] MAC Header", HFILL }
1225 { &hf_lorawan_mac_header_ftype_type,
1226 { "Message Type", "lorawan.mhdr.ftype",
1227 FT_UINT8, BASE_DEC,
1228 VALS(lorawan_ftypenames), LORAWAN_MAC_FTYPE_MASK,
1229 "[FType] Message Type", HFILL }
1231 { &hf_lorawan_mac_header_rfu_type,
1232 { "RFU", "lorawan.mhdr.rfu",
1233 FT_UINT8, BASE_DEC,
1234 NULL, LORAWAN_MAC_RFU_MASK,
1235 "[RFU]", HFILL }
1237 { &hf_lorawan_mac_header_major_type,
1238 { "Major Version", "lorawan.mhdr.major",
1239 FT_UINT8, BASE_DEC,
1240 VALS(lorawan_majornames), LORAWAN_MAC_MAJOR_MASK,
1241 "[Major] Major Version", HFILL }
1243 { &hf_lorawan_mac_commands_type,
1244 { "MAC Commands", "lorawan.mac_commands",
1245 FT_NONE, BASE_NONE,
1246 NULL, 0x0,
1247 NULL, HFILL }
1249 { &hf_lorawan_mac_command_uplink_type,
1250 { "Uplink Command", "lorawan.mac_command_uplink",
1251 FT_UINT8, BASE_DEC,
1252 VALS(lorawan_mac_uplink_commandnames), 0x0,
1253 NULL, HFILL }
1255 { &hf_lorawan_mac_command_downlink_type,
1256 { "Downlink Command", "lorawan.mac_command_downlink",
1257 FT_UINT8, BASE_DEC,
1258 VALS(lorawan_mac_downlink_commandnames), 0x0,
1259 NULL, HFILL }
1261 { &hf_lorawan_mac_command_down_link_check_ans_type,
1262 { "Link Check Answer", "lorawan.link_check_answer",
1263 FT_UINT8, BASE_HEX,
1264 NULL, 0x0,
1265 NULL, HFILL }
1267 { &hf_lorawan_mac_command_down_link_check_ans_margin_type,
1268 { "Demodulation Margin", "lorawan.link_check_answer.margin",
1269 FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
1270 UNS(&units_decibels), 0x0,
1271 NULL, HFILL }
1273 { &hf_lorawan_mac_command_down_link_check_ans_gwcnt_type,
1274 { "Gateway Count", "lorawan.link_check_answer.gwcnt",
1275 FT_UINT8, BASE_DEC,
1276 NULL, 0x0,
1277 NULL, HFILL }
1279 { &hf_lorawan_mac_command_down_link_adr_req_datarate_type,
1280 { "Data Rate", "lorawan.link_adr_request.datarate",
1281 FT_UINT8, BASE_DEC,
1282 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_DATARATE_MASK,
1283 NULL, HFILL }
1285 { &hf_lorawan_mac_command_down_link_adr_req_txpower_type,
1286 { "Transmit Power", "lorawan.link_adr_request.txpower",
1287 FT_UINT8, BASE_DEC,
1288 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_TXPOWER_MASK,
1289 NULL, HFILL }
1291 { &hf_lorawan_mac_command_down_link_adr_req_channel_type,
1292 { "Channel 1", "lorawan.link_adr_request.channel",
1293 FT_UINT16, BASE_HEX,
1294 NULL, 0x0,
1295 NULL, HFILL }
1297 { &hf_lorawan_mac_command_down_link_adr_req_channel1_type,
1298 { "Channel 1", "lorawan.link_adr_request.channel.1",
1299 FT_BOOLEAN, 16,
1300 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_1_MASK,
1301 NULL, HFILL }
1303 { &hf_lorawan_mac_command_down_link_adr_req_channel2_type,
1304 { "Channel 2", "lorawan.link_adr_request.channel.2",
1305 FT_BOOLEAN, 16,
1306 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_2_MASK,
1307 NULL, HFILL }
1309 { &hf_lorawan_mac_command_down_link_adr_req_channel3_type,
1310 { "Channel 3", "lorawan.link_adr_request.channel.3",
1311 FT_BOOLEAN, 16,
1312 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_3_MASK,
1313 NULL, HFILL }
1315 { &hf_lorawan_mac_command_down_link_adr_req_channel4_type,
1316 { "Channel 4", "lorawan.link_adr_request.channel.4",
1317 FT_BOOLEAN, 16,
1318 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_4_MASK,
1319 NULL, HFILL }
1321 { &hf_lorawan_mac_command_down_link_adr_req_channel5_type,
1322 { "Channel 5", "lorawan.link_adr_request.channel.5",
1323 FT_BOOLEAN, 16,
1324 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_5_MASK,
1325 NULL, HFILL }
1327 { &hf_lorawan_mac_command_down_link_adr_req_channel6_type,
1328 { "Channel 6", "lorawan.link_adr_request.channel.6",
1329 FT_BOOLEAN, 16,
1330 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_6_MASK,
1331 NULL, HFILL }
1333 { &hf_lorawan_mac_command_down_link_adr_req_channel7_type,
1334 { "Channel 7", "lorawan.link_adr_request.channel.7",
1335 FT_BOOLEAN, 16,
1336 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_7_MASK,
1337 NULL, HFILL }
1339 { &hf_lorawan_mac_command_down_link_adr_req_channel8_type,
1340 { "Channel 8", "lorawan.link_adr_request.channel.8",
1341 FT_BOOLEAN, 16,
1342 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_8_MASK,
1343 NULL, HFILL }
1345 { &hf_lorawan_mac_command_down_link_adr_req_channel9_type,
1346 { "Channel 9", "lorawan.link_adr_request.channel.9",
1347 FT_BOOLEAN, 16,
1348 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_9_MASK,
1349 NULL, HFILL }
1351 { &hf_lorawan_mac_command_down_link_adr_req_channel10_type,
1352 { "Channel 10", "lorawan.link_adr_request.channel.10",
1353 FT_BOOLEAN, 16,
1354 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_10_MASK,
1355 NULL, HFILL }
1357 { &hf_lorawan_mac_command_down_link_adr_req_channel11_type,
1358 { "Channel 11", "lorawan.link_adr_request.channel.11",
1359 FT_BOOLEAN, 16,
1360 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_11_MASK,
1361 NULL, HFILL }
1363 { &hf_lorawan_mac_command_down_link_adr_req_channel12_type,
1364 { "Channel 12", "lorawan.link_adr_request.channel.12",
1365 FT_BOOLEAN, 16,
1366 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_12_MASK,
1367 NULL, HFILL }
1369 { &hf_lorawan_mac_command_down_link_adr_req_channel13_type,
1370 { "Channel 13", "lorawan.link_adr_request.channel.13",
1371 FT_BOOLEAN, 16,
1372 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_13_MASK,
1373 NULL, HFILL }
1375 { &hf_lorawan_mac_command_down_link_adr_req_channel14_type,
1376 { "Channel 14", "lorawan.link_adr_request.channel.14",
1377 FT_BOOLEAN, 16,
1378 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_14_MASK,
1379 NULL, HFILL }
1381 { &hf_lorawan_mac_command_down_link_adr_req_channel15_type,
1382 { "Channel 15", "lorawan.link_adr_request.channel.15",
1383 FT_BOOLEAN, 16,
1384 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_15_MASK,
1385 NULL, HFILL }
1387 { &hf_lorawan_mac_command_down_link_adr_req_channel16_type,
1388 { "Channel 16", "lorawan.link_adr_request.channel.16",
1389 FT_BOOLEAN, 16,
1390 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHANNEL_16_MASK,
1391 NULL, HFILL }
1393 { &hf_lorawan_mac_command_down_link_adr_req_channel_mask_control_type,
1394 { "Channel Mask Control", "lorawan.link_adr_request.chmaskctl",
1395 FT_UINT8, BASE_DEC,
1396 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_CHMASKCNTL_MASK,
1397 NULL, HFILL }
1399 { &hf_lorawan_mac_command_down_link_adr_req_repetitions_type,
1400 { "Number Of Repetitions", "lorawan.link_adr_request.nbrep",
1401 FT_UINT8, BASE_DEC,
1402 NULL, LORAWAN_MAC_COMMAND_DOWN_LINK_ADR_REQ_NBREP_MASK,
1403 NULL, HFILL }
1405 { &hf_lorawan_mac_command_up_link_adr_ans_txpower_type,
1406 { "Transmit Power Ack", "lorawan.link_adr_response.txpower",
1407 FT_BOOLEAN, 8,
1408 NULL, LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_TXPOWER_MASK,
1409 NULL, HFILL }
1411 { &hf_lorawan_mac_command_up_link_adr_ans_datarate_type,
1412 { "Data Rate Ack", "lorawan.link_adr_response.datarate",
1413 FT_BOOLEAN, 8,
1414 NULL, LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_DATARATE_MASK,
1415 NULL, HFILL }
1417 { &hf_lorawan_mac_command_up_link_adr_ans_channel_mask_type,
1418 { "Channel Mask Ack", "lorawan.link_adr_response.channelmask",
1419 FT_BOOLEAN, 8,
1420 NULL, LORAWAN_MAC_COMMAND_UP_LINK_ADR_ANS_CHANNEL_MASK,
1421 NULL, HFILL }
1423 { &hf_lorawan_mac_command_down_dutycycle_type,
1424 { "Duty Cycle", "lorawan.dutycycle_request.dutycycle",
1425 FT_UINT8, BASE_DEC,
1426 NULL, 0x0,
1427 NULL, HFILL }
1429 { &hf_lorawan_mac_command_down_rx_setup_req_rx1droffset_type,
1430 { "RX1 Datarate Offset", "lorawan.rx_setup_request.rx1droffset",
1431 FT_UINT8, BASE_DEC,
1432 NULL, LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX1DROFFSET_MASK,
1433 NULL, HFILL }
1435 { &hf_lorawan_mac_command_down_rx_setup_req_rx2datarate_type,
1436 { "RX2 Datarate", "lorawan.rx_setup_request.rx2datarate",
1437 FT_UINT8, BASE_DEC,
1438 NULL, LORAWAN_MAC_COMMAND_DOWN_RX_SETUP_RX2DATARATE_MASK,
1439 NULL, HFILL }
1441 { &hf_lorawan_mac_command_down_rx_setup_req_frequency_type,
1442 { "Frequency", "lorawan.rx_setup_request.frequency",
1443 FT_UINT24, BASE_DEC|BASE_UNIT_STRING,
1444 UNS(&units_hz), 0x0,
1445 NULL, HFILL }
1447 { &hf_lorawan_mac_command_up_rx_setup_ans_type,
1448 { "RX Setup Response", "lorawan.rx_setup_response",
1449 FT_UINT8, BASE_HEX,
1450 NULL, 0x0,
1451 NULL, HFILL }
1453 { &hf_lorawan_mac_command_up_rx_setup_ans_rx1droffset_type,
1454 { "RX1 Datarate Offset Ack", "lorawan.rx_setup_response.rx1droffset",
1455 FT_BOOLEAN, 8,
1456 NULL, LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_TXPOWER_MASK,
1457 NULL, HFILL }
1459 { &hf_lorawan_mac_command_up_rx_setup_ans_rx2datarate_type,
1460 { "RX2 Datarate Ack", "lorawan.rx_setup_response.rx2datarate",
1461 FT_BOOLEAN, 8,
1462 NULL, LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_DATARATE_MASK,
1463 NULL, HFILL }
1465 { &hf_lorawan_mac_command_up_rx_setup_ans_frequency_type,
1466 { "Frequency Ack", "lorawan.rx_setup_response.frequency",
1467 FT_BOOLEAN, 8,
1468 NULL, LORAWAN_MAC_COMMAND_UP_RX_SETUP_ANS_CHANNEL_MASK,
1469 NULL, HFILL }
1471 { &hf_lorawan_mac_command_up_device_status_ans_battery_type,
1472 { "Battery Level", "lorawan.device_status_response.battery",
1473 FT_UINT8, BASE_DEC,
1474 NULL, 0x0,
1475 NULL, HFILL }
1477 { &hf_lorawan_mac_command_up_device_status_ans_margin_type,
1478 { "Margin", "lorawan.device_status_response.margin",
1479 FT_UINT8, BASE_DEC,
1480 NULL, LORAWAN_MAC_COMMAND_UP_DEVICE_STATUS_ANS_MARGIN_MASK,
1481 NULL, HFILL }
1483 { &hf_lorawan_mac_command_down_new_channel_req_index_type,
1484 { "Index", "lorawan.new_channel_request.index",
1485 FT_UINT8, BASE_DEC,
1486 NULL, 0x0,
1487 NULL, HFILL }
1489 { &hf_lorawan_mac_command_down_new_channel_req_frequency_type,
1490 { "Frequency", "lorawan.new_channel_request.frequency",
1491 FT_UINT24, BASE_DEC|BASE_UNIT_STRING,
1492 UNS(&units_hz), 0x0,
1493 NULL, HFILL }
1495 { &hf_lorawan_mac_command_down_new_channel_req_drrange_max_type,
1496 { "Maximum Data Rate", "lorawan.new_channel_request.drrange_max",
1497 FT_UINT8, BASE_DEC,
1498 NULL, LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MAX_MASK,
1499 NULL, HFILL }
1501 { &hf_lorawan_mac_command_down_new_channel_req_drrange_min_type,
1502 { "Minimum Data Rate", "lorawan.new_channel_request.drrange_min",
1503 FT_UINT8, BASE_DEC,
1504 NULL, LORAWAN_MAC_COMMAND_DOWN_NEW_CHANNEL_REQ_DRRANGE_MIN_MASK,
1505 NULL, HFILL }
1507 { &hf_lorawan_mac_command_up_new_channel_ans_type,
1508 { "New Channel Response", "lorawan.new_channel_response",
1509 FT_UINT8, BASE_HEX,
1510 NULL, 0x0,
1511 NULL, HFILL }
1513 { &hf_lorawan_mac_command_up_new_channel_ans_datarate_type,
1514 { "Datarate Ack", "lorawan.new_channel_response.datarate",
1515 FT_BOOLEAN, 8,
1516 NULL, LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_DATARATE_MASK,
1517 NULL, HFILL }
1519 { &hf_lorawan_mac_command_up_new_channel_ans_frequency_type,
1520 { "Frequency Ack", "lorawan.new_channel_response.frequency",
1521 FT_BOOLEAN, 8,
1522 NULL, LORAWAN_MAC_COMMAND_UP_NEW_CHANNEL_ANS_FREQUENCY_MASK,
1523 NULL, HFILL }
1525 { &hf_lorawan_mac_command_down_rx_timing_req_delay_type,
1526 { "Delay", "lorawan.rx_timing_request.delay",
1527 FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
1528 UNS(&units_seconds), LORAWAN_MAC_COMMAND_DOWN_RX_TIMING_REQ_DELAY_MASK,
1529 NULL, HFILL }
1531 { &hf_lorawan_mac_command_up_di_channel_ans_type,
1532 { "Status", "lorawan.di_channel_response",
1533 FT_BYTES, BASE_NONE,
1534 NULL, 0x0,
1535 NULL, HFILL }
1537 { &hf_lorawan_mac_command_up_ping_slot_info_req_type,
1538 { "PingSlotParam", "lorawan.ping_slot_info_request",
1539 FT_BYTES, BASE_NONE,
1540 NULL, 0x0,
1541 NULL, HFILL }
1543 { &hf_lorawan_mac_command_up_ping_slot_channel_ans_type,
1544 { "Status", "lorawan.ping_slot_channel_response",
1545 FT_BYTES, BASE_NONE,
1546 NULL, 0x0,
1547 NULL, HFILL }
1549 { &hf_lorawan_mac_command_up_beacon_freq_ans_type,
1550 { "Status", "lorawan.beacon_freq_response",
1551 FT_BYTES, BASE_NONE,
1552 NULL, 0x0,
1553 NULL, HFILL }
1555 { &hf_lorawan_mac_command_down_tx_param_setup_req_type,
1556 { "DwellTime, EIRP", "lorawan.tx_param_setup_request",
1557 FT_BYTES, BASE_NONE,
1558 NULL, 0x0,
1559 NULL, HFILL }
1561 { &hf_lorawan_mac_command_down_di_channel_req_type,
1562 { "ChIndex, Frequency", "lorawan.di_channel_request",
1563 FT_BYTES, BASE_NONE,
1564 NULL, 0x0,
1565 NULL, HFILL }
1567 { &hf_lorawan_mac_command_down_device_time_ans_type,
1568 { "DeviceTimeAns", "lorawan.device_time_response",
1569 FT_BYTES, BASE_NONE,
1570 NULL, 0x0,
1571 NULL, HFILL }
1573 { &hf_lorawan_mac_command_down_ping_slot_channel_req_type,
1574 { "Frequency, DR", "lorawan.ping_slot_channel_request",
1575 FT_BYTES, BASE_NONE,
1576 NULL, 0x0,
1577 NULL, HFILL }
1579 { &hf_lorawan_mac_command_down_beacon_freq_req_type,
1580 { "Frequency", "lorawan.beacon_freq_request",
1581 FT_BYTES, BASE_NONE,
1582 NULL, 0x0,
1583 NULL, HFILL }
1585 { &hf_lorawan_join_request_type,
1586 { "Join Request", "lorawan.join_request",
1587 FT_NONE, BASE_NONE,
1588 NULL, 0x0,
1589 NULL, HFILL }
1591 { &hf_lorawan_join_request_joineui_type,
1592 { "Join-Server identifier", "lorawan.join_request.joineui",
1593 FT_EUI64, BASE_NONE,
1594 NULL, 0x0,
1595 "[JoinEUI] Join-Server identifier", HFILL }
1597 { &hf_lorawan_join_request_deveui_type,
1598 { "End-device identifier", "lorawan.join_request.deveui",
1599 FT_EUI64, BASE_NONE,
1600 NULL, 0x0,
1601 "[DevEUI] End-device identifier", HFILL }
1603 { &hf_lorawan_join_request_devnonce_type,
1604 { "Device Nonce", "lorawan.join_request.devnonce",
1605 FT_UINT16, BASE_DEC,
1606 NULL, 0x0,
1607 "[DevNonce] Device Nonce", HFILL }
1609 { &hf_lorawan_join_accept_type,
1610 { "Join Accept", "lorawan.join_accept",
1611 FT_NONE, BASE_NONE,
1612 NULL, 0x0,
1613 NULL, HFILL }
1615 { &hf_lorawan_join_accept_joinnonce_type,
1616 { "Join-Server nonce", "lorawan.join_accept.joinnonce",
1617 FT_UINT24, BASE_HEX,
1618 NULL, 0x0,
1619 "[JoinNonce] Join-Server nonce", HFILL }
1621 { &hf_lorawan_join_accept_netid_type,
1622 { "Network identifier", "lorawan.join_accept.netid",
1623 FT_UINT24, BASE_HEX,
1624 NULL, 0x0,
1625 "[NetID] Network identifier", HFILL }
1627 { &hf_lorawan_join_accept_devaddr_type,
1628 { "Device Address", "lorawan.join_accept.devaddr",
1629 FT_UINT32, BASE_HEX,
1630 NULL, 0x0,
1631 "[DevAddr] Device Address", HFILL }
1633 { &hf_lorawan_join_accept_dlsettings_type,
1634 { "Downlink configuration", "lorawan.join_accept.dlsettings",
1635 FT_UINT8, BASE_HEX,
1636 NULL, 0x0,
1637 "[DLSettings] Downlink configuration", HFILL }
1639 { &hf_lorawan_join_accept_dlsettings_rx1droffset_type,
1640 { "RX1 Data rate offset", "lorawan.join_accept.dlsettings.rx1droffset",
1641 FT_UINT8, BASE_DEC,
1642 NULL, LORAWAN_JOIN_ACCEPT_RX1DROFFSET_MASK,
1643 "[RX1DROffset] RX1 Data rate offset", HFILL }
1645 { &hf_lorawan_join_accept_dlsettings_rx2dr_type,
1646 { "RX2 Data rate", "lorawan.join_accept.dlsettings.rx2datarate",
1647 FT_UINT8, BASE_DEC,
1648 NULL, LORAWAN_JOIN_ACCEPT_RX2DR_MASK,
1649 "[RX2DataRate] RX2 Data rate", HFILL }
1651 { &hf_lorawan_join_accept_rxdelay_type,
1652 { "Delay between TX and RX", "lorawan.join_accept.rxdelay",
1653 FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
1654 UNS(&units_seconds), 0x0,
1655 "[RXDelay] Delay between TX and RX", HFILL }
1657 { &hf_lorawan_join_accept_cflist_type,
1658 { "List of network parameters", "lorawan.join_accept.cflist",
1659 FT_BYTES, BASE_NONE,
1660 NULL, 0x0,
1661 "[CFList] List of network parameters", HFILL }
1663 { &hf_lorawan_frame_header_type,
1664 { "Frame Header", "lorawan.fhdr",
1665 FT_NONE, BASE_NONE,
1666 NULL, 0x0,
1667 "[FHDR] Frame Header", HFILL }
1669 { &hf_lorawan_frame_header_address_type,
1670 { "Device Address", "lorawan.fhdr.devaddr",
1671 FT_UINT32, BASE_HEX,
1672 NULL, 0x0,
1673 "[DevAddr] Device Address", HFILL }
1675 { &hf_lorawan_frame_header_frame_control_type,
1676 { "Frame Control", "lorawan.fhdr.fctrl",
1677 FT_UINT8, BASE_HEX,
1678 NULL, 0x0,
1679 "[FCtrl] Frame Control", HFILL }
1681 { &hf_lorawan_frame_header_frame_control_adr_type,
1682 { "Adaptive Data Rate", "lorawan.fhdr.fctrl.adr",
1683 FT_BOOLEAN, 8,
1684 NULL, 0x80,
1685 "[ADR] Adaptive Data Rate", HFILL }
1687 { &hf_lorawan_frame_header_frame_control_adrackreq_type,
1688 { "ADR Acknowledgement Request", "lorawan.fhdr.fctrl.adrackreq",
1689 FT_BOOLEAN, 8,
1690 NULL, 0x40,
1691 "[ADRACKReq] ADR Acknowledgement Request(up) / RFU(down)", HFILL}
1693 { &hf_lorawan_frame_header_frame_control_ack_type,
1694 { "Acknowledgement", "lorawan.fhdr.fctrl.ack",
1695 FT_BOOLEAN, 8,
1696 NULL, 0x20,
1697 "[ACK] Acknowledgement", HFILL }
1699 { &hf_lorawan_frame_header_frame_control_fpending_type,
1700 { "ClassB Enabled / Frame Pending", "lorawan.fhdr.fctrl.fpending",
1701 FT_BOOLEAN, 8,
1702 NULL, 0x10,
1703 "[FPending/ClassB] ClassB Enabled (up) / Frame Pending (down)", HFILL }
1705 { &hf_lorawan_frame_header_frame_control_foptslen_type,
1706 { "Frame Options Length", "lorawan.fhdr.fctrl.foptslen",
1707 FT_UINT8, BASE_DEC,
1708 NULL, LORAWAN_FRAME_FOPTSLEN_MASK,
1709 "[FOptsLen] Frame Options Length", HFILL }
1711 { &hf_lorawan_frame_header_frame_counter_type,
1712 { "Frame Counter", "lorawan.fhdr.fcnt",
1713 FT_UINT16, BASE_DEC,
1714 NULL, 0x0,
1715 "[FCnt] Frame Counter", HFILL }
1717 { &hf_lorawan_frame_fport_type,
1718 { "Port", "lorawan.fport",
1719 FT_UINT8, BASE_HEX,
1720 NULL, 0x0,
1721 "[FPort] Port", HFILL }
1723 { &hf_lorawan_frame_payload_type,
1724 { "Frame Payload", "lorawan.frmpayload",
1725 FT_BYTES, BASE_NONE,
1726 NULL, 0x0,
1727 "[FRMPayload] Frame Payload", HFILL }
1729 { &hf_lorawan_frame_payload_decrypted_type,
1730 { "Decrypted Frame Payload", "lorawan.frmpayload_decrypted",
1731 FT_BYTES, BASE_NONE,
1732 NULL, 0x0,
1733 NULL, HFILL }
1735 { &hf_lorawan_mic_type,
1736 { "Message Integrity Code", "lorawan.mic",
1737 FT_UINT32, BASE_HEX,
1738 NULL, 0x0,
1739 "[MIC] Message Integrity Code", HFILL }
1741 { &hf_lorawan_mic_status_type,
1742 { "Message Integrity Code Status", "lorawan.mic.status",
1743 FT_UINT8, BASE_NONE,
1744 VALS(proto_checksum_vals), 0x0,
1745 NULL, HFILL }
1747 { &hf_lorawan_beacon_rfu1_type,
1748 { "RFU", "lorawan.beacon.rfu1",
1749 FT_BYTES, BASE_NONE,
1750 NULL, 0x0,
1751 "[RFU]", HFILL}
1753 { &hf_lorawan_beacon_time_type,
1754 { "Timestamp", "lorawan.beacon.time",
1755 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1756 NULL, 0x0,
1757 "[Time] Timestamp", HFILL}
1759 { &hf_lorawan_beacon_crc1_type,
1760 { "CRC of Timestamp", "lorawan.beacon.crc1",
1761 FT_UINT16, BASE_HEX,
1762 NULL, 0x0,
1763 "[CRC] CRC of Timestamp", HFILL }
1765 { &hf_lorawan_beacon_crc1_status_type,
1766 { "Beacon Timestamp CRC Status", "lorawan.beacon.crc1.status",
1767 FT_UINT8, BASE_NONE,
1768 VALS(proto_checksum_vals), 0x0,
1769 NULL, HFILL }
1771 { &hf_lorawan_beacon_gwspecific_type,
1772 { "Gateway specific part", "lorawan.beacon.gwspecific",
1773 FT_NONE, BASE_NONE,
1774 NULL, 0x0,
1775 "[GwSpecific] Gateway specific part", HFILL }
1777 { &hf_lorawan_beacon_gwspecific_infodesc_type,
1778 { "Information descriptor", "lorawan.beacon.gwspecific.infodesc",
1779 FT_UINT8, BASE_DEC,
1780 NULL, 0x0,
1781 "[InfoDesc] Information descriptor", HFILL }
1783 { &hf_lorawan_beacon_gwspecific_lat_type,
1784 { "GPS latitude", "lorawan.beacon.gwspecific.lat",
1785 FT_UINT24, BASE_CUSTOM,
1786 CF_FUNC(cf_coords_lat_custom), 0x0,
1787 "[Lat] GPS latitude", HFILL }
1789 { &hf_lorawan_beacon_gwspecific_lng_type,
1790 { "GPS longitude", "lorawan.beacon.gwspecific.lng",
1791 FT_UINT24, BASE_CUSTOM,
1792 CF_FUNC(cf_coords_lng_custom), 0x0,
1793 "[Lng] GPS longitude", HFILL }
1795 { &hf_lorawan_beacon_rfu2_type,
1796 { "RFU", "lorawan.beacon.rfu2",
1797 FT_BYTES, BASE_NONE,
1798 NULL, 0x0,
1799 "[RFU]", HFILL }
1801 { &hf_lorawan_beacon_crc2_type,
1802 { "CRC of GwSpecific", "lorawan.beacon.crc2",
1803 FT_UINT16, BASE_HEX,
1804 NULL, 0x0,
1805 "[CRC] CRC of GwSpecific", HFILL }
1807 { &hf_lorawan_beacon_crc2_status_type,
1808 { "Beacon GwSpecific CRC Status", "lorawan.beacon.crc2.status",
1809 FT_UINT8, BASE_NONE,
1810 VALS(proto_checksum_vals), 0x0,
1811 NULL, HFILL }
1815 /* Setup protocol subtree array */
1816 static int *ett[] = {
1817 &ett_lorawan,
1818 &ett_lorawan_mac_header,
1819 &ett_lorawan_mac_commands,
1820 &ett_lorawan_mac_command,
1821 &ett_lorawan_mac_command_link_check_ans,
1822 &ett_lorawan_mac_command_link_adr_req_channel,
1823 &ett_lorawan_mac_command_rx_setup_ans,
1824 &ett_lorawan_mac_command_new_channel_ans,
1825 &ett_lorawan_join_request,
1826 &ett_lorawan_join_accept,
1827 &ett_lorawan_join_accept_dlsettings,
1828 &ett_lorawan_frame_header,
1829 &ett_lorawan_frame_header_control,
1830 &ett_lorawan_frame_payload_decrypted,
1831 &ett_lorawan_beacon,
1832 &ett_lorawan_beacon_gwspecific,
1835 static ei_register_info ei[] = {
1836 { &ei_lorawan_missing_keys, { "lorawan.missing_keys", PI_PROTOCOL, PI_NOTE, "Missing encryption keys", EXPFILL }},
1837 { &ei_lorawan_decrypting_error, { "lorawan.decrypting_error", PI_DECRYPTION, PI_ERROR, "Error decrypting payload", EXPFILL }},
1838 { &ei_lorawan_mic, { "lorawan.mic_bad.expert", PI_CHECKSUM, PI_WARN, "Bad MIC", EXPFILL }},
1839 { &ei_lorawan_length_error, { "lorawan.length_error", PI_MALFORMED, PI_ERROR, "Field length is not according to LoRaWAN standard", EXPFILL }},
1840 { &ei_lorawan_mhdr_error, { "lorawan.mhdr_error", PI_MALFORMED, PI_ERROR, "LoRaWAN MAC Header malformed", EXPFILL }},
1843 expert_module_t* expert_lorawan;
1845 proto_lorawan = proto_register_protocol (
1846 "LoRaWAN Protocol", /* name */
1847 "LoRaWAN", /* short name */
1848 "lorawan" /* abbrev */
1851 lorawan_handle = register_dissector("lorawan", dissect_lorawan, proto_lorawan);
1853 proto_register_field_array(proto_lorawan, hf, array_length(hf));
1854 proto_register_subtree_array(ett, array_length(ett));
1856 expert_lorawan = expert_register_protocol(proto_lorawan);
1857 expert_register_field_array(expert_lorawan, ei, array_length(ei));
1859 static uat_field_t root_keys_uat_fields[] = {
1860 UAT_FLD_CSTRING(root_keys, deveui_string, "DevEUI", "LoRaWAN End-device Identifier"),
1861 UAT_FLD_CSTRING(root_keys, appkey_string, "AppKey", "LoRaWAN Application Key"),
1862 UAT_END_FIELDS
1864 static uat_field_t session_keys_uat_fields[] = {
1865 UAT_FLD_CSTRING(session_keys, dev_addr_string, "DevAddr", "LoRaWAN Device Address"),
1866 UAT_FLD_CSTRING(session_keys, nwkskey_string, "NwkSKey", "LoRaWAN Network Session Key"),
1867 UAT_FLD_CSTRING(session_keys, appskey_string, "AppSKey", "LoRaWAN Application Session Key"),
1868 UAT_END_FIELDS
1871 uat_t *root_keys_uat = uat_new("LoRaWAN Root Keys",
1872 sizeof(root_key_t),
1873 "root_keys_lorawan",
1874 true,
1875 &root_keys,
1876 &root_num_keys,
1877 UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
1878 NULL,
1879 root_keys_copy_cb,
1880 root_keys_update_cb,
1881 root_keys_free_cb,
1882 NULL,
1883 NULL,
1884 root_keys_uat_fields
1886 uat_t *session_keys_uat = uat_new("LoRaWAN Session Keys",
1887 sizeof(session_key_t),
1888 "session_keys_lorawan",
1889 true,
1890 &session_keys,
1891 &session_num_keys,
1892 UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS,
1893 NULL,
1894 session_keys_copy_cb,
1895 session_keys_update_cb,
1896 session_keys_free_cb,
1897 NULL,
1898 NULL,
1899 session_keys_uat_fields
1902 module_t *lorawan_module;
1903 lorawan_module = prefs_register_protocol(proto_lorawan, NULL);
1904 prefs_register_uat_preference(lorawan_module, "root_keys_lorawan", "LoRaWAN Root Keys",
1905 "A table to define root encryption keys for LoRaWAN devices, used for Join Request/Accept",
1906 root_keys_uat);
1907 prefs_register_uat_preference(lorawan_module, "session_keys_lorawan", "LoRaWAN Session Keys",
1908 "A table to define session encryption keys for LoRaWAN devices, used for Data Up/Down",
1909 session_keys_uat);
1912 void
1913 proto_reg_handoff_lorawan(void)
1915 dissector_add_uint("loratap.syncword", 0x34, lorawan_handle);
1916 dissector_add_for_decode_as("udp.port", lorawan_handle);
1920 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1922 * Local variables:
1923 * c-basic-offset: 8
1924 * tab-width: 8
1925 * indent-tabs-mode: t
1926 * End:
1928 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1929 * :indentSize=8:tabSize=8:noTabs=false: