Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-gmrp.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-gmrp.c
2
 * Routines for GMRP (GARP Multicast Registration Protocol) dissection
3
 * Copyright 2001, Markus Seehofer <mseehofe@nt.hirschmann.de>
4
 *
5
 * Based on the code from packet-gvrp.c (GVRP) from
6
 * Kevin Shi <techishi@ms22.hinet.net> Copyright 2000
7
 *
8
 * Wireshark - Network traffic analyzer
9
 * By Gerald Combs <gerald@wireshark.org>
10
 * Copyright 1998 Gerald Combs
11
 *
12
 * SPDX-License-Identifier: GPL-2.0-or-later
13
 */
14
15
#include "config.h"
16
17
#include <epan/packet.h>
18
#include <epan/expert.h>
19
#include <epan/llcsaps.h>
20
21
void proto_register_gmrp(void);
22
23
/* Initialize the protocol and registered fields */
24
static int proto_gmrp;
25
static int hf_gmrp_proto_id;
26
static int hf_gmrp_attribute_type;
27
static int hf_gmrp_attribute_length;
28
static int hf_gmrp_attribute_event;
29
static int hf_gmrp_attribute_value_group_membership;
30
static int hf_gmrp_attribute_value_service_requirement;
31
static int hf_gmrp_end_of_mark;
32
33
/* Initialize the subtree pointers */
34
static int ett_gmrp;
35
static int ett_gmrp_message;
36
static int ett_gmrp_attribute_list;
37
/*static int ett_gmrp_attribute;*/
38
39
static expert_field ei_gmrp_proto_id;
40
41
42
/* Constant definitions */
43
0
#define GARP_DEFAULT_PROTOCOL_ID    0x0001
44
0
#define GARP_END_OF_MARK            0x00
45
46
0
#define GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP    0x01
47
0
#define GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT 0x02
48
49
#define GMRP_SERVICE_REQUIREMENT_FORWARD_ALL                0x00
50
#define GMRP_SERVICE_REQUIREMENT_FORWARD_ALL_UNREGISTERED   0x01
51
52
static const value_string attribute_type_vals[] = {
53
    { GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP    ,"Group Membership" },
54
    { GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT ,"Service Requirement" },
55
    { 0,                   NULL }
56
};
57
58
/* The length of GMRP LeaveAll attribute should be 2 octets (one for length
59
 * and the other for event) */
60
0
#define GMRP_LENGTH_LEAVEALL        (int)(sizeof(uint8_t)+sizeof(uint8_t))
61
62
/* The length of GMRP attribute other than LeaveAll should be:
63
*
64
*  8 bytes for Group Membership (1 for length, 1 for event and 6 for mac address to register)
65
*  or
66
*  3 bytes for Service Requirement (1 for length, 1 for event, 1 for attribute value)
67
*
68
 */
69
0
#define GMRP_GROUP_MEMBERSHIP_NON_LEAVEALL      (int)(sizeof(uint8_t)+sizeof(uint8_t)+(6*sizeof(uint8_t)))
70
0
#define GMRP_SERVICE_REQUIREMENT_NON_LEAVEALL   (int)(sizeof(uint8_t)+sizeof(uint8_t)+sizeof(uint8_t))
71
72
/* Packet offset definitions */
73
0
#define GARP_PROTOCOL_ID        0
74
75
/* Event definitions */
76
0
#define GMRP_EVENT_LEAVEALL     0
77
0
#define GMRP_EVENT_JOINEMPTY    1
78
0
#define GMRP_EVENT_JOININ       2
79
0
#define GMRP_EVENT_LEAVEEMPTY   3
80
0
#define GMRP_EVENT_LEAVEIN      4
81
0
#define GMRP_EVENT_EMPTY        5
82
83
static const value_string event_vals[] = {
84
    { GMRP_EVENT_LEAVEALL,   "Leave All" },
85
    { GMRP_EVENT_JOINEMPTY,  "Join Empty" },
86
    { GMRP_EVENT_JOININ,     "Join In" },
87
    { GMRP_EVENT_LEAVEEMPTY, "Leave Empty" },
88
    { GMRP_EVENT_LEAVEIN,    "Leave In" },
89
    { GMRP_EVENT_EMPTY,      "Empty" },
90
    { 0,                     NULL }
91
};
92
93
94
/* Code to actually dissect the packets */
95
static int
96
dissect_gmrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
97
0
{
98
0
    proto_item   *ti;
99
0
    proto_tree   *gmrp_tree, *msg_tree, *attr_tree;
100
0
    uint16_t      protocol_id;
101
0
    uint8_t       octet;
102
0
    uint8_t       attribute_type;
103
0
    int           msg_index, attr_index, offset = 0, length = tvb_reported_length(tvb);
104
105
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "GMRP");
106
107
0
    col_set_str(pinfo->cinfo, COL_INFO, "GMRP");
108
109
0
        ti = proto_tree_add_item(tree, proto_gmrp, tvb, 0, -1, ENC_NA);
110
111
0
        gmrp_tree = proto_item_add_subtree(ti, ett_gmrp);
112
113
        /* Read in GARP protocol ID */
114
0
        protocol_id = tvb_get_ntohs(tvb, GARP_PROTOCOL_ID);
115
116
0
        ti = proto_tree_add_uint_format_value(gmrp_tree, hf_gmrp_proto_id, tvb,
117
0
                                   GARP_PROTOCOL_ID, 2, protocol_id,
118
0
                                   "0x%04x (%s)", protocol_id,
119
0
                                   protocol_id == GARP_DEFAULT_PROTOCOL_ID ?
120
0
                                     "GARP Multicast Registration Protocol" :
121
0
                                     "Unknown Protocol");
122
123
        /* Currently only one protocol ID is supported */
124
0
        if (protocol_id != GARP_DEFAULT_PROTOCOL_ID)
125
0
        {
126
0
            expert_add_info(pinfo, ti, &ei_gmrp_proto_id);
127
0
            call_data_dissector(tvb_new_subset_remaining(tvb, GARP_PROTOCOL_ID + 2),
128
0
                pinfo, tree);
129
0
            return tvb_captured_length(tvb);
130
0
        }
131
132
0
        offset += 2;
133
0
        length -= 2;
134
135
0
        msg_index = 0;
136
137
        /* Begin to parse GARP messages */
138
0
        while (length)
139
0
        {
140
0
            proto_item   *msg_item;
141
0
            int           msg_start = offset;
142
143
            /* Read in attribute type. */
144
0
            attribute_type = octet = tvb_get_uint8(tvb, offset);
145
146
            /* Check for end of mark */
147
0
            if (octet == GARP_END_OF_MARK)
148
0
            {
149
                /* End of GARP PDU */
150
0
                if (msg_index)
151
0
                {
152
0
                    proto_tree_add_uint_format(gmrp_tree, hf_gmrp_end_of_mark, tvb, offset, 1, octet, "End of pdu");
153
0
                    break;
154
0
                }
155
0
                else
156
0
                {
157
0
                    call_data_dissector(tvb_new_subset_remaining(tvb, offset),
158
0
                                   pinfo, tree);
159
0
                    return tvb_captured_length(tvb);
160
0
                }
161
0
            }
162
163
0
            offset += 1;
164
0
            length -= 1;
165
166
0
            msg_tree = proto_tree_add_subtree_format(gmrp_tree, tvb, msg_start, -1,
167
0
                                           ett_gmrp_message, &msg_item, "Message %d", msg_index + 1);
168
169
0
            proto_tree_add_uint(msg_tree, hf_gmrp_attribute_type, tvb,
170
0
                                msg_start, 1, octet);
171
172
            /* GMRP supports Group Membership and Service Requirement as attribute types */
173
0
            if ( (octet != GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP) && (octet != GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT) )
174
0
            {
175
0
                call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo,
176
0
                               tree);
177
0
                return tvb_captured_length(tvb);
178
0
            }
179
180
0
            attr_index = 0;
181
182
0
            while (length)
183
0
            {
184
0
                int          attr_start = offset;
185
0
                proto_item   *attr_item;
186
187
                /* Read in attribute length. */
188
0
                octet = tvb_get_uint8(tvb, offset);
189
190
                /* Check for end of mark */
191
0
                if (octet == GARP_END_OF_MARK)
192
0
                {
193
                    /* If at least one message has been already read,
194
                     * check for another end of mark.
195
                     */
196
0
                    if (attr_index)
197
0
                    {
198
0
                        proto_tree_add_uint_format(msg_tree, hf_gmrp_end_of_mark, tvb, offset,
199
0
                                            1, octet, "  End of mark");
200
201
0
                        offset += 1;
202
0
                        length -= 1;
203
204
0
                        proto_item_set_len(msg_item, offset - msg_start);
205
0
                        break;
206
0
                    }
207
0
                    else
208
0
                    {
209
0
                        call_data_dissector(tvb_new_subset_remaining(tvb, offset),
210
0
                                       pinfo, tree);
211
0
                        return tvb_captured_length(tvb);
212
0
                    }
213
0
                }
214
0
                else
215
0
                {
216
0
                    uint8_t  event;
217
218
0
                    offset += 1;
219
0
                    length -= 1;
220
221
0
                    attr_tree = proto_tree_add_subtree_format(msg_tree, tvb, attr_start, -1,
222
0
                                                    ett_gmrp_attribute_list, &attr_item, "  Attribute %d", attr_index + 1);
223
224
0
                    proto_tree_add_uint(attr_tree, hf_gmrp_attribute_length,
225
0
                                        tvb, attr_start, 1, octet);
226
227
                    /* Read in attribute event */
228
0
                    event = tvb_get_uint8(tvb, offset);
229
230
0
                    proto_tree_add_uint(attr_tree, hf_gmrp_attribute_event,
231
0
                                        tvb, offset, 1, event);
232
233
0
                    offset += 1;
234
0
                    length -= 1;
235
236
0
                    switch (event) {
237
238
0
                    case GMRP_EVENT_LEAVEALL:
239
0
                        if (octet != GMRP_LENGTH_LEAVEALL)
240
0
                        {
241
0
                            call_data_dissector(tvb_new_subset_remaining(tvb, offset),
242
0
                                           pinfo, tree);
243
0
                            return tvb_captured_length(tvb);
244
0
                        }
245
0
                        break;
246
247
0
                    case GMRP_EVENT_JOINEMPTY:
248
0
                    case GMRP_EVENT_JOININ:
249
0
                    case GMRP_EVENT_LEAVEEMPTY:
250
0
                    case GMRP_EVENT_LEAVEIN:
251
0
                    case GMRP_EVENT_EMPTY:
252
0
                        if ( (octet != GMRP_GROUP_MEMBERSHIP_NON_LEAVEALL) &&
253
0
                             (octet != GMRP_SERVICE_REQUIREMENT_NON_LEAVEALL) )
254
0
                        {
255
0
                            call_data_dissector(tvb_new_subset_remaining(tvb, offset),
256
0
                                           pinfo, tree);
257
0
                            return tvb_captured_length(tvb);
258
0
                        }
259
260
                        /* Show attribute value */
261
262
0
                        if ( GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP == attribute_type )
263
0
                        {
264
                            /* Group Membership */
265
0
                            proto_tree_add_item(attr_tree, hf_gmrp_attribute_value_group_membership,
266
0
                                                tvb, offset, 6, ENC_NA);
267
268
0
                            offset += 6;
269
0
                            length -= 6;
270
0
                        }
271
0
                        else
272
0
                            if ( GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT == attribute_type )
273
0
                            {
274
                                /* Service Requirement */
275
0
                                proto_tree_add_item(attr_tree, hf_gmrp_attribute_value_service_requirement,
276
0
                                                    tvb, offset, 1, ENC_BIG_ENDIAN);
277
278
0
                                offset += 1;
279
0
                                length -= 1;
280
0
                            }
281
0
                            else
282
0
                            {
283
0
                                call_data_dissector(tvb_new_subset_remaining(tvb, offset),
284
0
                                               pinfo, tree);
285
0
                                return tvb_captured_length(tvb);
286
0
                            }
287
288
0
                        break;
289
290
0
                    default:
291
0
                        call_data_dissector(tvb_new_subset_remaining(tvb, offset),
292
0
                                       pinfo, tree);
293
0
                        return tvb_captured_length(tvb);
294
0
                    }
295
0
                }
296
297
0
                proto_item_set_len(attr_item, offset - attr_start);
298
299
0
                attr_index++;
300
0
            }
301
302
0
            msg_index++;
303
0
        }
304
0
        return tvb_captured_length(tvb);
305
0
}
306
307
308
309
/* Register the protocol with Wireshark */
310
void
311
proto_register_gmrp(void)
312
14
{
313
14
    static hf_register_info hf[] = {
314
14
        { &hf_gmrp_proto_id,
315
14
          { "Protocol Identifier", "gmrp.protocol_id",
316
14
            FT_UINT16,      BASE_HEX,      NULL,  0x0,
317
14
            NULL , HFILL }
318
14
        },
319
14
        { &hf_gmrp_attribute_type,
320
14
          { "Type",        "gmrp.attribute_type",
321
14
            FT_UINT8,        BASE_HEX,      VALS(attribute_type_vals),  0x0,
322
14
            NULL , HFILL }
323
14
        },
324
14
        { &hf_gmrp_attribute_length,
325
14
          { "Length",      "gmrp.attribute_length",
326
14
            FT_UINT8,        BASE_DEC,      NULL,  0x0,
327
14
            NULL , HFILL }
328
14
        },
329
14
        { &hf_gmrp_attribute_event,
330
14
          { "Event",       "gmrp.attribute_event",
331
14
            FT_UINT8,        BASE_DEC,      VALS(event_vals),  0x0,
332
14
            NULL , HFILL }
333
14
        },
334
14
        { &hf_gmrp_attribute_value_group_membership,
335
14
          { "Value",       "gmrp.attribute_value_group_membership",
336
14
            FT_ETHER,        BASE_NONE,      NULL,  0x0,
337
14
            NULL , HFILL }
338
14
        },
339
14
        { &hf_gmrp_attribute_value_service_requirement,
340
14
          { "Value",       "gmrp.attribute_value_service_requirement",
341
14
            FT_UINT8,        BASE_HEX,      NULL,  0x0,
342
14
            NULL , HFILL }
343
14
        },
344
14
        { &hf_gmrp_end_of_mark,
345
14
          { "End of mark",       "gmrp.end_of_mark",
346
14
            FT_UINT8,        BASE_HEX,      NULL,  0x0,
347
14
            NULL , HFILL }
348
14
        }
349
350
14
    };
351
352
14
    static int *ett[] = {
353
14
        &ett_gmrp,
354
14
        &ett_gmrp_message,
355
14
        &ett_gmrp_attribute_list
356
14
    };
357
358
14
    static ei_register_info ei[] = {
359
14
        { &ei_gmrp_proto_id, { "gmrp.protocol_id.not_gmrp", PI_UNDECODED, PI_WARN, "This version of Wireshark only knows about protocol id = 1", EXPFILL }},
360
14
    };
361
362
14
    expert_module_t* expert_gmrp;
363
364
    /* Register the protocol name and description for GMRP */
365
14
    proto_gmrp = proto_register_protocol("GARP Multicast Registration Protocol", "GMRP", "gmrp");
366
367
    /* Required function calls to register the header fields and subtrees
368
     * used by GMRP */
369
14
    proto_register_field_array(proto_gmrp, hf, array_length(hf));
370
14
    proto_register_subtree_array(ett, array_length(ett));
371
14
    expert_gmrp = expert_register_protocol(proto_gmrp);
372
14
    expert_register_field_array(expert_gmrp, ei, array_length(ei));
373
374
14
    register_dissector("gmrp", dissect_gmrp, proto_gmrp);
375
376
14
}
377
378
/*
379
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
380
 *
381
 * Local variables:
382
 * c-basic-offset: 4
383
 * tab-width: 8
384
 * indent-tabs-mode: nil
385
 * End:
386
 *
387
 * vi: set shiftwidth=4 tabstop=8 expandtab:
388
 * :indentSize=4:tabSize=8:noTabs=true:
389
 */