/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 | | */ |