epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-mqtt-sn.c
blob9b3ed3fca6164665821e3206526ba5ed00521a99
1 /* packet-mqtt-sn.c
3 * Routines for MQTT-SN v1.2 <http://mqtt.org>
5 * Copyright (c) 2015, Jan-Hendrik Bolte <jabolte@uni-osnabrueck.de>
6 * Copyright (c) 2015, University of Osnabrueck
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
16 #include <epan/packet.h>
17 #include <epan/tfs.h>
18 #include <wsutil/array.h>
20 /* MQTT-SN message types. */
21 #define MQTTSN_ADVERTISE 0x00
22 #define MQTTSN_SEARCHGW 0x01
23 #define MQTTSN_GWINFO 0x02
24 #define MQTTSN_RESERVED_03 0x03
25 #define MQTTSN_CONNECT 0x04
26 #define MQTTSN_CONNACK 0x05
27 #define MQTTSN_WILLTOPICREQ 0x06
28 #define MQTTSN_WILLTOPIC 0x07
29 #define MQTTSN_WILLMSGREQ 0x08
30 #define MQTTSN_WILLMSG 0x09
31 #define MQTTSN_REGISTER 0x0A
32 #define MQTTSN_REGACK 0x0B
33 #define MQTTSN_PUBLISH 0x0C
34 #define MQTTSN_PUBACK 0x0D
35 #define MQTTSN_PUBCOMP 0x0E
36 #define MQTTSN_PUBREC 0x0F
37 #define MQTTSN_PUBREL 0x10
38 #define MQTTSN_RESERVED_11 0x11
39 #define MQTTSN_SUBSCRIBE 0x12
40 #define MQTTSN_SUBACK 0x13
41 #define MQTTSN_UNSUBSCRIBE 0x14
42 #define MQTTSN_UNSUBACK 0x15
43 #define MQTTSN_PINGREQ 0x16
44 #define MQTTSN_PINGRESP 0x17
45 #define MQTTSN_DISCONNECT 0x18
46 #define MQTTSN_RESERVED_19 0x19
47 #define MQTTSN_WILLTOPICUPD 0x1A
48 #define MQTTSN_WILLTOPICRESP 0x1B
49 #define MQTTSN_WILLMSGUPD 0x1C
50 #define MQTTSN_WILLMSGRESP 0x1D
51 #define MQTTSN_ENCAPSULATED_MSG 0xFE
53 /* Masks to extract flag values. */
54 #define MQTTSN_MASK_DUP_FLAG 0x80
55 #define MQTTSN_MASK_QOS 0x60
56 #define MQTTSN_MASK_RETAIN 0x10
57 #define MQTTSN_MASK_WILL 0x08
58 #define MQTTSN_MASK_CLEAN 0x04
59 #define MQTTSN_MASK_TOPIC_ID_TYPE 0x03
61 /* Mask to extract radius from control. */
62 #define MQTTSN_MASK_CONTROL 0x03
64 /* MQTT-SN QoS levels. */
65 #define MQTTSN_QOS_ATMOST_ONCE 0x00
66 #define MQTTSN_QOS_ATLEAST_ONCE 0x01
67 #define MQTTSN_QOS_EXACTLY_ONCE 0x02
68 #define MQTTSN_QOS_NO_CONNECTION 0x03
70 /* MQTT-SN topic types. */
71 #define MQTTSN_TOPIC_NORMAL_ID 0x00
72 #define MQTTSN_TOPIC_PREDEF_ID 0x01
73 #define MQTTSN_TOPIC_SHORT_NAME 0x02
74 #define MQTTSN_TOPIC_RESERVED 0x03
76 /* MQTT-SN connection return types. */
77 #define MQTTSN_CON_ACCEPTED 0x00
78 #define MQTTSN_CON_REFUSED_CONGESTION 0x01
79 #define MQTTSN_CON_REFUSED_INVALID_TOPIC_ID 0x02
80 #define MQTTSN_CON_REFUSED_NOT_SUPPORTED 0x03
82 void proto_register_mqttsn(void);
83 void proto_reg_handoff_mqttsn(void);
85 /* MQTT-SN message type values. */
86 static const value_string mqttsn_msgtype_vals[] = {
87 { MQTTSN_ADVERTISE, "Advertise Gateway" },
88 { MQTTSN_SEARCHGW, "Search Gateway" },
89 { MQTTSN_GWINFO, "Gateway Info" },
90 { MQTTSN_RESERVED_03, "Reserved_03" },
91 { MQTTSN_CONNECT, "Connect Command" },
92 { MQTTSN_CONNACK, "Connect Ack" },
93 { MQTTSN_WILLTOPICREQ, "Will Topic Request" },
94 { MQTTSN_WILLTOPIC, "Will Topic" },
95 { MQTTSN_WILLMSGREQ, "Will Message Request" },
96 { MQTTSN_WILLMSG, "Will Message" },
97 { MQTTSN_REGISTER, "Register" },
98 { MQTTSN_REGACK, "Register Ack" },
99 { MQTTSN_PUBLISH, "Publish Message" },
100 { MQTTSN_PUBACK, "Publish Ack" },
101 { MQTTSN_PUBCOMP, "Publish Complete" },
102 { MQTTSN_PUBREC, "Publish Received" },
103 { MQTTSN_PUBREL, "Publish Release" },
104 { MQTTSN_RESERVED_11, "Reserved_11" },
105 { MQTTSN_SUBSCRIBE, "Subscribe Request" },
106 { MQTTSN_SUBACK, "Subscribe Ack" },
107 { MQTTSN_UNSUBSCRIBE, "Unsubscribe Request" },
108 { MQTTSN_UNSUBACK, "Unsubscribe Ack" },
109 { MQTTSN_PINGREQ, "Ping Request" },
110 { MQTTSN_PINGRESP, "Ping Response" },
111 { MQTTSN_DISCONNECT, "Disconnect Req" },
112 { MQTTSN_RESERVED_19, "Reserved_19" },
113 { MQTTSN_WILLTOPICUPD, "Will Topic Update" },
114 { MQTTSN_WILLTOPICRESP, "Will Topic Response" },
115 { MQTTSN_WILLMSGUPD, "Will Message Update" },
116 { MQTTSN_WILLMSGRESP, "Will Message Response" },
117 { MQTTSN_ENCAPSULATED_MSG, "Encapsulated Message" },
118 { 0, NULL }
120 static value_string_ext mqttsn_msgtype_vals_ext = VALUE_STRING_EXT_INIT(mqttsn_msgtype_vals);
122 /* MQTT-SN QoS level values. */
123 static const value_string mqttsn_qos_vals[] = {
124 { MQTTSN_QOS_ATMOST_ONCE, "Fire and Forget" },
125 { MQTTSN_QOS_ATLEAST_ONCE, "Acknowledged deliver" },
126 { MQTTSN_QOS_EXACTLY_ONCE, "Assured Delivery" },
127 { MQTTSN_QOS_NO_CONNECTION, "No Connection required" },
128 { 0, NULL }
131 /* MQTT-SN topic type values. */
132 static const value_string mqttsn_typeid_vals[] = {
133 { MQTTSN_TOPIC_NORMAL_ID, "Normal ID" },
134 { MQTTSN_TOPIC_PREDEF_ID, "Pre-defined ID" },
135 { MQTTSN_TOPIC_SHORT_NAME, "Short Topic Name" },
136 { MQTTSN_TOPIC_RESERVED, "Reserved" },
137 { 0, NULL }
140 /* MQTT-SN connection return type values. */
141 static const value_string mqttsn_return_vals[] = {
142 { MQTTSN_CON_ACCEPTED, "Accepted" },
143 { MQTTSN_CON_REFUSED_CONGESTION, "Rejected: Congestion" },
144 { MQTTSN_CON_REFUSED_INVALID_TOPIC_ID, "Rejected: invalid topic ID" },
145 { MQTTSN_CON_REFUSED_NOT_SUPPORTED, "Rejected: not supported" },
146 { 0, NULL }
149 /* MQTT-SN Handle */
150 static dissector_handle_t mqttsn_handle;
152 /* Initialize the protocol and registered fields. */
153 static int proto_mqttsn;
155 static int hf_mqttsn_msg;
156 static int hf_mqttsn_msg_len;
157 static int hf_mqttsn_msg_type;
158 static int hf_mqttsn_dup;
159 static int hf_mqttsn_qos;
160 static int hf_mqttsn_retain;
161 static int hf_mqttsn_will;
162 static int hf_mqttsn_clean_session;
163 static int hf_mqttsn_topic_id_type;
164 static int hf_mqttsn_return_code;
165 static int hf_mqttsn_gw_id;
166 static int hf_mqttsn_gw_addr;
167 static int hf_mqttsn_adv_interv;
168 static int hf_mqttsn_radius;
169 static int hf_mqttsn_protocol_id;
170 static int hf_mqttsn_topic_id;
171 static int hf_mqttsn_msg_id;
172 static int hf_mqttsn_topic;
173 static int hf_mqttsn_topic_name_or_id;
174 static int hf_mqttsn_sleep_timer;
175 static int hf_mqttsn_will_topic;
176 static int hf_mqttsn_will_msg;
177 static int hf_mqttsn_pub_msg;
178 static int hf_mqttsn_client_id;
179 static int hf_mqttsn_keep_alive;
180 static int hf_mqttsn_control_info;
181 static int hf_mqttsn_wireless_node_id;
183 /* Initialize subtree pointers. */
184 static int ett_mqttsn_hdr;
185 static int ett_mqttsn_msg;
186 static int ett_mqttsn_flags;
188 /* Dissect a single MQTT-SN packet. */
189 // NOLINTNEXTLINE(misc-no-recursion)
190 static void dissect_mqttsn_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
192 /* Various variables. */
193 int long_hdr_len = 0;
194 uint8_t mqttsn_msg_type_id;
195 uint16_t mqttsn_msg_len;
197 /* Get the message length. */
198 mqttsn_msg_len = tvb_get_uint8(tvb, offset);
200 /* If the message length is equal to 1 then the next two bytes define the real message length. */
201 if (mqttsn_msg_len == 1)
203 long_hdr_len = 1;
204 mqttsn_msg_len = tvb_get_ntohs(tvb, offset + 1);
207 /* If this is an encapsulated message, we need to add the offset of the previous packet. */
208 mqttsn_msg_len += offset;
210 /* Get the message type id (in byte 1 or 3 - depending on the message length). */
211 mqttsn_msg_type_id = tvb_get_uint8(tvb, offset + (long_hdr_len ? 3 : 1));
213 if (tree)
215 /* Variables for the message items and trees. */
216 proto_item *ti = NULL;
217 proto_item *ti_mqttsn = NULL;
218 proto_tree *mqttsn_tree = NULL;
219 proto_tree *mqttsn_msg_tree = NULL;
220 proto_tree *mqttsn_flag_tree = NULL;
222 /* Add MQTT-SN subtree to the main tree. */
223 if (offset == 0)
225 ti = proto_tree_add_item(tree, proto_mqttsn, tvb, 0, -1, ENC_NA);
226 mqttsn_tree = proto_item_add_subtree(ti, ett_mqttsn_hdr);
228 /* If this is an encapsulated message, we add the message to the existing subtree. */
229 else
231 mqttsn_tree = tree;
234 /* Add message subtree. */
235 ti_mqttsn = proto_tree_add_item(mqttsn_tree, hf_mqttsn_msg, tvb, offset + (long_hdr_len ? 3 : 1), -1, ENC_NA);
236 mqttsn_msg_tree = proto_item_add_subtree(ti_mqttsn, ett_mqttsn_msg);
238 /* | Message type (1 octet) | */
239 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_type, tvb, offset + (long_hdr_len ? 3 : 1), 1, ENC_BIG_ENDIAN);
240 offset += 1;
242 /* | Message length (1 - 2 octets) | */
243 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_len, tvb, offset - 1 + (long_hdr_len ? 1 : 0), (long_hdr_len ? 2 : 1), ENC_BIG_ENDIAN);
244 offset += (long_hdr_len ? 3 : 1);
247 * Only some message types contain flags (1 octet).
248 * ______________________________________________________________________________________
249 * | | | | | | |
250 * | bit 7 | bit 6 + 5 | bit 4 | bit 3 | bit 2 | bit 1 + 0 |
251 * | DUP | QoS | Retain | Will | CleanSession | TopicIdType |
252 * |_________|___________|____________|__________|__________________|___________________|
254 switch (mqttsn_msg_type_id)
256 /* Connect */
257 case MQTTSN_CONNECT:
258 /* Add Will, CleanSession and Topic ID Type flags. */
259 mqttsn_flag_tree = proto_item_add_subtree(ti_mqttsn, ett_mqttsn_flags);
260 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_will, tvb, offset, 1, ENC_BIG_ENDIAN);
261 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_clean_session, tvb, offset, 1, ENC_BIG_ENDIAN);
262 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_topic_id_type, tvb, offset, 1, ENC_BIG_ENDIAN);
263 offset += 1;
264 break;
266 /* Publish */
267 case MQTTSN_PUBLISH:
268 /* Add DUP, QoS, Retain and Topic ID Type flags. */
269 mqttsn_flag_tree = proto_item_add_subtree(ti_mqttsn, ett_mqttsn_flags);
270 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_dup, tvb, offset, 1, ENC_BIG_ENDIAN);
271 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_qos, tvb, offset, 1, ENC_BIG_ENDIAN);
272 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_retain, tvb, offset, 1, ENC_BIG_ENDIAN);
273 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_topic_id_type, tvb, offset, 1, ENC_BIG_ENDIAN);
274 offset += 1;
275 break;
277 /* Will Topic + Subscribe + Subscribe Acknowledgement + Unsubscribe + Will Topic Update */
278 case MQTTSN_WILLTOPIC:
279 case MQTTSN_SUBSCRIBE:
280 case MQTTSN_SUBACK:
281 case MQTTSN_UNSUBSCRIBE:
282 case MQTTSN_WILLTOPICUPD:
283 /* Add Topic ID Type flag. */
284 mqttsn_flag_tree = proto_item_add_subtree(ti_mqttsn, ett_mqttsn_flags);
285 proto_tree_add_item(mqttsn_flag_tree, hf_mqttsn_topic_id_type, tvb, offset, 1, ENC_BIG_ENDIAN);
286 offset += 1;
287 break;
289 /* Default Case */
290 default:
291 break;
294 /* Add message specific informations. */
295 switch (mqttsn_msg_type_id)
297 /* Advertise Gateway */
298 case MQTTSN_ADVERTISE:
299 /* | 1 - Gateway ID | 2,3 - Duration until next Advertise | */
300 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_gw_id, tvb, offset, 1, ENC_BIG_ENDIAN);
301 offset += 1;
302 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_adv_interv, tvb, offset, 2, ENC_BIG_ENDIAN);
303 break;
305 /* Search Gateway */
306 case MQTTSN_SEARCHGW:
307 /* | 1 - Broadcast Radius | */
308 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_radius, tvb, offset, 1, ENC_BIG_ENDIAN);
309 break;
311 /* Gateway Information */
312 case MQTTSN_GWINFO:
313 /* | 1 - Gateway ID | 2:n - Gateway Address (optional) | */
314 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_gw_id, tvb, offset, 1, ENC_BIG_ENDIAN);
315 offset += 1;
317 /* Gateway Address is only present if message is sent by client. */
318 if (offset < mqttsn_msg_len)
320 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_gw_addr, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
322 break;
324 /* Connect */
325 case MQTTSN_CONNECT:
326 /* | 1 - Protocol ID | 2,3 - Keep Alive Duration | 4:n - Client ID | */
327 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_protocol_id, tvb, offset, 1, ENC_BIG_ENDIAN);
328 offset += 1;
329 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN);
330 offset += 2;
331 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_client_id, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
332 break;
334 /* Connection Acknowledgement */
335 case MQTTSN_CONNACK:
336 /* | 1 - Return code | */
337 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_return_code, tvb, offset, 1, ENC_BIG_ENDIAN);
338 break;
340 /* Will Topic Request + Will Message Request */
341 case MQTTSN_WILLTOPICREQ:
342 case MQTTSN_WILLMSGREQ:
343 /* Will topic/message requests don't have a variable header. */
344 break;
346 /* Will Topic */
347 case MQTTSN_WILLTOPIC:
348 /* | 1:n - Will topic | */
349 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_will_topic, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
350 break;
352 /* Will Message */
353 case MQTTSN_WILLMSG:
354 /* | 1:n - Will message | */
355 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_will_msg, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
356 break;
358 /* Register */
359 case MQTTSN_REGISTER:
360 /* | 1,2 - Topic ID | 3,4 - Message ID | 5:n - Topic name | */
361 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_topic_id, tvb, offset, 2, ENC_BIG_ENDIAN);
362 offset += 2;
363 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
364 offset += 2;
365 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_topic, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
366 break;
368 /* Register Acknowledgement */
369 case MQTTSN_REGACK:
370 /* | 1,2 - Topic ID | 3,4 - Message ID | 5 - Return code | */
371 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_topic_id, tvb, offset, 2, ENC_BIG_ENDIAN);
372 offset += 2;
373 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
374 offset += 2;
375 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_return_code, tvb, offset, 1, ENC_BIG_ENDIAN);
376 break;
378 /* Publish */
379 case MQTTSN_PUBLISH:
380 /* | 1,2 - Topic ID | 3,4 - Message ID | 5:n - Publish data | */
381 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_topic_id, tvb, offset, 2, ENC_BIG_ENDIAN);
382 offset += 2;
383 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
384 offset += 2;
385 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_pub_msg, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
386 break;
388 /* Publish Acknowledgement */
389 case MQTTSN_PUBACK:
390 /* | 1,2 - Topic ID | 3,4 - Message ID | 5 - Return code | */
391 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_topic_id, tvb, offset, 2, ENC_BIG_ENDIAN);
392 offset += 2;
393 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
394 offset += 2;
395 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_return_code, tvb, offset, 1, ENC_BIG_ENDIAN);
396 break;
398 /* Publish Complete + Publish Received + Publish Released */
399 case MQTTSN_PUBCOMP:
400 case MQTTSN_PUBREC:
401 case MQTTSN_PUBREL:
402 /* | 1,2 - Message ID | */
403 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
404 break;
406 /* Subscribe + Unsubscribe */
407 case MQTTSN_SUBSCRIBE:
408 case MQTTSN_UNSUBSCRIBE:
409 /* | 1,2 - Message ID | 5:n - Topic name _OR_ 5,6 - Topic ID | */
410 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
411 offset += 2;
412 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_topic_name_or_id, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
413 break;
415 /* Subscribe Acknowledgment */
416 case MQTTSN_SUBACK:
417 /* | 1,2 - Topic ID | 3,4 - Message ID | 5 - Return code | */
418 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_topic_id, tvb, offset, 2, ENC_BIG_ENDIAN);
419 offset += 2;
420 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
421 offset += 2;
422 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_return_code, tvb, offset, 1, ENC_BIG_ENDIAN);
423 break;
425 /* Unsubscribe Acknowledgement */
426 case MQTTSN_UNSUBACK:
427 /* | 1,2 - Message ID | */
428 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_msg_id, tvb, offset, 2, ENC_BIG_ENDIAN);
429 break;
431 /* Ping Request */
432 case MQTTSN_PINGREQ:
433 /* | 1:n - Client ID (optional) | */
434 if (offset < mqttsn_msg_len)
436 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_client_id, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
438 break;
440 /* Ping Response */
441 case MQTTSN_PINGRESP:
442 /* Ping responses don't have a variable header. */
443 break;
445 /* Disconnect */
446 case MQTTSN_DISCONNECT:
447 /* | 1,2 - Sleep Time Duration (optional) | */
448 if (offset < mqttsn_msg_len)
450 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_sleep_timer, tvb, offset, 2, ENC_BIG_ENDIAN);
452 break;
454 /* Will Topic Update */
455 case MQTTSN_WILLTOPICUPD:
456 /* | 1:n - Will topic | */
457 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_will_topic, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
458 break;
460 /* Will Message Update */
461 case MQTTSN_WILLMSGUPD:
462 /* | 1:n - Will message | */
463 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_will_msg, tvb, offset, (mqttsn_msg_len - offset), ENC_ASCII);
464 break;
466 /* Will Topic Response + Will Message Response */
467 case MQTTSN_WILLTOPICRESP:
468 case MQTTSN_WILLMSGRESP:
469 /* | 1 - Return code | */
470 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_return_code, tvb, offset, 1, ENC_BIG_ENDIAN);
471 break;
473 case MQTTSN_ENCAPSULATED_MSG:
474 /* | 1 - Control information | 2:n - Wireless Node ID | n+1:m - MQTT-SN message | */
475 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_control_info, tvb, offset, 1, ENC_BIG_ENDIAN);
476 offset += 1;
477 proto_tree_add_item(mqttsn_msg_tree, hf_mqttsn_wireless_node_id, tvb, offset, (mqttsn_msg_len - offset), ENC_BIG_ENDIAN);
478 offset += (mqttsn_msg_len - offset);
480 /* Dissect encapsulated message (if present). */
481 if (tvb_reported_length_remaining(tvb, offset) > 0)
483 increment_dissection_depth(pinfo);
484 dissect_mqttsn_packet(tvb, pinfo, mqttsn_msg_tree, offset);
485 decrement_dissection_depth(pinfo);
488 /* Default Case */
489 default:
490 break;
495 /* Dissect a complete MQTT-SN message. */
496 static int dissect_mqttsn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
498 /* Various variables. */
499 int offset = 0;
500 uint8_t mqttsn_msg_type_id;
503 * If the value in byte 0 is unequal to 1 then the value defines the
504 * message length and the message type id is contained in byte 1.
506 if (tvb_get_uint8(tvb, 0) != 1)
508 mqttsn_msg_type_id = tvb_get_uint8(tvb, 1);
511 * If the value in byte 0 is equal to 1 then the next two bytes define
512 * the real message length and the message type id is contained in byte 3.
514 else
516 mqttsn_msg_type_id = tvb_get_uint8(tvb, 3);
519 /* Add the protcol name to the protocol column. */
520 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MQTT-SN");
522 /* Add the message type to the info column. */
523 col_clear(pinfo->cinfo, COL_INFO);
524 col_add_str(pinfo->cinfo, COL_INFO, val_to_str_ext(mqttsn_msg_type_id, &mqttsn_msgtype_vals_ext, "Unknown (0x%02x)"));
526 /* Dissect a MQTT-SN packet. */
527 dissect_mqttsn_packet(tvb, pinfo, tree, offset);
528 return tvb_captured_length(tvb);
531 /* Register the protocol with Wireshark. */
532 void proto_register_mqttsn(void)
534 static hf_register_info hf_mqttsn[] = {
535 { &hf_mqttsn_msg,
536 { "Message", "mqttsn.msg",
537 FT_NONE, BASE_NONE, NULL, 0,
538 NULL, HFILL }
540 { &hf_mqttsn_msg_len,
541 { "Message Length", "mqttsn.msg.len",
542 FT_UINT16, BASE_DEC, NULL, 0x0,
543 NULL, HFILL }
545 { &hf_mqttsn_msg_type,
546 { "Message Type", "mqttsn.msg.type",
547 FT_UINT8, BASE_HEX | BASE_EXT_STRING, &mqttsn_msgtype_vals_ext, 0,
548 NULL, HFILL }
550 { &hf_mqttsn_dup,
551 { "DUP", "mqttsn.dup",
552 FT_BOOLEAN, 8, TFS(&tfs_yes_no), MQTTSN_MASK_DUP_FLAG,
553 NULL, HFILL }
555 { &hf_mqttsn_will,
556 { "Will", "mqttsn.will",
557 FT_BOOLEAN, 8, TFS(&tfs_yes_no), MQTTSN_MASK_WILL,
558 NULL, HFILL }
560 { &hf_mqttsn_clean_session,
561 { "Clean Session", "mqttsn.clean.session",
562 FT_BOOLEAN, 8, TFS(&tfs_yes_no), MQTTSN_MASK_CLEAN,
563 NULL, HFILL }
565 { &hf_mqttsn_topic_id_type,
566 { "Topic ID Type", "mqttsn.topic.id.type",
567 FT_UINT8, BASE_HEX, VALS(mqttsn_typeid_vals), MQTTSN_MASK_TOPIC_ID_TYPE,
568 NULL, HFILL }
570 { &hf_mqttsn_qos,
571 { "QoS", "mqttsn.qos",
572 FT_UINT8, BASE_HEX, VALS(mqttsn_qos_vals), MQTTSN_MASK_QOS,
573 NULL, HFILL }
575 { &hf_mqttsn_retain,
576 { "Retain", "mqttsn.retain",
577 FT_BOOLEAN, 8, TFS(&tfs_yes_no), MQTTSN_MASK_RETAIN,
578 NULL, HFILL }
580 { &hf_mqttsn_return_code,
581 { "Return Code", "mqttsn.return.code",
582 FT_UINT8, BASE_HEX, VALS(mqttsn_return_vals), 0x0,
583 NULL, HFILL }
585 { &hf_mqttsn_gw_id,
586 { "Gateway ID", "mqttsn.gw.id",
587 FT_UINT8, BASE_DEC, NULL, 0x0,
588 NULL, HFILL }
590 { &hf_mqttsn_gw_addr,
591 { "Gateway Address", "mqttsn.gw.addr",
592 FT_STRING, BASE_NONE, NULL, 0x0,
593 NULL, HFILL }
595 { &hf_mqttsn_adv_interv,
596 { "Advertise Interval", "mqttsn.adv.interv",
597 FT_UINT16, BASE_DEC, NULL, 0x0,
598 NULL, HFILL }
600 { &hf_mqttsn_radius,
601 { "Broadcast Radius", "mqttsn.radius",
602 FT_UINT8, BASE_DEC, NULL, 0x0,
603 NULL, HFILL }
605 { &hf_mqttsn_protocol_id,
606 { "Protocol ID", "mqttsn.protocol.id",
607 FT_UINT8, BASE_HEX, NULL, 0x0,
608 NULL, HFILL }
610 { &hf_mqttsn_topic_id,
611 { "Topic ID", "mqttsn.topic.id",
612 FT_UINT16, BASE_DEC, NULL, 0x0,
613 NULL, HFILL }
615 { &hf_mqttsn_msg_id,
616 { "Message ID", "mqttsn.msg.id",
617 FT_UINT16, BASE_DEC, NULL, 0x0,
618 NULL, HFILL }
620 { &hf_mqttsn_topic,
621 { "Topic Name", "mqttsn.topic",
622 FT_STRING, BASE_NONE, NULL, 0x0,
623 NULL, HFILL }
625 { &hf_mqttsn_topic_name_or_id,
626 { "Topic Name/ID", "mqttsn.topic.name.or.id",
627 FT_STRING, BASE_NONE, NULL, 0x0,
628 NULL, HFILL }
630 { &hf_mqttsn_sleep_timer,
631 { "Sleep Timer", "mqttsn.sleep.timer",
632 FT_UINT16, BASE_DEC, NULL, 0x0,
633 NULL, HFILL }
635 { &hf_mqttsn_will_topic,
636 { "Will Topic", "mqttsn.will.topic",
637 FT_STRING, BASE_NONE, NULL, 0x0,
638 NULL, HFILL }
640 { &hf_mqttsn_will_msg,
641 { "Will Message", "mqttsn.will.msg",
642 FT_STRING, BASE_NONE, NULL, 0x0,
643 NULL, HFILL }
645 { &hf_mqttsn_pub_msg,
646 { "Message", "mqttsn.pub.msg",
647 FT_STRING, BASE_NONE, NULL, 0x0,
648 NULL, HFILL }
650 { &hf_mqttsn_client_id,
651 { "Client ID", "mqttsn.client.id",
652 FT_STRING, BASE_NONE, NULL, 0x0,
653 NULL, HFILL }
655 { &hf_mqttsn_keep_alive,
656 { "Keep Alive", "mqttsn.keep.alive",
657 FT_UINT16, BASE_DEC, NULL, 0x0,
658 NULL, HFILL }
660 { &hf_mqttsn_control_info,
661 { "Control", "mqttsn.control.info",
662 FT_UINT8, BASE_HEX, NULL, MQTTSN_MASK_CONTROL,
663 NULL, HFILL }
665 { &hf_mqttsn_wireless_node_id,
666 { "Wireless Node ID", "mqttsn.wireless.node.id",
667 FT_UINT16, BASE_DEC, NULL, 0x0,
668 NULL, HFILL }
672 /* Setup protocol subtree arrays. */
673 static int* ett_mqttsn[] = {
674 &ett_mqttsn_hdr,
675 &ett_mqttsn_msg,
676 &ett_mqttsn_flags
679 /* Register protocol names and descriptions. */
680 proto_mqttsn = proto_register_protocol("MQ Telemetry Transport Protocol for Sensor Networks", "MQTT-SN", "mqttsn");
682 /* Create the dissector handle. */
683 mqttsn_handle = register_dissector("mqttsn", dissect_mqttsn, proto_mqttsn);
685 /* Register fields and subtrees. */
686 proto_register_field_array(proto_mqttsn, hf_mqttsn, array_length(hf_mqttsn));
687 proto_register_subtree_array(ett_mqttsn, array_length(ett_mqttsn));
690 /* Dissector Handoff */
691 void proto_reg_handoff_mqttsn(void)
693 dissector_add_for_decode_as_with_preference("udp.port", mqttsn_handle);
697 * Editor modelines - https://www.wireshark.org/tools/modelines.html
699 * Local variables:
700 * c-basic-offset: 4
701 * tab-width: 8
702 * indent-tabs-mode: nil
703 * End:
705 * vi: set shiftwidth=4 tabstop=8 expandtab:
706 * :indentSize=4:tabSize=8:noTabs=true: