Coverage Report

Created: 2026-09-28 06:52

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