Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-lsdp.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-lsdp.c
2
 * Dissector for Lenbrook Service Discovery Protocol
3
 *
4
 * Copyright (c) 2024 by Martin Mayer <martin.mayer@m2-it-solutions.de>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
#include <epan/packet.h>
15
#include <epan/expert.h>
16
#include <wsutil/str_util.h>
17
18
14
#define LSDP_UDP_PORT     11430
19
0
#define LSDP_HEADER_LEN       6
20
0
#define LSDP_HEADER_VER       1
21
0
#define LSDP_MAGIC       "LSDP"
22
23
void proto_register_lsdp(void);
24
void proto_reg_handoff_lsdp(void);
25
26
static dissector_handle_t lsdp_handle;
27
28
static int proto_lsdp;
29
30
/* Header Fields */
31
static int hf_lsdp_header_length;
32
static int hf_lsdp_header_magic_word;
33
static int hf_lsdp_header_proto_version;
34
35
/* Common Message Fields */
36
static int hf_lsdp_msg_length;
37
static int hf_lsdp_msg_type;
38
static int hf_lsdp_node_id_length;
39
static int hf_lsdp_node_id_mac;
40
static int hf_lsdp_node_id;
41
42
/* Query Message */
43
static int hf_lsdp_query;
44
static int hf_lsdp_query_count;
45
static int hf_lsdp_query_class;
46
47
/* Announce Message */
48
static int hf_lsdp_announce;
49
static int hf_lsdp_announce_addr_length;
50
static int hf_lsdp_announce_addr_ipv4;
51
static int hf_lsdp_announce_addr_ipv6;
52
static int hf_lsdp_announce_count;
53
54
/* Announce Message Records */
55
static int hf_lsdp_announce_record;
56
static int hf_lsdp_announce_record_class;
57
static int hf_lsdp_announce_record_count;
58
59
/* Announce Message Record TXT-Records */
60
static int hf_lsdp_announce_record_txt;
61
static int hf_lsdp_announce_record_txt_key_length;
62
static int hf_lsdp_announce_record_txt_key;
63
static int hf_lsdp_announce_record_txt_value_length;
64
static int hf_lsdp_announce_record_txt_value;
65
66
/* Delete Message */
67
static int hf_lsdp_delete;
68
static int hf_lsdp_delete_count;
69
static int hf_lsdp_delete_class;
70
71
/* Trees */
72
static int ett_lsdp;
73
static int ett_lsdp_node_id;
74
static int ett_lsdp_msg;
75
static int ett_lsdp_msg_rec;
76
static int ett_lsdp_msg_rec_txt;
77
78
/* Expert fields */
79
static expert_field ei_lsdp_unknown_msg_type;
80
static expert_field ei_lsdp_invalid_addr_len;
81
82
#define CLASS_PLAYER         0x0001
83
#define CLASS_SERVER         0x0002
84
#define CLASS_PLAYER_MZ      0x0003
85
#define CLASS_SOVI_MFG       0x0004
86
#define CLASS_SOVI_KEYPAD    0x0005
87
#define CLASS_PLAYER_SLAVE   0x0006
88
#define CLASS_REMOTE_APP     0x0007
89
#define CLASS_HUB            0x0008
90
#define CLASS_ALL            0xFFFF
91
92
static const value_string lsdp_class_id_vals[] = {
93
    { CLASS_PLAYER,       "BluOS Player" },
94
    { CLASS_SERVER,       "BluOS Server" },
95
    { CLASS_PLAYER_MZ,    "BluOS Player (secondary in multi-zone)" },
96
    { CLASS_SOVI_MFG,     "sovi-mfg (used for manufacturing testing)" },
97
    { CLASS_SOVI_KEYPAD,  "sovi-keypad" },
98
    { CLASS_PLAYER_SLAVE, "BluOS Player (pair slave)" },
99
    { CLASS_REMOTE_APP,   "Remote Web App (AVR OSD Web Page)" },
100
    { CLASS_HUB,          "BluOS Hub" },
101
    { CLASS_ALL,          "All Classes (Query Message)" },
102
    { 0,                  NULL }
103
};
104
105
static const value_string lsdp_class_id_short_vals[] = {
106
    { CLASS_PLAYER,       "Player" },
107
    { CLASS_SERVER,       "Server" },
108
    { CLASS_PLAYER_MZ,    "Multizone Player" },
109
    { CLASS_SOVI_MFG,     "sovi-mfg" },
110
    { CLASS_SOVI_KEYPAD,  "sovi-keypad" },
111
    { CLASS_PLAYER_SLAVE, "Slave Player" },
112
    { CLASS_REMOTE_APP,   "Web App" },
113
    { CLASS_HUB,          "Hub" },
114
    { CLASS_ALL,          "All Classes" },
115
    { 0,                  NULL }
116
};
117
118
0
#define MSG_TYPE_ANNOUNCE    0x41   // Chr. 'A'
119
0
#define MSG_TYPE_DELETE      0x44   // Chr. 'D'
120
0
#define MSG_TYPE_QUERY_BCR   0x51   // Chr. 'Q'
121
0
#define MSG_TYPE_QUERY_UCR   0x52   // Chr. 'R'
122
123
static const value_string lsdp_msg_type_vals[] = {
124
    { MSG_TYPE_ANNOUNCE,  "Announce Message" },
125
    { MSG_TYPE_DELETE,    "Delete Message" },
126
    { MSG_TYPE_QUERY_BCR, "Query Message (for broadcast response)" },
127
    { MSG_TYPE_QUERY_UCR, "Query Message (for unicast response)" },
128
    { 0,                  NULL }
129
};
130
131
static int
132
dissect_lsdp_node_info(tvbuff_t *tvb, proto_tree *tree, int offset)
133
0
{
134
0
    uint8_t node_id_len;
135
0
    int start_offset = offset;
136
0
    proto_item *pi_id;
137
0
    proto_tree *id_tree;
138
139
0
    node_id_len = tvb_get_uint8(tvb, offset);
140
0
    proto_tree_add_item(tree, hf_lsdp_node_id_length, tvb, offset, 1, ENC_BIG_ENDIAN);
141
0
    offset += 1;
142
143
    /*
144
        Normally, Node-ID is the MAC address of an interface, but COULD also be an arbitrary ID.
145
        Populate Node-ID field and also MAC if length is 6.
146
    */
147
0
    pi_id = proto_tree_add_item(tree, hf_lsdp_node_id, tvb, offset, node_id_len, ENC_NA);
148
0
    if(node_id_len == 6) {
149
0
        id_tree = proto_item_add_subtree(pi_id, ett_lsdp_node_id);
150
0
        proto_tree_add_item(id_tree, hf_lsdp_node_id_mac, tvb, offset, node_id_len, ENC_NA);
151
0
    }
152
0
    offset += node_id_len;
153
154
0
    return offset - start_offset;
155
0
}
156
157
static int
158
dissect_lsdp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
159
0
{
160
0
    uint8_t msg_type, msg_len;
161
0
    uint32_t addr_len, count, txt_count, k_len, v_len, class;
162
0
    int offset_s1, offset_s2;
163
0
    proto_item *msg_item, *rec_item, *txt_item;
164
0
    proto_tree *msg_tree, *rec_tree, *txt_tree;
165
0
    const uint8_t *key, *val;
166
167
0
    msg_len = tvb_get_uint8(tvb, offset);
168
0
    msg_type = tvb_get_uint8(tvb, offset+1);
169
170
0
    col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(msg_type, lsdp_msg_type_vals, "Unknown Message Type"));
171
172
0
    switch (msg_type) {
173
0
        case MSG_TYPE_QUERY_BCR:
174
0
        case MSG_TYPE_QUERY_UCR:
175
176
0
            msg_item = proto_tree_add_item(tree, hf_lsdp_query, tvb, offset, msg_len, ENC_NA);
177
0
            msg_tree = proto_item_add_subtree(msg_item, ett_lsdp_msg);
178
179
0
            proto_tree_add_item(msg_tree, hf_lsdp_msg_length, tvb, offset, 1, ENC_BIG_ENDIAN);
180
0
            offset += 1;
181
182
0
            proto_tree_add_item(msg_tree, hf_lsdp_msg_type, tvb, offset, 1, ENC_BIG_ENDIAN);
183
0
            offset += 1;
184
185
0
            proto_tree_add_item_ret_uint(msg_tree, hf_lsdp_query_count, tvb, offset, 1, ENC_BIG_ENDIAN, &count);
186
0
            offset += 1;
187
188
0
            for(uint32_t i=0; i < count; i++) {
189
0
                proto_tree_add_item_ret_uint(msg_tree, hf_lsdp_query_class, tvb, offset, 2, ENC_BIG_ENDIAN, &class);
190
0
                col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", val_to_str_const(class, lsdp_class_id_short_vals, "Unknown Class"));
191
0
                offset += 2;
192
0
            }
193
194
0
            break;
195
196
0
        case MSG_TYPE_ANNOUNCE:
197
198
0
            msg_item = proto_tree_add_item(tree, hf_lsdp_announce, tvb, offset, msg_len, ENC_NA);
199
0
            msg_tree = proto_item_add_subtree(msg_item, ett_lsdp_msg);
200
201
0
            proto_tree_add_item(msg_tree, hf_lsdp_msg_length, tvb, offset, 1, ENC_BIG_ENDIAN);
202
0
            offset += 1;
203
204
0
            proto_tree_add_item(msg_tree, hf_lsdp_msg_type, tvb, offset, 1, ENC_BIG_ENDIAN);
205
0
            offset += 1;
206
207
0
            offset += dissect_lsdp_node_info(tvb, msg_tree, offset);
208
209
0
            proto_tree_add_item_ret_uint(msg_tree, hf_lsdp_announce_addr_length, tvb, offset, 1, ENC_BIG_ENDIAN, &addr_len);
210
0
            offset += 1;
211
212
0
            if(addr_len == 4) {
213
0
                proto_tree_add_item(msg_tree, hf_lsdp_announce_addr_ipv4, tvb, offset, addr_len, ENC_NA);
214
0
            } else if (addr_len==16) {
215
0
                proto_tree_add_item(msg_tree, hf_lsdp_announce_addr_ipv6, tvb, offset, addr_len, ENC_NA);
216
0
            } else {
217
0
                expert_add_info(pinfo, msg_tree, &ei_lsdp_invalid_addr_len);
218
0
            }
219
0
            offset += addr_len;
220
221
0
            proto_tree_add_item_ret_uint(msg_tree, hf_lsdp_announce_count, tvb, offset, 1, ENC_BIG_ENDIAN, &count);
222
0
            proto_item_append_text(msg_item, " (%d Record%s)", count, plurality(count, "", "s"));
223
0
            offset += 1;
224
225
            /* Loop Announce Records */
226
0
            for(uint32_t i=0; i < count; i++) {
227
228
0
                offset_s1 = offset;
229
230
0
                rec_item = proto_tree_add_item(msg_tree, hf_lsdp_announce_record, tvb, offset, 0, ENC_NA);
231
0
                rec_tree = proto_item_add_subtree(rec_item, ett_lsdp_msg_rec);
232
233
0
                proto_tree_add_item_ret_uint(rec_tree, hf_lsdp_announce_record_class, tvb, offset, 2, ENC_BIG_ENDIAN, &class);
234
0
                offset += 2;
235
236
0
                col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", val_to_str_const(class, lsdp_class_id_short_vals, "Unknown Class"));
237
238
0
                proto_tree_add_item_ret_uint(rec_tree, hf_lsdp_announce_record_count, tvb, offset, 1, ENC_BIG_ENDIAN, &txt_count);
239
0
                proto_item_append_text(rec_item, " (%d TXT-Record%s)", txt_count, plurality(txt_count, "", "s"));
240
0
                offset += 1;
241
242
                /* Loop TXT records (key-value pairs) */
243
0
                for(uint32_t j=0; j < txt_count; j++) {
244
245
0
                    offset_s2 = offset;
246
247
0
                    txt_item = proto_tree_add_item(rec_tree, hf_lsdp_announce_record_txt, tvb, offset, 0, ENC_NA);
248
0
                    txt_tree = proto_item_add_subtree(txt_item, ett_lsdp_msg_rec_txt);
249
250
0
                    proto_tree_add_item_ret_uint(txt_tree, hf_lsdp_announce_record_txt_key_length, tvb, offset, 1, ENC_BIG_ENDIAN, &k_len);
251
0
                    offset += 1;
252
253
0
                    proto_tree_add_item_ret_string(txt_tree, hf_lsdp_announce_record_txt_key, tvb, offset, k_len, ENC_UTF_8, pinfo->pool, &key);
254
0
                    offset += k_len;
255
256
0
                    proto_tree_add_item_ret_uint(txt_tree, hf_lsdp_announce_record_txt_value_length, tvb, offset, 1, ENC_BIG_ENDIAN, &v_len);
257
0
                    offset += 1;
258
259
0
                    proto_tree_add_item_ret_string(txt_tree, hf_lsdp_announce_record_txt_value, tvb, offset, v_len, ENC_UTF_8, pinfo->pool, &val);
260
0
                    offset += v_len;
261
262
0
                    proto_item_append_text(txt_item, " (%s: %s)", key, val);
263
0
                    proto_item_set_len(txt_item, offset - offset_s2);
264
265
                    /* Keys of interest for info column */
266
0
                    if(
267
0
                        strcmp(key, "name") == 0 ||
268
0
                        strcmp(key, "model") == 0 ||
269
0
                        strcmp(key, "version") == 0
270
0
                    ) {
271
0
                        col_append_fstr(pinfo->cinfo, COL_INFO, " %s='%s'", key, val);
272
0
                    }
273
0
                }
274
275
0
                proto_item_set_len(rec_item, offset - offset_s1);
276
0
            }
277
278
0
            break;
279
280
0
        case MSG_TYPE_DELETE:
281
282
0
            msg_item = proto_tree_add_item(tree, hf_lsdp_delete, tvb, offset, msg_len, ENC_NA);
283
0
            msg_tree = proto_item_add_subtree(msg_item, ett_lsdp_msg);
284
285
0
            proto_tree_add_item(msg_tree, hf_lsdp_msg_length, tvb, offset, 1, ENC_BIG_ENDIAN);
286
0
            offset += 1;
287
288
0
            proto_tree_add_item(msg_tree, hf_lsdp_msg_type, tvb, offset, 1, ENC_BIG_ENDIAN);
289
0
            offset += 1;
290
291
0
            offset += dissect_lsdp_node_info(tvb, msg_tree, offset);
292
293
0
            proto_tree_add_item_ret_uint(msg_tree, hf_lsdp_delete_count, tvb, offset, 1, ENC_BIG_ENDIAN, &count);
294
0
            offset += 1;
295
296
0
            for(uint32_t i=0; i < count; i++) {
297
0
                proto_tree_add_item_ret_uint(msg_tree, hf_lsdp_delete_class, tvb, offset, 2, ENC_BIG_ENDIAN, &class);
298
0
                col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", val_to_str_const(class, lsdp_class_id_short_vals, "Unknown Class"));
299
0
                offset += 2;
300
0
            }
301
302
0
            break;
303
304
0
        default:
305
0
            expert_add_info(pinfo, tree, &ei_lsdp_unknown_msg_type);
306
0
            break;
307
0
    }
308
309
0
    return msg_len;
310
0
}
311
312
static int
313
dissect_lsdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
314
0
{
315
0
    int offset;
316
0
    proto_item *ti;
317
0
    proto_tree *lsdp_tree;
318
319
    /* Basic tests for LSDP */
320
0
    if(
321
0
        tvb_reported_length(tvb) < LSDP_HEADER_LEN ||                   // Header must be available
322
0
        tvb_get_uint8(tvb, 0) != LSDP_HEADER_LEN ||                     // Header length must be fixed
323
0
        tvb_memeql(tvb, 1, LSDP_MAGIC, strlen(LSDP_MAGIC)) != 0 ||      // Magic Word must match
324
0
        tvb_get_uint8(tvb, 5) != LSDP_HEADER_VER                        // We only support version 1
325
0
    )
326
0
        return 0;
327
328
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "LSDP");
329
0
    col_clear(pinfo->cinfo,COL_INFO);
330
331
0
    ti = proto_tree_add_item(tree, proto_lsdp, tvb, 0, 0, ENC_NA);
332
0
    lsdp_tree = proto_item_add_subtree(ti, ett_lsdp);
333
334
0
    offset = 0;
335
336
0
    proto_tree_add_item(lsdp_tree, hf_lsdp_header_length, tvb, offset, 1, ENC_BIG_ENDIAN);
337
0
    offset += 1;
338
339
0
    proto_tree_add_item(lsdp_tree, hf_lsdp_header_magic_word, tvb, offset, 4, ENC_ASCII);
340
0
    offset += 4;
341
342
0
    proto_tree_add_item(lsdp_tree, hf_lsdp_header_proto_version, tvb, offset, 1, ENC_BIG_ENDIAN);
343
0
    offset += 1;
344
345
    /* One packet can contain multiple messages */
346
0
    while((unsigned)offset < tvb_reported_length(tvb)) {
347
348
        /*
349
            Ensure there are enough bytes remaining for another message
350
            - at least 2 bytes (length, type) must be available
351
            - length must not be zero - ensure offset to advance
352
        */
353
0
        if(
354
0
            tvb_reported_length_remaining(tvb, offset) < 2 ||
355
0
            tvb_get_uint8(tvb, offset) == 0
356
0
        )
357
0
            break;
358
359
0
        offset += dissect_lsdp_message(tvb, pinfo, lsdp_tree, offset);
360
361
0
    }
362
363
0
    proto_item_set_len(ti, offset);
364
0
    return offset;
365
0
}
366
367
void
368
proto_register_lsdp(void)
369
14
{
370
14
    static hf_register_info hf[] = {
371
14
        { &hf_lsdp_header_length,
372
14
            { "Header Length", "lsdp.header.length",
373
14
            FT_UINT8, BASE_DEC,
374
14
            NULL, 0x0,
375
14
            NULL, HFILL }
376
14
        },
377
14
        { &hf_lsdp_header_magic_word,
378
14
            { "Magic Word", "lsdp.header.magic_word",
379
14
            FT_STRING, BASE_NONE,
380
14
            NULL, 0x0,
381
14
            NULL, HFILL }
382
14
        },
383
14
        { &hf_lsdp_header_proto_version,
384
14
            { "Protocol Version", "lsdp.header.proto_version",
385
14
            FT_UINT8, BASE_DEC,
386
14
            NULL, 0x0,
387
14
            NULL, HFILL }
388
14
        },
389
14
        { &hf_lsdp_msg_length,
390
14
            { "Message Length", "lsdp.msg.length",
391
14
            FT_UINT8, BASE_DEC,
392
14
            NULL, 0x0,
393
14
            NULL, HFILL }
394
14
        },
395
14
        { &hf_lsdp_msg_type,
396
14
            { "Message Type", "lsdp.msg.type",
397
14
            FT_UINT8, BASE_HEX,
398
14
            VALS(lsdp_msg_type_vals), 0x0,
399
14
            NULL, HFILL }
400
14
        },
401
14
        { &hf_lsdp_node_id_length,
402
14
            { "Node ID Length", "lsdp.node_id.length",
403
14
            FT_UINT8, BASE_DEC,
404
14
            NULL, 0x0,
405
14
            NULL, HFILL }
406
14
        },
407
14
        { &hf_lsdp_node_id_mac,
408
14
            { "Node ID (MAC)", "lsdp.node_id.mac",
409
14
            FT_ETHER, BASE_NONE,
410
14
            NULL, 0x0,
411
14
            NULL, HFILL }
412
14
        },
413
14
        { &hf_lsdp_node_id,
414
14
            { "Node ID", "lsdp.node_id",
415
14
            FT_BYTES, BASE_NONE,
416
14
            NULL, 0x0,
417
14
            NULL, HFILL }
418
14
        },
419
14
        { &hf_lsdp_query,
420
14
            { "Query Message", "lsdp.query",
421
14
            FT_NONE, BASE_NONE,
422
14
            NULL, 0x0,
423
14
            NULL, HFILL }
424
14
        },
425
14
        { &hf_lsdp_query_count,
426
14
            { "Count", "lsdp.query.count",
427
14
            FT_UINT8, BASE_DEC,
428
14
            NULL, 0x0,
429
14
            NULL, HFILL }
430
14
        },
431
14
        { &hf_lsdp_query_class,
432
14
            { "Class", "lsdp.query.class",
433
14
            FT_UINT16, BASE_HEX,
434
14
            VALS(lsdp_class_id_vals), 0x0,
435
14
            NULL, HFILL }
436
14
        },
437
14
        { &hf_lsdp_announce,
438
14
            { "Announce Message", "lsdp.announce",
439
14
            FT_NONE, BASE_NONE,
440
14
            NULL, 0x0,
441
14
            NULL, HFILL }
442
14
        },
443
14
        { &hf_lsdp_announce_addr_length,
444
14
            { "Address Length", "lsdp.announce.addr.length",
445
14
            FT_UINT8, BASE_DEC,
446
14
            NULL, 0x0,
447
14
            NULL, HFILL }
448
14
        },
449
14
        { &hf_lsdp_announce_addr_ipv4,
450
14
            { "Address", "lsdp.announce.addr_ipv4",
451
14
            FT_IPv4, BASE_NONE,
452
14
            NULL, 0x0,
453
14
            NULL, HFILL }
454
14
        },
455
14
        { &hf_lsdp_announce_addr_ipv6,
456
14
            { "Address", "lsdp.announce.addr_ipv6",
457
14
            FT_IPv6, BASE_NONE,
458
14
            NULL, 0x0,
459
14
            NULL, HFILL }
460
14
        },
461
14
        { &hf_lsdp_announce_count,
462
14
            { "Count", "lsdp.announce.count",
463
14
            FT_UINT8, BASE_DEC,
464
14
            NULL, 0x0,
465
14
            NULL, HFILL }
466
14
        },
467
14
        { &hf_lsdp_announce_record,
468
14
            { "Announce Record", "lsdp.announce.record",
469
14
            FT_NONE, BASE_NONE,
470
14
            NULL, 0x0,
471
14
            NULL, HFILL }
472
14
        },
473
14
        { &hf_lsdp_announce_record_class,
474
14
            { "Class", "lsdp.announce.record.class",
475
14
            FT_UINT16, BASE_HEX,
476
14
            VALS(lsdp_class_id_vals), 0x0,
477
14
            NULL, HFILL }
478
14
        },
479
14
        { &hf_lsdp_announce_record_count,
480
14
            { "Count", "lsdp.announce.record.count",
481
14
            FT_UINT8, BASE_DEC,
482
14
            NULL, 0x0,
483
14
            NULL, HFILL }
484
14
        },
485
14
        { &hf_lsdp_announce_record_txt,
486
14
            { "TXT-Record", "lsdp.announce.record.txt",
487
14
            FT_NONE, BASE_NONE,
488
14
            NULL, 0x0,
489
14
            NULL, HFILL }
490
14
        },
491
14
        { &hf_lsdp_announce_record_txt_key_length,
492
14
            { "Key Length", "lsdp.announce.record.txt.key.length",
493
14
            FT_UINT8, BASE_DEC,
494
14
            NULL, 0x0,
495
14
            NULL, HFILL }
496
14
        },
497
14
        { &hf_lsdp_announce_record_txt_key,
498
14
            { "Key", "lsdp.announce.record.txt.key",
499
14
            FT_STRING, BASE_NONE,
500
14
            NULL, 0x0,
501
14
            NULL, HFILL }
502
14
        },
503
14
        { &hf_lsdp_announce_record_txt_value_length,
504
14
            { "Value Length", "lsdp.announce.record.txt.val.length",
505
14
            FT_UINT8, BASE_DEC,
506
14
            NULL, 0x0,
507
14
            NULL, HFILL }
508
14
        },
509
14
        { &hf_lsdp_announce_record_txt_value,
510
14
            { "Key", "lsdp.announce.record.txt.val",
511
14
            FT_STRING, BASE_NONE,
512
14
            NULL, 0x0,
513
14
            NULL, HFILL }
514
14
        },
515
14
        { &hf_lsdp_delete,
516
14
            { "Delete Message", "lsdp.delete",
517
14
            FT_NONE, BASE_NONE,
518
14
            NULL, 0x0,
519
14
            NULL, HFILL }
520
14
        },
521
14
        { &hf_lsdp_delete_count,
522
14
            { "Count", "lsdp.delete.count",
523
14
            FT_UINT8, BASE_DEC,
524
14
            NULL, 0x0,
525
14
            NULL, HFILL }
526
14
        },
527
14
        { &hf_lsdp_delete_class,
528
14
            { "Class", "lsdp.delete.class",
529
14
            FT_UINT16, BASE_HEX,
530
14
            VALS(lsdp_class_id_vals), 0x0,
531
14
            NULL, HFILL }
532
14
        }
533
14
    };
534
535
14
    static ei_register_info ei[] = {
536
14
        { &ei_lsdp_unknown_msg_type,
537
14
            { "lsdp.unknown_msg_type", PI_MALFORMED, PI_ERROR,
538
14
                "Message is of invalid type", EXPFILL }
539
14
        },
540
14
        { &ei_lsdp_invalid_addr_len,
541
14
            { "lsdp.invalid_addr_len", PI_MALFORMED, PI_ERROR,
542
14
                "Address has an invalid length", EXPFILL }
543
14
        }
544
14
    };
545
546
14
    static int *ett[] = {
547
14
        &ett_lsdp,
548
14
        &ett_lsdp_node_id,
549
14
        &ett_lsdp_msg,
550
14
        &ett_lsdp_msg_rec,
551
14
        &ett_lsdp_msg_rec_txt
552
14
    };
553
554
14
    expert_module_t* expert_lsdp;
555
556
14
    proto_lsdp = proto_register_protocol ("Lenbrook Service Discovery Protocol", "LSDP", "lsdp");
557
558
14
    proto_register_field_array(proto_lsdp, hf, array_length(hf));
559
14
    proto_register_subtree_array(ett, array_length(ett));
560
561
14
    expert_lsdp = expert_register_protocol(proto_lsdp);
562
14
    expert_register_field_array(expert_lsdp, ei, array_length(ei));
563
564
14
    lsdp_handle = register_dissector("lsdp", dissect_lsdp, proto_lsdp);
565
14
}
566
567
void
568
proto_reg_handoff_lsdp(void)
569
14
{
570
14
    dissector_add_uint("udp.port", LSDP_UDP_PORT, lsdp_handle);
571
14
}
572
573
/*
574
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
575
 *
576
 * Local variables:
577
 * c-basic-offset: 4
578
 * tab-width: 8
579
 * indent-tabs-mode: nil
580
 * End:
581
 *
582
 * vi: set shiftwidth=4 tabstop=8 expandtab:
583
 * :indentSize=4:tabSize=8:noTabs=true:
584
 */