Define some fcns & vars as static...
[metze/wireshark/wip.git] / epan / dissectors / packet-glbp.c
1 /* packet-glbp.c
2  *
3  * Cisco's GLBP:  Gateway Load Balancing Protocol
4  *
5  * $Id$
6  *
7  * Copyright 2007 Joerg Mayer (see AUTHORS file)
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 /*
29  * Documentation:
30  * http://www.cisco.com/en/US/docs/ios/12_2t/12_2t15/feature/guide/ft_glbp.pdf
31  *
32  * TODO: This dissector has been written without specs, so much of it is
33  *    guesswork. Also, there are still unknown elements in the message.
34  * Some debug output:
35  * GLBP: Fa0/0 Grp 1020 Hello  out VG Active  pri 100 vIP FE80::C800:8FF:FE64:AAAA
36  *       hello 3000, hold 10000 VF 1 Active  pri 167 vMAC 0007.b403.fc01
37  * GLBP: Fa0/0 Grp 1021 Hello  out VG Active  pri 100 vIP 10.20.20.100
38  *       hello 3000, hold 10000 VF 1 Active  pri 167 vMAC 0007.b403.fd01
39  */
40
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44
45 #include <glib.h>
46 #include <epan/packet.h>
47 #include <epan/expert.h>
48
49 static int proto_glbp = -1;
50 /* glbp header? */
51 static gint hf_glbp_version = -1;
52 static gint hf_glbp_unknown1 = -1;
53 static gint hf_glbp_group = -1;
54 static gint hf_glbp_unknown2 = -1;
55 static gint hf_glbp_ownerid = -1;
56 static gint hf_glbp_tlv = -1;
57 static gint hf_glbp_type = -1;
58 static gint hf_glbp_length = -1;
59 /* glbp type = 1 - hello */
60 static gint hf_glbp_hello_unknown10 = -1;
61 static gint hf_glbp_hello_vgstate = -1;
62 static gint hf_glbp_hello_unknown11 = -1;
63 static gint hf_glbp_hello_priority = -1;
64 static gint hf_glbp_hello_unknown12 = -1;
65 static gint hf_glbp_hello_helloint = -1;
66 static gint hf_glbp_hello_holdint = -1;
67 static gint hf_glbp_hello_redirect = -1;
68 static gint hf_glbp_hello_timeout = -1;
69 static gint hf_glbp_hello_unknown13 = -1;
70 static gint hf_glbp_hello_addrtype = -1;
71 static gint hf_glbp_hello_addrlen = -1;
72 static gint hf_glbp_hello_virtualipv4 = -1;
73 static gint hf_glbp_hello_virtualipv6 = -1;
74 static gint hf_glbp_hello_virtualunk = -1;
75 /* glbp type = 2 - Request/Response??? */
76 static gint hf_glbp_reqresp_forwarder = -1;
77 static gint hf_glbp_reqresp_vfstate = -1;
78 static gint hf_glbp_reqresp_unknown21 = -1;
79 static gint hf_glbp_reqresp_priority = -1;
80 static gint hf_glbp_reqresp_weight = -1;
81 static gint hf_glbp_reqresp_unknown22 = -1;
82 static gint hf_glbp_reqresp_virtualmac = -1;
83 /* glbp type = 3 - Auth */
84 static gint hf_glbp_auth_authtype = -1;
85 static gint hf_glbp_auth_authlength = -1;
86 static gint hf_glbp_auth_plainpass = -1;
87 static gint hf_glbp_auth_md5hash = -1;
88 static gint hf_glbp_auth_md5chainindex = -1;
89 static gint hf_glbp_auth_md5chainhash = -1;
90 static gint hf_glbp_auth_authunknown = -1;
91 /* unknown type */
92 static gint hf_glbp_unknown_data = -1;
93
94 static gint ett_glbp = -1;
95 static gint ett_glbp_tlv = -1;
96
97 static const value_string glbp_type_vals[] = {
98         { 1,    "Hello" },
99         { 2,    "Request/Response?" },
100         { 3,    "Auth" },
101
102         { 0, NULL }
103 };
104
105 #if 0
106 static const value_string glbp_reqresp_forwarder_vals[] = {
107         { 0,    "Request?" },
108         { 2,    "Response?" },
109
110         { 0, NULL }
111 };
112 #endif
113
114 static const value_string glbp_addr_type_vals[] = {
115         { 1,    "IPv4" },
116         { 2,    "IPv6" },
117
118         { 0, NULL }
119 };
120
121 static const value_string glbp_auth_type_vals[] = {
122         { 0,    "None" },
123         { 1,    "Plain text" },
124         { 2,    "MD5 string" },
125         { 3,    "MD5 chain" },
126
127         { 0, NULL }
128 };
129
130 #if 0
131 static const value_string glbp_loadbalancing_vals[] = {
132         { x,    "None (AVG only)" },
133         { x,    "Weighted" },
134         { x,    "Host dependent" },
135         { x,    "Round robin" },
136
137         { 0, NULL }
138 };
139 #endif
140
141 static const value_string glbp_vgstate_vals[] = {
142 #if 0
143         { x,    "Disabled" },
144         { x,    "Initial" },
145 #endif
146         { 4,    "Listen" },
147         { 8,    "Speak" },
148         { 0x10, "Standby" },
149         { 0x20, "Active" },
150
151         { 0, NULL }
152 };
153
154 static const value_string glbp_vfstate_vals[] = {
155 #if 0
156         { x,    "Disabled" },
157         { x,    "Initial" },
158 #endif
159         { 4,    "Listen" },
160         { 0x20, "Active" },
161
162         { 0, NULL }
163 };
164
165 static int
166 dissect_glbp_hello(tvbuff_t *tvb, int offset,
167         packet_info *pinfo, proto_tree *tlv_tree)
168 {
169   guint8 addrtype;
170   guint8 addrlen;
171
172   proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown10, tvb, offset, 1,  FALSE);
173   offset ++;
174   proto_tree_add_item(tlv_tree, hf_glbp_hello_vgstate, tvb, offset, 1,  FALSE);
175   offset ++;
176   proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown11, tvb, offset, 1,  FALSE);
177   offset ++;
178   proto_tree_add_item(tlv_tree, hf_glbp_hello_priority, tvb, offset, 1,  FALSE);
179   offset++;
180   proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown12, tvb, offset, 2, FALSE);
181   offset += 2;
182   proto_tree_add_item(tlv_tree, hf_glbp_hello_helloint, tvb, offset, 4, FALSE);
183   offset += 4;
184   proto_tree_add_item(tlv_tree, hf_glbp_hello_holdint, tvb, offset, 4, FALSE);
185   offset += 4;
186   proto_tree_add_item(tlv_tree, hf_glbp_hello_redirect, tvb, offset, 2, FALSE);
187   offset += 2;
188   proto_tree_add_item(tlv_tree, hf_glbp_hello_timeout, tvb, offset, 2, FALSE);
189   offset += 2;
190   proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown13, tvb, offset, 2, FALSE);
191   offset += 2;
192   proto_tree_add_item(tlv_tree, hf_glbp_hello_addrtype, tvb, offset, 1, FALSE);
193   addrtype = tvb_get_guint8(tvb, offset);
194   offset++;
195   proto_tree_add_item(tlv_tree, hf_glbp_hello_addrlen, tvb, offset, 1, FALSE);
196   addrlen = tvb_get_guint8(tvb, offset);
197   offset++;
198   switch (addrtype) {
199     case 1:
200     if (addrlen != 4) {
201       expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Wrong IPv4 address length: %u", addrlen);
202       return offset + addrlen;
203     }
204     proto_tree_add_item(tlv_tree, hf_glbp_hello_virtualipv4, tvb, offset, addrlen, FALSE);
205     break;
206   case 2:
207     if (addrlen != 16) {
208       expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Wrong IPv6 address length: %u", addrlen);
209       return offset + addrlen;
210     }
211     proto_tree_add_item(tlv_tree, hf_glbp_hello_virtualipv6, tvb, offset, addrlen, FALSE);
212     break;
213   default:
214     proto_tree_add_item(tlv_tree, hf_glbp_hello_virtualunk, tvb, offset, addrlen, FALSE);
215     break;
216   }
217   offset += addrlen;
218
219   col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
220     val_to_str(addrtype, glbp_addr_type_vals, "%d"));
221
222   return offset;
223 }
224
225
226 static int
227 dissect_glbp_reqresp(tvbuff_t *tvb, int offset,
228         packet_info *pinfo _U_, proto_tree *tlv_tree)
229 {
230   proto_tree_add_item(tlv_tree, hf_glbp_reqresp_forwarder, tvb, offset, 1, FALSE);
231   offset++;
232   proto_tree_add_item(tlv_tree, hf_glbp_reqresp_vfstate, tvb, offset, 1, FALSE);
233   offset++;
234   proto_tree_add_item(tlv_tree, hf_glbp_reqresp_unknown21, tvb, offset, 1, FALSE);
235   offset += 1;
236   proto_tree_add_item(tlv_tree, hf_glbp_reqresp_priority, tvb, offset, 1, FALSE);
237   offset++;
238   proto_tree_add_item(tlv_tree, hf_glbp_reqresp_weight, tvb, offset, 1, FALSE);
239   offset++;
240   proto_tree_add_item(tlv_tree, hf_glbp_reqresp_unknown22, tvb, offset, 7, FALSE);
241   offset += 7;
242   proto_tree_add_item(tlv_tree, hf_glbp_reqresp_virtualmac, tvb, offset, 6, FALSE);
243   offset += 6;
244
245   return offset;
246 }
247
248 static int
249 dissect_glbp_auth(tvbuff_t *tvb, int offset,
250         packet_info *pinfo _U_, proto_tree *tlv_tree)
251 {
252   guint8 authtype;
253   guint8 authlength;
254
255   proto_tree_add_item(tlv_tree, hf_glbp_auth_authtype, tvb, offset, 1,  FALSE);
256   authtype = tvb_get_guint8(tvb, offset);
257   offset++;
258   proto_tree_add_item(tlv_tree, hf_glbp_auth_authlength, tvb, offset, 1,  FALSE);
259   authlength = tvb_get_guint8(tvb, offset);
260   offset++;
261   switch(authtype) {
262   case 1:
263     proto_tree_add_item(tlv_tree, hf_glbp_auth_plainpass, tvb, offset, authlength, FALSE);
264     offset += authlength;
265     break;
266   case 2:
267     proto_tree_add_item(tlv_tree, hf_glbp_auth_md5hash, tvb, offset, authlength, FALSE);
268     offset += authlength;
269     break;
270   case 3:
271     proto_tree_add_item(tlv_tree, hf_glbp_auth_md5chainindex, tvb, offset, 4, FALSE);
272     proto_tree_add_item(tlv_tree, hf_glbp_auth_md5chainhash, tvb, offset+4, authlength-4, FALSE);
273     offset += authlength;
274     break;
275   default:
276     proto_tree_add_item(tlv_tree, hf_glbp_auth_authunknown, tvb, offset, authlength, FALSE);
277     offset += authlength;
278     break;
279   }
280
281   return offset;
282 }
283
284 static int
285 dissect_glbp_unknown(tvbuff_t *tvb, int offset, guint32 length,
286         packet_info *pinfo _U_, proto_tree *tlv_tree)
287 {
288   proto_tree_add_item(tlv_tree, hf_glbp_unknown_data, tvb, offset, length, FALSE);
289   offset += length;
290
291   return offset;
292 }
293
294 static int
295 dissect_glbp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
296 {
297   proto_tree *glbp_tree = NULL;
298   proto_tree *tlv_tree = NULL;
299   proto_item *ti = NULL;
300   guint8 type;
301   int offset = 0;
302   int lastoffset;
303   guint8 length;
304   guint16 group;
305
306   group = tvb_get_ntohs(tvb, 2);
307
308   col_set_str(pinfo->cinfo, COL_PROTOCOL, "GLBP");
309   col_add_fstr(pinfo->cinfo, COL_INFO, "G: %d", group);
310
311   if (tree) {
312     ti = proto_tree_add_item(tree, proto_glbp, tvb, 0, -1, FALSE);
313     glbp_tree = proto_item_add_subtree(ti, ett_glbp);
314
315     /* glbp header? */
316     proto_tree_add_item(glbp_tree, hf_glbp_version, tvb, offset, 1,  FALSE);
317     offset++;
318     proto_tree_add_item(glbp_tree, hf_glbp_unknown1, tvb, offset, 1,  FALSE);
319     offset++;
320     proto_tree_add_item(glbp_tree, hf_glbp_group, tvb, offset, 2,  FALSE);
321     offset += 2;
322     proto_tree_add_item(glbp_tree, hf_glbp_unknown2, tvb, offset, 2,  FALSE);
323     offset += 2;
324     proto_tree_add_item(glbp_tree, hf_glbp_ownerid, tvb, offset, 6, FALSE);
325     offset += 6;
326     while (tvb_length_remaining(tvb, offset) > 0) {
327
328       type = tvb_get_guint8(tvb, offset);
329       length = tvb_get_guint8(tvb, offset+1);
330       if (length < 2) {
331         expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Length %u too small", length);
332         return offset;
333       }
334       length -= 2;
335
336       ti = proto_tree_add_item(glbp_tree, hf_glbp_tlv, tvb, offset, length+2, FALSE);
337       tlv_tree = proto_item_add_subtree(ti, ett_glbp_tlv);
338       proto_item_append_text(ti, " l=%d, t=%s", length+2,
339         val_to_str(type, glbp_type_vals, "%d"));
340
341       proto_tree_add_item(tlv_tree, hf_glbp_type, tvb, offset, 1,  FALSE);
342       offset++;
343       proto_tree_add_item(tlv_tree, hf_glbp_length, tvb, offset, 1,  FALSE);
344       offset++;
345       col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
346         val_to_str(type, glbp_type_vals, "%d"));
347   
348       lastoffset = offset;
349       switch(type) {
350         case 1: /* Hello */
351           offset = dissect_glbp_hello(tvb, offset, pinfo, tlv_tree);
352         break;
353         case 2: /* Request/Response */
354           offset = dissect_glbp_reqresp(tvb, offset, pinfo, tlv_tree);
355         break;
356         case 3: /* Plaintext auth */
357           offset = dissect_glbp_auth(tvb, offset, pinfo, tlv_tree);
358         break;
359         default:
360           offset = dissect_glbp_unknown(tvb, offset, length, pinfo, tlv_tree);
361         break;
362       }
363       if (lastoffset >= offset) {
364         expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Zero or negative length");
365         return lastoffset;
366       }
367       /* Skip over trailing bytes before starting with the next element */
368       if (lastoffset + length > offset)
369         offset = lastoffset + length;
370     }
371   }
372   return offset;
373 }
374
375 static gboolean
376 test_glbp(tvbuff_t *tvb, packet_info *pinfo)
377 {
378         guint32 unknown1;
379         if ( tvb_length(tvb) < 2)
380                 return FALSE;
381         unknown1 = tvb_get_guint8(tvb, 1);
382         if (tvb_get_guint8(tvb, 0) != 1 /* version? */
383                 || unknown1 > 4
384                 || pinfo->srcport != pinfo->destport
385 #if 0 /* XXX */
386                 || unknown1 == 0 && pinfo->net_dst != ipv4:224.0.0.102
387                                  && pinfo->net_dst != ipv6:...
388                 || unknown1 == 0 && pinfo->dl_src != ether:c2-00-7c-b8-00-00
389 #endif
390         ) {
391                 return FALSE;
392         }
393         return TRUE;
394 }
395
396 static int
397 dissect_glbp_static(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
398 {
399         if ( !test_glbp(tvb, pinfo) ) {
400                 return 0;
401         }
402         return dissect_glbp(tvb, pinfo, tree);
403 }
404
405
406 void
407 proto_register_glbp(void)
408 {
409   static hf_register_info hf[] = {
410         /* Header */
411         { &hf_glbp_version,
412            { "Version?",        "glbp.version", FT_UINT8, BASE_DEC, NULL,
413              0x0, NULL, HFILL }},
414
415         { &hf_glbp_unknown1,
416            { "Unknown1",        "glbp.unknown1", FT_UINT8, BASE_DEC, NULL,
417              0x0, NULL, HFILL }},
418
419         { &hf_glbp_group,
420            { "Group",           "glbp.group", FT_UINT16, BASE_DEC, NULL,
421              0x0, NULL, HFILL }},
422
423         { &hf_glbp_unknown2,
424            { "Unknown2",      "glbp.unknown2", FT_BYTES, BASE_NONE, NULL,
425              0x0, NULL, HFILL }},
426
427         { &hf_glbp_ownerid,
428            { "Owner ID",       "glbp.ownerid", FT_ETHER, BASE_NONE, NULL,
429              0x0, NULL, HFILL }},
430
431         { &hf_glbp_tlv,
432            { "TLV",       "glbp.tlv", FT_PROTOCOL, BASE_NONE, NULL,
433              0x0, NULL, HFILL }},
434
435         { &hf_glbp_type,
436            { "Type",         "glbp.type", FT_UINT8, BASE_DEC, VALS(glbp_type_vals),
437              0x0, NULL, HFILL }},
438
439         { &hf_glbp_length,
440            { "Length",       "glbp.length", FT_UINT8, BASE_DEC, NULL,
441              0x0, NULL, HFILL }},
442
443         /* type = 1 - hello */
444         { &hf_glbp_hello_unknown10,
445            { "Unknown1-0",      "glbp.hello.unknown10", FT_BYTES, BASE_NONE, NULL,
446              0x0, NULL, HFILL }},
447
448         { &hf_glbp_hello_vgstate,
449            { "VG state?",      "glbp.hello.vgstate", FT_UINT8, BASE_DEC, VALS(glbp_vgstate_vals),
450              0x0, NULL, HFILL }},
451
452         { &hf_glbp_hello_unknown11,
453            { "Unknown1-1",      "glbp.hello.unknown11", FT_BYTES, BASE_NONE, NULL,
454              0x0, NULL, HFILL }},
455
456         { &hf_glbp_hello_priority,
457            { "Priority",      "glbp.hello.priority", FT_UINT8, BASE_DEC, NULL,
458              0x0, NULL, HFILL }},
459
460         { &hf_glbp_hello_unknown12,
461            { "Unknown1-2",      "glbp.hello.unknown12", FT_BYTES, BASE_NONE, NULL,
462              0x0, NULL, HFILL }},
463
464         { &hf_glbp_hello_helloint,
465            { "Helloint",      "glbp.hello.helloint", FT_UINT32, BASE_DEC, NULL,
466              0x0, "Hello interval [msec]", HFILL }},
467
468         { &hf_glbp_hello_holdint,
469            { "Holdint",      "glbp.hello.holdint", FT_UINT32, BASE_DEC, NULL,
470              0x0, "Hold interval [msec]", HFILL }},
471
472         { &hf_glbp_hello_redirect,
473            { "Redirect",      "glbp.hello.redirect", FT_UINT16, BASE_DEC, NULL,
474              0x0, "Redirect interval [sec]", HFILL }},
475
476         { &hf_glbp_hello_timeout,
477            { "Timeout",      "glbp.hello.timeout", FT_UINT16, BASE_DEC, NULL,
478              0x0, "Forwarder timeout interval [sec]", HFILL }},
479
480         { &hf_glbp_hello_unknown13,
481            { "Unknown1-3",      "glbp.hello.unknown13", FT_BYTES, BASE_NONE, NULL,
482              0x0, NULL, HFILL }},
483
484         { &hf_glbp_hello_addrtype,
485            { "Address type",      "glbp.hello.addrtype", FT_UINT8, BASE_DEC, VALS(glbp_addr_type_vals),
486              0x0, NULL, HFILL }},
487
488         { &hf_glbp_hello_addrlen,
489            { "Address length",      "glbp.hello.addrlen", FT_UINT8, BASE_DEC, NULL,
490              0x0, NULL, HFILL }},
491
492         { &hf_glbp_hello_virtualipv4,
493            { "Virtual IPv4",      "glbp.hello.virtualipv4", FT_IPv4, BASE_NONE, NULL,
494              0x0, NULL, HFILL }},
495
496         { &hf_glbp_hello_virtualipv6,
497            { "Virtual IPv6",      "glbp.hello.virtualipv6", FT_IPv6, BASE_NONE, NULL,
498              0x0, NULL, HFILL }},
499
500         { &hf_glbp_hello_virtualunk,
501            { "Virtual Unknown",      "glbp.hello.virtualunk", FT_BYTES, BASE_NONE, NULL,
502              0x0, NULL, HFILL }},
503
504         /* type = 2 - request/response??? */
505         { &hf_glbp_reqresp_forwarder,
506            { "Forwarder?",      "glbp.reqresp.forwarder", FT_UINT8, BASE_DEC, NULL,
507              0x0, NULL, HFILL }},
508
509         { &hf_glbp_reqresp_vfstate,
510            { "VF state?",      "glbp.reqresp.vfstate", FT_UINT8, BASE_DEC, VALS(glbp_vfstate_vals),
511              0x0, NULL, HFILL }},
512
513         { &hf_glbp_reqresp_unknown21,
514            { "Unknown2-1",      "glbp.reqresp.unknown21", FT_BYTES, BASE_NONE, NULL,
515              0x0, NULL, HFILL }},
516
517         { &hf_glbp_reqresp_priority,
518            { "Priority",          "glbp.reqresp.priority", FT_UINT8, BASE_DEC, NULL,
519              0x0, NULL, HFILL }},
520
521         { &hf_glbp_reqresp_weight,
522            { "Weight",          "glbp.reqresp.weight", FT_UINT8, BASE_DEC, NULL,
523              0x0, NULL, HFILL }},
524
525         { &hf_glbp_reqresp_unknown22,
526            { "Unknown2-2",      "glbp.reqresp.unknown22", FT_BYTES, BASE_NONE, NULL,
527              0x0, NULL, HFILL }},
528
529         { &hf_glbp_reqresp_virtualmac,
530            { "Virtualmac",       "glbp.reqresp.virtualmac", FT_ETHER, BASE_NONE, NULL,
531              0x0, NULL, HFILL }},
532
533         /* type = 3 - auth */
534         { &hf_glbp_auth_authtype,
535            { "Authtype",         "glbp.auth.authtype", FT_UINT8, BASE_DEC, VALS(glbp_auth_type_vals),
536              0x0, NULL, HFILL }},
537
538         { &hf_glbp_auth_authlength,
539            { "Authlength",       "glbp.auth.authlength", FT_UINT8, BASE_DEC, NULL,
540              0x0, NULL, HFILL }},
541
542         { &hf_glbp_auth_plainpass,
543            { "Plain pass",       "glbp.auth.plainpass", FT_STRING, BASE_NONE, NULL,
544              0x0, NULL, HFILL }},
545
546         { &hf_glbp_auth_md5hash,
547            { "MD5-string hash",       "glbp.auth.md5hash", FT_BYTES, BASE_NONE, NULL,
548              0x0, NULL, HFILL }},
549
550         { &hf_glbp_auth_md5chainindex,
551            { "MD5-chain index",       "glbp.auth.md5chainindex", FT_UINT32, BASE_DEC, NULL,
552              0x0, NULL, HFILL }},
553
554         { &hf_glbp_auth_md5chainhash,
555            { "MD5-chain hash",       "glbp.auth.md5chainhash", FT_BYTES, BASE_NONE, NULL,
556              0x0, NULL, HFILL }},
557
558         { &hf_glbp_auth_authunknown,
559            { "Unknown auth value",       "glbp.auth.authunknown", FT_BYTES, BASE_NONE, NULL,
560              0x0, NULL, HFILL }},
561
562         /* type = unknown */
563         { &hf_glbp_unknown_data,
564            { "Unknown TLV data",      "glbp.unknown.data", FT_BYTES, BASE_NONE, NULL,
565              0x0, NULL, HFILL }},
566
567   };
568   static gint *ett[] = {
569     &ett_glbp,
570     &ett_glbp_tlv,
571   };
572
573   proto_glbp = proto_register_protocol(
574         "Gateway Load Balancing Protocol", "GLBP", "glbp");
575   proto_register_field_array(proto_glbp, hf, array_length(hf));
576   proto_register_subtree_array(ett, array_length(ett));
577 }
578
579 void
580 proto_reg_handoff_glbp(void)
581 {
582   dissector_handle_t glbp_handle;
583
584   glbp_handle = new_create_dissector_handle(dissect_glbp_static, proto_glbp);
585   dissector_add("udp.port", 3222, glbp_handle);
586 }