Additional RAP error code for password changes sent to a BDC, from Devin
[obnox/wireshark/wip.git] / packet-gmrp.c
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  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42
43 #include <glib.h>
44
45 #ifdef NEED_SNPRINTF_H
46 # include "snprintf.h"
47 #endif
48
49 #include <epan/packet.h>
50 #include "llcsaps.h"
51
52 /* Initialize the protocol and registered fields */
53 static int proto_gmrp = -1;
54 static int hf_gmrp_proto_id = -1;
55 static int hf_gmrp_attribute_type = -1;
56 static int hf_gmrp_attribute_length = -1;
57 static int hf_gmrp_attribute_event = -1;
58 static int hf_gmrp_attribute_value_group_membership = -1;
59 static int hf_gmrp_attribute_value_service_requirement = -1;
60 /*static int hf_gmrp_end_of_mark = -1;*/
61
62 /* Initialize the subtree pointers */
63 static gint ett_gmrp = -1;
64 /*static gint ett_gmrp_message = -1;
65 static gint ett_gmrp_attribute_list = -1;
66 static gint ett_gmrp_attribute = -1;*/
67
68 static dissector_handle_t data_handle;
69
70 /* Constant definitions */
71 #define GARP_DEFAULT_PROTOCOL_ID        0x0001
72 #define GARP_END_OF_MARK                        0x00
73
74 #define GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP    0x01
75 #define GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT 0x02
76
77 #define GMRP_SERVICE_REQUIREMENT_FORWARD_ALL                            0x00
78 #define GMRP_SERVICE_REQUIREMENT_FORWARD_ALL_UNREGISTERED       0x01
79
80 static const value_string attribute_type_vals[] = {
81         { GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP    ,"Group Membership" },
82         { GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT ,"Service Requirement" },
83         { 0,                   NULL }
84 };
85
86 /* The length of GMRP LeaveAll attribute should be 2 octets (one for length
87  * and the other for event) */
88 #define GMRP_LENGTH_LEAVEALL            (sizeof(guint8)+sizeof(guint8))
89
90 /* The length of GMRP attribute other than LeaveAll should be:
91 *
92 *  8 bytes for Group Membership (1 for length, 1 for event and 6 for mac address to register)
93 *  or
94 *  3 bytes for Service Requirement (1 for length, 1 for event, 1 for attribute value)
95 *
96  */
97 #define GMRP_GROUP_MEMBERSHIP_NON_LEAVEALL              (sizeof(guint8)+sizeof(guint8)+(6*sizeof(guint8)))
98 #define GMRP_SERVICE_REQUIREMENT_NON_LEAVEALL   (sizeof(guint8)+sizeof(guint8)+sizeof(guint8))
99
100 /* Packet offset definitions */
101 #define GARP_PROTOCOL_ID                0
102
103 /* Event definitions */
104 #define GMRP_EVENT_LEAVEALL             0
105 #define GMRP_EVENT_JOINEMPTY    1
106 #define GMRP_EVENT_JOININ               2
107 #define GMRP_EVENT_LEAVEEMPTY   3
108 #define GMRP_EVENT_LEAVEIN              4
109 #define GMRP_EVENT_EMPTY                5
110
111 static const value_string event_vals[] = {
112         { GMRP_EVENT_LEAVEALL,   "Leave All" },
113         { GMRP_EVENT_JOINEMPTY,  "Join Empty" },
114         { GMRP_EVENT_JOININ,     "Join In" },
115         { GMRP_EVENT_LEAVEEMPTY, "Leave Empty" },
116         { GMRP_EVENT_LEAVEIN,    "Leave In" },
117         { GMRP_EVENT_EMPTY,      "Empty" },
118         { 0,                     NULL }
119 };
120
121
122 /* Code to actually dissect the packets */
123 static void
124 dissect_gmrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
125 {
126     proto_item   *ti;
127     proto_tree   *gmrp_tree;
128     guint16       protocol_id;
129     guint8        octet;
130     guint8                attribute_type;
131     int           msg_index, attr_index, offset = 0, length = tvb_reported_length(tvb);
132     
133     if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
134         col_set_str(pinfo->cinfo, COL_PROTOCOL, "GMRP");
135     
136     if (check_col(pinfo->cinfo, COL_INFO)) 
137         col_set_str(pinfo->cinfo, COL_INFO, "GMRP");
138
139     if (tree)
140     {
141         ti = proto_tree_add_item(tree, proto_gmrp, tvb, 0, length, FALSE);
142
143         gmrp_tree = proto_item_add_subtree(ti, ett_gmrp);
144
145         /* Read in GARP protocol ID */
146         protocol_id = tvb_get_ntohs(tvb, GARP_PROTOCOL_ID);
147     
148         proto_tree_add_uint_format(gmrp_tree, hf_gmrp_proto_id, tvb,
149                                    GARP_PROTOCOL_ID, sizeof(guint16), 
150                                    protocol_id,
151                                    "Protocol Identifier: 0x%04x (%s)", 
152                                    protocol_id,
153                                    protocol_id == GARP_DEFAULT_PROTOCOL_ID ? 
154                                      "GARP Multicast Registration Protocol" :
155                                      "Unknown Protocol");
156
157         /* Currently only one protocol ID is supported */
158         if (protocol_id != GARP_DEFAULT_PROTOCOL_ID)
159         {
160             proto_tree_add_text(gmrp_tree, tvb, GARP_PROTOCOL_ID, sizeof(guint16), 
161  "   (Warning: this version of Ethereal only knows about protocol id = 1)");
162             call_dissector(data_handle,tvb_new_subset(tvb, GARP_PROTOCOL_ID + sizeof(guint16), -1,tvb_reported_length_remaining(tvb,GARP_PROTOCOL_ID + sizeof(guint16))),pinfo, tree);
163             return;
164         }
165
166         offset += sizeof(guint16);
167         length -= sizeof(guint16);
168
169         msg_index = 0;
170
171         /* Begin to parse GARP messages */
172         while (length)
173         {
174                         proto_item   *msg_item;
175                         int           msg_start = offset;
176
177                         /* Read in attribute type. */
178                         attribute_type = octet = tvb_get_guint8(tvb, offset);
179
180                         /* Check for end of mark */
181                         if (octet == GARP_END_OF_MARK)
182                         {
183                                 /* End of GARP PDU */
184                                 if (msg_index)
185                                 {
186                                         proto_tree_add_text(gmrp_tree, tvb, offset, sizeof(guint8),
187                                                         "End of pdu");
188                                         break;
189                                 }
190                                 else
191                                 {
192                                         call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
193                                         return;
194                                 }
195                         }
196
197                         offset += sizeof(guint8);
198                         length -= sizeof(guint8);
199
200                         msg_item = proto_tree_add_text(gmrp_tree, tvb, msg_start, -1,
201                                                    "Message %d", msg_index + 1);
202
203                         proto_tree_add_uint(gmrp_tree, hf_gmrp_attribute_type, tvb,
204                                         msg_start, sizeof(guint8), octet);
205
206                         /* GMRP supports Group Membership and Service Requirement as attribute types */
207                         if ( (octet != GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP) && (octet != GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT) )
208                         {
209                                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
210                                 return;
211                         }
212
213                         attr_index = 0;
214
215                         while (length)
216                         {
217                                 int          attr_start = offset;
218                                 proto_item   *attr_item;
219
220                                 /* Read in attribute length. */
221                                 octet = tvb_get_guint8(tvb, offset);
222
223                                 /* Check for end of mark */
224                                 if (octet == GARP_END_OF_MARK)
225                                 {
226                                         /* If at least one message has been already read, 
227                                          * check for another end of mark.
228                                          */
229                                         if (attr_index)
230                                         {
231                                                 proto_tree_add_text(gmrp_tree, tvb, offset,
232                                                                         sizeof(guint8), "  End of mark");
233
234                                                 offset += sizeof(guint8);
235                                                 length -= sizeof(guint8);
236
237                                                 proto_item_set_len(msg_item, offset - msg_start);
238                                                 break;
239                                         }
240                                         else
241                                         {
242                                                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
243                                                 return;
244                                         }
245                                 }
246                                 else
247                                 {
248                                         guint8   event;
249
250                                         offset += sizeof(guint8);
251                                         length -= sizeof(guint8);
252
253                                         attr_item = proto_tree_add_text(gmrp_tree, tvb,
254                                          attr_start, -1, "  Attribute %d", attr_index + 1);
255
256                                         proto_tree_add_uint(gmrp_tree, hf_gmrp_attribute_length,
257                                          tvb, attr_start, sizeof(guint8), octet);
258
259                                         /* Read in attribute event */
260                                         event = tvb_get_guint8(tvb, offset);
261
262                                         proto_tree_add_uint(gmrp_tree, hf_gmrp_attribute_event,
263                                          tvb, offset, sizeof(guint8), event);
264
265                                         offset += sizeof(guint8);
266                                         length -= sizeof(guint8);
267
268                                         switch (event) {
269
270                                         case GMRP_EVENT_LEAVEALL:
271                                                 if (octet != GMRP_LENGTH_LEAVEALL)
272                                                 {
273                                                         call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
274                                                         return;
275                                                 }
276                                                 break;
277
278                                          case GMRP_EVENT_JOINEMPTY:
279                                          case GMRP_EVENT_JOININ:
280                                          case GMRP_EVENT_LEAVEEMPTY:
281                                          case GMRP_EVENT_LEAVEIN:
282                                          case GMRP_EVENT_EMPTY:
283                                                 if ( (octet != GMRP_GROUP_MEMBERSHIP_NON_LEAVEALL) && (octet != GMRP_SERVICE_REQUIREMENT_NON_LEAVEALL) )
284                                                 {
285                                                         call_dissector(data_handle,tvb_new_subset(tvb, offset, -1,tvb_reported_length_remaining(tvb,offset)),pinfo, tree);
286                                                         return;
287                                                 }
288
289                                         /* Show attribute value */
290
291                                         if ( GMRP_ATTRIBUTE_TYPE_GROUP_MEMBERSHIP == attribute_type )
292                                         {
293                                                 /* Group Membership */
294                                                 proto_tree_add_item(gmrp_tree, hf_gmrp_attribute_value_group_membership,
295                                                         tvb, offset, (6*sizeof(guint8)), FALSE);
296
297                                                 offset += 6*sizeof(guint8);
298                                                 length -= 6*sizeof(guint8);
299                                         }
300                                         else
301                                         if ( GMRP_ATTRIBUTE_TYPE_SERVICE_REQUIREMENT == attribute_type )
302                                         {
303                                                 /* Service Requirement */
304                                                 proto_tree_add_item(gmrp_tree, hf_gmrp_attribute_value_service_requirement,
305                                                         tvb, offset, sizeof(guint8), FALSE);
306                                                         
307                                                 offset += sizeof(guint8);
308                                                 length -= sizeof(guint8);
309                                         }
310                                         else
311                                         {
312                                                 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
313                                                 return;
314                                         }
315
316                                         break;
317
318                                          default:
319                                         call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
320                                         return;
321                                         }
322                                 }
323
324                                 proto_item_set_len(attr_item, offset - attr_start);
325
326                                 attr_index++;
327                         }
328
329                         msg_index++;
330                 }
331     }
332 }
333
334
335
336 /* Register the protocol with Ethereal */
337 void
338 proto_register_gmrp(void)
339 {                
340     static hf_register_info hf[] = {
341         { &hf_gmrp_proto_id,
342             { "Protocol ID", "garp.protocol_id",
343             FT_UINT16,      BASE_HEX,      NULL,  0x0,
344             "" , HFILL }
345         },
346         { &hf_gmrp_attribute_type,
347             { "Type",        "garp.attribute_type",
348             FT_UINT8,        BASE_HEX,      VALS(attribute_type_vals),  0x0,
349             "" , HFILL }
350         },
351         { &hf_gmrp_attribute_length,
352             { "Length",      "garp.attribute_length",
353             FT_UINT8,        BASE_DEC,      NULL,  0x0,
354             "" , HFILL }
355         },
356         { &hf_gmrp_attribute_event,
357             { "Event",       "garp.attribute_event",
358             FT_UINT8,        BASE_DEC,      VALS(event_vals),  0x0,
359             "" , HFILL }
360         },
361         { &hf_gmrp_attribute_value_group_membership,
362             { "Value",       "garp.attribute_value_group_membership",
363             FT_ETHER,        BASE_HEX,      NULL,  0x0,
364             "" , HFILL }
365         },
366         { &hf_gmrp_attribute_value_service_requirement,
367             { "Value",       "garp.attribute_value_service_requirement",
368             FT_UINT8,        BASE_HEX,      NULL,  0x0,
369             "" , HFILL }
370         }
371         
372     };
373
374     static gint *ett[] = {
375         &ett_gmrp
376     };
377
378     /* Register the protocol name and description for GMRP */
379     proto_gmrp = proto_register_protocol("GARP Multicast Registration Protocol", "GMRP", "gmrp");
380
381     /* Required function calls to register the header fields and subtrees
382      * used by GMRP */
383     proto_register_field_array(proto_gmrp, hf, array_length(hf));
384     proto_register_subtree_array(ett, array_length(ett));
385     
386     register_dissector("gmrp", dissect_gmrp, proto_gmrp);
387     
388 }
389
390 void
391 proto_reg_handoff_gmrp(void){
392   data_handle = find_dissector("data");
393 }