Coverage Report

Created: 2026-06-30 07:22

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