From Jesper Peterson:
[obnox/wireshark/wip.git] / packet-srvloc.c
1 /* packet-srvloc.c
2  * Routines for SRVLOC (Service Location Protocol) packet dissection
3  * Copyright 1999, James Coe <jammer@cin.net>
4  * Copyright 2002, Brad Hards
5  * Updated for TCP segments by Greg Morris <gmorris@novell.com>
6  * Copyright 2003, Greg Morris
7  *
8  * NOTE: This is Alpha software not all features have been verified yet.
9  *       In particular I have not had an opportunity to see how it
10  *       responds to SRVLOC over TCP.
11  *
12  * $Id: packet-srvloc.c,v 1.42 2003/08/18 18:06:06 guy Exp $
13  *
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@ethereal.com>
16  * Copyright 1998 Gerald Combs
17  *
18  * Service Location Protocol is RFC 2165
19  * Service Location Protocol Version 2 is RFC 2608
20  *   - partial support by Brad Hards <bradh@frogmouth.net>
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License
24  * as published by the Free Software Foundation; either version 2
25  * of the License, or (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  */
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <stdio.h>
42 #include <stdlib.h>
43
44 #include <string.h>
45 #include <time.h>
46 #include <glib.h>
47
48 #include <epan/packet.h>
49 #include <epan/strutil.h>
50 #include "prefs.h"
51 #include "packet-tcp.h"
52 #include "reassemble.h"
53
54 static gboolean srvloc_desegment = TRUE;
55 static int proto_srvloc = -1;
56 static int hf_srvloc_version = -1;
57 static int hf_srvloc_function = -1;
58 static int hf_srvloc_pktlen = -1;
59 static int hf_srvloc_xid = -1;
60 static int hf_srvloc_langtaglen = -1;
61 static int hf_srvloc_langtag = -1;
62 static int hf_srvloc_nextextoff = -1;
63 static int hf_srvloc_flags_v1 = -1;
64 static int hf_srvloc_flags_v1_overflow = -1;
65 static int hf_srvloc_flags_v1_monolingual = -1;
66 static int hf_srvloc_flags_v1_url_auth = -1;
67 static int hf_srvloc_flags_v1_attribute_auth = -1;
68 static int hf_srvloc_flags_v1_fresh = -1;
69 static int hf_srvloc_error = -1;
70 static int hf_srvloc_flags_v2 = -1;
71 static int hf_srvloc_flags_v2_overflow = -1;
72 static int hf_srvloc_flags_v2_fresh = -1;
73 static int hf_srvloc_flags_v2_reqmulti = -1;
74 static int hf_srvloc_error_v2 = -1;
75 static int hf_srvloc_daadvert_timestamp = -1;
76 static int hf_srvloc_daadvert_urllen = -1;
77 static int hf_srvloc_daadvert_url = -1;
78 static int hf_srvloc_daadvert_scopelistlen = -1;
79 static int hf_srvloc_daadvert_scopelist = -1;
80 static int hf_srvloc_daadvert_attrlistlen = -1;
81 static int hf_srvloc_daadvert_attrlist = -1;
82 static int hf_srvloc_daadvert_slpspilen = -1;
83 static int hf_srvloc_daadvert_slpspi = -1;
84 static int hf_srvloc_daadvert_authcount = -1;
85 static int hf_srvloc_srvreq_prlistlen = -1;
86 static int hf_srvloc_srvreq_prlist = -1;
87 static int hf_srvloc_srvreq_srvtypelen = -1;
88 static int hf_srvloc_srvreq_srvtypelist = -1;
89 static int hf_srvloc_srvreq_scopelistlen = -1;
90 static int hf_srvloc_srvreq_scopelist = -1;
91 static int hf_srvloc_srvreq_predicatelen = -1;
92 static int hf_srvloc_srvreq_predicate = -1;
93 static int hf_srvloc_srvreq_slpspilen = -1;
94 static int hf_srvloc_srvreq_slpspi = -1;
95 static int hf_srvloc_srvrply_urlcount = -1;
96 static int hf_srvloc_srvreg_attrlistlen = -1;
97 static int hf_srvloc_srvreg_attrlist = -1;
98 static int hf_srvloc_srvreg_attrauthcount = -1;
99 static int hf_srvloc_srvreg_srvtypelen = -1;
100 static int hf_srvloc_srvreg_srvtype = -1;
101 static int hf_srvloc_srvreg_scopelistlen = -1;
102 static int hf_srvloc_srvreg_scopelist = -1;
103 static int hf_srvloc_srvdereg_scopelistlen = -1;
104 static int hf_srvloc_srvdereg_scopelist = -1;
105 static int hf_srvloc_srvdereg_taglistlen = -1;
106 static int hf_srvloc_srvdereg_taglist = -1;
107 static int hf_srvloc_attrreq_prlistlen  = -1;
108 static int hf_srvloc_attrreq_prlist  = -1;
109 static int hf_srvloc_attrreq_urllen  = -1;
110 static int hf_srvloc_attrreq_url  = -1;
111 static int hf_srvloc_attrreq_scopelistlen  = -1;
112 static int hf_srvloc_attrreq_scopelist  = -1;
113 static int hf_srvloc_attrreq_attrlistlen = -1;
114 static int hf_srvloc_attrreq_attrlist = -1;
115 static int hf_srvloc_attrreq_taglistlen  = -1;
116 static int hf_srvloc_attrreq_taglist  = -1;
117 static int hf_srvloc_attrreq_slpspilen = -1;
118 static int hf_srvloc_attrreq_slpspi = -1;
119 static int hf_srvloc_attrrply_attrlistlen = -1;
120 static int hf_srvloc_attrrply_attrlist = -1;
121 static int hf_srvloc_attrrply_attrauthcount = -1;
122 static int hf_srvloc_srvtypereq_prlistlen = -1;
123 static int hf_srvloc_srvtypereq_prlist = -1;
124 static int hf_srvloc_srvtypereq_nameauthlistlen = -1;
125 static int hf_srvloc_srvtypereq_nameauthlistlenall = -1;
126 static int hf_srvloc_srvtypereq_nameauthlist = -1;
127 static int hf_srvloc_srvtypereq_scopelistlen = -1;
128 static int hf_srvloc_srvtypereq_scopelist = -1;
129 static int hf_srvloc_srvtyperply_srvtypelen = -1;
130 static int hf_srvloc_srvtyperply_srvtype = -1;
131 static int hf_srvloc_srvtyperply_srvtypelistlen = -1;
132 static int hf_srvloc_srvtyperply_srvtypelist = -1;
133 static int hf_srvloc_saadvert_urllen = -1;
134 static int hf_srvloc_saadvert_url = -1;
135 static int hf_srvloc_saadvert_scopelistlen = -1;
136 static int hf_srvloc_saadvert_scopelist = -1;
137 static int hf_srvloc_saadvert_attrlistlen = -1;
138 static int hf_srvloc_saadvert_attrlist = -1;
139 static int hf_srvloc_saadvert_authcount = -1;
140 static int hf_srvloc_authblkv2_bsd = -1;
141 static int hf_srvloc_authblkv2_len = -1;
142 static int hf_srvloc_authblkv2_timestamp = -1;
143 static int hf_srvloc_authblkv2_slpspilen = -1;
144 static int hf_srvloc_authblkv2_slpspi = -1;
145 static int hf_srvloc_url_reserved = -1;
146 static int hf_srvloc_url_lifetime = -1;
147 static int hf_srvloc_url_urllen = -1;
148 static int hf_srvloc_url_url = -1;
149 static int hf_srvloc_url_numauths = -1;
150
151
152 static gint ett_srvloc = -1;
153 static gint ett_srvloc_flags = -1;
154
155
156 static const true_false_string tfs_srvloc_flags_overflow = {
157     "Message will not fit in datagram",
158     "Message will fit in a datagram"
159 };
160 static const true_false_string tfs_srvloc_flags_v1_monolingual = {
161     "Only responses in specified language will be accepted",
162     "Responses in any language will be accepted"
163 };
164 static const true_false_string tfs_srvloc_flags_v1_url_auth = {
165     "URL Authentication Block is present",
166     "URL Authentication Block is absent"
167 };
168 static const true_false_string tfs_srvloc_flags_v1_attribute_auth = {
169     "Attribute Authentication Block is present",
170     "Attribute Authentication Block is absent"
171 };
172 static const true_false_string tfs_srvloc_flags_fresh = {
173     "New Service Registration",
174     "Not a new Service Registration"
175 };
176 static const true_false_string tfs_srvloc_flags_v2_reqmulti = {
177     "Multicast (or broadcast) request",
178     "Not multicast or broadcast"
179 };
180
181
182 #define TCP_PORT_SRVLOC 427
183 #define UDP_PORT_SRVLOC 427
184
185 /* Define function types */
186
187 #define SRVREQ          1
188 #define SRVRPLY         2
189 #define SRVREG          3
190 #define SRVDEREG        4
191 #define SRVACK          5
192 #define ATTRRQST        6
193 #define ATTRRPLY        7
194 #define DAADVERT        8
195 #define SRVTYPERQST     9
196 #define SRVTYPERPLY     10
197 #define SAADVERT        11 /* SLPv2, section 8 */
198
199 /* Create protocol header structure */
200
201 /* bradh: looks like never used. */
202 /* bradh: comment it out for now since it doesn't work for v2
203 struct srvloc_hdr {
204     guint8      version;
205     guint8      function;
206     guint16     length;
207     guint8      flags;
208     guint8      dialect;
209     guchar      language[2];
210     guint16     encoding;
211     guint16     xid;
212 };
213 */
214
215 /* List to resolve function numbers to names */
216
217 static const value_string srvloc_functions[] = {
218     { SRVREQ, "Service Request" },
219     { SRVRPLY, "Service Reply" },
220     { SRVREG, "Service Registration" },
221     { SRVDEREG, "Service Deregister" },
222     { SRVACK, "Service Acknowledge" },
223     { ATTRRQST, "Attribute Request" },
224     { ATTRRPLY, "Attribute Reply" },
225     { DAADVERT, "DA Advertisement" },
226     { SRVTYPERQST, "Service Type Request" },
227     { SRVTYPERPLY, "Service Type Reply" },
228     { SAADVERT, "SA Advertisement" }, /* v2 only */
229     { 0, NULL }
230 };
231
232 /* List to resolve flag values to names */
233
234
235 /* Define flag masks */
236
237 #define FLAG_O          0x80
238 #define FLAG_M          0x40
239 #define FLAG_U          0x20
240 #define FLAG_A          0x10
241 #define FLAG_F          0x08
242
243 /* it all changes for Version 2 */
244 #define FLAG_O_V2       0x8000
245 #define FLAG_F_V2       0x4000
246 #define FLAG_R_V2       0x2000
247
248 /* Define Error Codes  - Version 1*/
249
250 #define SUCCESS         0
251 #define LANG_NOT_SPTD   1
252 #define PROT_PARSE_ERR  2
253 #define INVLD_REG       3
254 #define SCOPE_NOT_SPTD  4
255 #define CHRSET_NOT_UND  5
256 #define AUTH_ABSENT     6
257 #define AUTH_FAILED     7
258
259 /* List to resolve error codes to names */
260
261 static const value_string srvloc_errs[] = {
262     { SUCCESS, "No Error" },
263     { LANG_NOT_SPTD, "Language not supported" },
264     { PROT_PARSE_ERR, "Protocol parse error" },
265     { INVLD_REG, "Invalid registration" },
266     { SCOPE_NOT_SPTD, "Scope not supported" },
267     { CHRSET_NOT_UND, "Character set not understood" },
268     { AUTH_ABSENT, "Authentication absent" },
269     { AUTH_FAILED, "Authentication failed" },
270     { 0, NULL }
271 };
272
273 /* Define Error Codes for Version 2 */
274
275 #define LANGUAGE_NOT_SUPPORTED  1 
276 #define PARSE_ERROR             2
277 #define INVALID_REGISTRATION    3
278 #define SCOPE_NOT_SUPPORTED     4
279 #define AUTHENTICATION_UNKNOWN  5
280 #define AUTHENTICATION_ABSENT   6
281 #define AUTHENTICATION_FAILED   7
282 #define VER_NOT_SUPPORTED       9
283 #define INTERNAL_ERROR          10
284 #define DA_BUSY_NOW             11
285 #define OPTION_NOT_UNDERSTOOD   12
286 #define INVALID_UPDATE          13
287 #define MSG_NOT_SUPPORTED       14
288 #define REFRESH_REJECTED        15
289
290 static const value_string srvloc_errs_v2[] = {
291     { SUCCESS, "No Error" },
292     { LANGUAGE_NOT_SUPPORTED, "No data in the requested language" },
293     { PARSE_ERROR, "The message fails to obey SLP syntax." },
294     { INVALID_REGISTRATION, "The SrvReg has problems" },
295     { SCOPE_NOT_SUPPORTED, "Scope list not supported" },
296     { AUTHENTICATION_UNKNOWN, "Unsupported SLP SPI." },
297     { AUTHENTICATION_ABSENT, "URL and ATTR authentication not provided"},
298     { AUTHENTICATION_FAILED, "Authentication error"},
299     { VER_NOT_SUPPORTED, "Unsupported version number in message header" },
300     { INTERNAL_ERROR, "The DA (or SA) is too sick to respond" },
301     { DA_BUSY_NOW, "UA or SA SHOULD retry" },
302     { OPTION_NOT_UNDERSTOOD, "Unknown option from the mandatory range"},
303     { INVALID_UPDATE, "Invalid SrvReg" },
304     { MSG_NOT_SUPPORTED, "No support for AttrRqst or SrvTypeRqst" },
305     { REFRESH_REJECTED, "SrvReg sent too soon"},
306     { 0, NULL }
307 };
308
309 /*
310  * Character encodings.
311  * This is a small subset of what's in
312  *
313  *      http://www.isi.edu/in-notes/iana/assignments/character-sets
314  *
315  * XXX - we should do something useful with this, i.e. properly
316  * handle strings based on the character set they're in.
317  *
318  * XXX - what does "properly handle strings" mean?  How do we know
319  * what character set the terminal can handle (for tty-based code)
320  * or the GUI can handle (for GUI code)?
321  *
322  * XXX - the Ethereal core really should be what does all the
323  * character set handling for strings, and it should be stuck with
324  * the task of figuring out how to properly handle them.
325  */
326 #define CHARSET_ASCII           3
327 #define CHARSET_ISO_10646_UTF_1 27
328 #define CHARSET_ISO_646_BASIC   28
329 #define CHARSET_ISO_646_IRV     30
330 #define CHARSET_ISO_8859_1      4
331 #define CHARSET_ISO_10646_UCS_2 1000    /* a/k/a Unicode */
332 #define CHARSET_UTF_7           1012
333 #define CHARSET_UTF_8           106
334
335 static const value_string charsets[] = {
336         { CHARSET_ASCII, "US-ASCII" },
337         { CHARSET_ISO_10646_UTF_1, "ISO 10646 UTF-1" },
338         { CHARSET_ISO_646_BASIC, "ISO 646 basic:1983" },
339         { CHARSET_ISO_646_IRV, "ISO 646 IRV:1983" },
340         { CHARSET_ISO_8859_1, "ISO 8859-1" },
341         { CHARSET_ISO_10646_UCS_2, "Unicode" },
342         { CHARSET_UTF_7, "UTF-7" },
343         { CHARSET_UTF_8, "UTF-8" },
344         { 0, NULL }
345 };
346
347 static int
348 dissect_authblk(tvbuff_t *tvb, int offset, proto_tree *tree)
349 {
350     struct tm   *stamp;
351     time_t      seconds;
352     double      floatsec;
353     guint16     length;
354
355     seconds = tvb_get_ntohl(tvb, offset) - 2208988800ul;
356     stamp = gmtime(&seconds);
357     if (stamp != NULL) {
358       floatsec = stamp->tm_sec + tvb_get_ntohl(tvb, offset + 4) / 4294967296.0;
359       proto_tree_add_text(tree, tvb, offset, 8,
360                           "Timestamp: %04d-%02d-%02d %02d:%02d:%07.4f UTC",
361                           stamp->tm_year + 1900, stamp->tm_mon + 1,
362                           stamp->tm_mday, stamp->tm_hour, stamp->tm_min,
363                           floatsec);
364     } else {
365       proto_tree_add_text(tree, tvb, offset, 8, "Timestamp not representable");
366     }
367     proto_tree_add_text(tree, tvb, offset + 8, 2, "Block Structure Desciptor: %u",
368                         tvb_get_ntohs(tvb, offset + 8));
369     length = tvb_get_ntohs(tvb, offset + 10);
370     proto_tree_add_text(tree, tvb, offset + 10, 2, "Authenticator length: %u",
371                         length);
372     offset += 12;
373     proto_tree_add_text(tree, tvb, offset, length, "Authentication block: %s",
374                         tvb_format_text(tvb, offset, length));
375     offset += length;
376     return offset;
377 }
378
379 /* SLPv2 version - Needs to be fixed to match RFC2608 sect 9.2*/
380 static int
381 dissect_authblk_v2(tvbuff_t *tvb, int offset, proto_tree *tree)
382 {
383     guint16 length;
384     
385     proto_tree_add_item(tree, hf_srvloc_authblkv2_bsd, tvb, offset, 2, FALSE);
386     proto_tree_add_item(tree, hf_srvloc_authblkv2_len, tvb, offset+2, 2, FALSE);
387     proto_tree_add_item(tree, hf_srvloc_authblkv2_timestamp, tvb, offset+4, 4, FALSE);
388     length = tvb_get_ntohs(tvb, offset + 8);
389     proto_tree_add_uint(tree, hf_srvloc_authblkv2_slpspilen, tvb, offset + 8, 2, length);
390     offset += 10;
391     proto_tree_add_item(tree, hf_srvloc_authblkv2_slpspi, tvb, offset, length, TRUE);
392     offset += length;
393     /* add code in here to handle Structured Authentication Block */
394     return offset;
395 }
396
397 static int
398 dissect_attrauthblk_v2(tvbuff_t *tvb, int offset, proto_tree *tree)
399 {
400     tvb=tvb; tree=tree; /* silence gcc for now */
401     /* add code in here to handle attribute authentication */
402     return offset;
403 }
404
405 static void
406 add_v1_string(proto_tree *tree, int hf, tvbuff_t *tvb, int offset, int length,
407     guint16 encoding)
408 {
409         char *unicode_str;
410
411         switch (encoding) {
412
413         case CHARSET_ISO_10646_UCS_2:
414                 unicode_str = tvb_fake_unicode(tvb, offset, length/2, FALSE);
415                 proto_tree_add_string(tree, hf, tvb, offset, length,
416                                     unicode_str);
417                 g_free(unicode_str);
418                 break;
419
420         default:
421                 proto_tree_add_item(tree, hf, tvb, offset, length, TRUE);
422                 break;
423         }
424 }
425
426 static int
427 dissect_url_entry_v1(tvbuff_t *tvb, int offset, proto_tree *tree,
428                      guint16 encoding, guint16 flags)
429 {
430     guint16     url_len;
431
432     proto_tree_add_item(tree, hf_srvloc_url_lifetime, tvb, offset, 2,
433                         FALSE);
434     offset += 2;
435     url_len = tvb_get_ntohs(tvb, offset);
436     proto_tree_add_uint(tree, hf_srvloc_url_urllen, tvb, offset, 2,
437                         url_len);
438     offset += 2;
439     add_v1_string(tree, hf_srvloc_url_url, tvb, offset, url_len, encoding);
440     offset += url_len;
441     if ( (flags & FLAG_U) == FLAG_U )
442         offset = dissect_authblk(tvb, offset, tree);
443     return offset;
444 }
445
446 static int
447 dissect_url_entry_v2(tvbuff_t *tvb, int offset, proto_tree *tree)
448 {
449     guint8      reserved;
450     guint16     url_len;
451     guint8      num_auths;
452
453     reserved = tvb_get_guint8(tvb, offset);
454     proto_tree_add_uint(tree, hf_srvloc_url_reserved, tvb, offset, 1,
455                         reserved);
456     offset += 1;
457     proto_tree_add_item(tree, hf_srvloc_url_lifetime, tvb, offset, 2,
458                         FALSE);
459     offset += 2;
460     url_len = tvb_get_ntohs(tvb, offset);
461     proto_tree_add_uint(tree, hf_srvloc_url_urllen, tvb, offset, 2,
462                         url_len);
463     offset += 2;
464     proto_tree_add_item(tree, hf_srvloc_url_url, tvb, offset, url_len, TRUE);
465     offset += url_len;
466     num_auths = tvb_get_guint8(tvb, offset);
467     proto_tree_add_uint(tree, hf_srvloc_url_numauths, tvb, offset, 1,
468                         num_auths);
469     offset += 1;
470     while (num_auths > 0) {
471         offset = dissect_authblk_v2(tvb, offset, tree);
472         num_auths--;
473     }
474     return offset;
475 }
476
477 /* Packet dissection routine called by tcp & udp when port 427 detected */
478
479 static void
480 dissect_srvloc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
481 {
482     int         offset = 0;
483     proto_item  *ti, *tf;
484     proto_tree  *srvloc_tree, *srvloc_flags;
485     guint8      version;
486     guint8      function;
487     guint16     encoding;
488     guint32     length; /* three bytes needed for v2 */
489     guint16     flags; /* two byes needed for v2 */
490     guint32     count;
491     guint32     next_ext_off; /* three bytes, v2 only */
492     guint16     lang_tag_len;
493     nstime_t    ts;
494
495     if (check_col(pinfo->cinfo, COL_PROTOCOL))
496         col_set_str(pinfo->cinfo, COL_PROTOCOL, "SRVLOC");
497
498     if (check_col(pinfo->cinfo, COL_INFO))
499         col_clear(pinfo->cinfo, COL_INFO);
500
501     version = tvb_get_guint8(tvb, offset);
502     function = tvb_get_guint8(tvb, offset + 1);
503
504     if (check_col(pinfo->cinfo, COL_INFO))
505         col_add_str(pinfo->cinfo, COL_INFO,
506             val_to_str(function, srvloc_functions, "Unknown Function (%u)"));
507
508     if (tree) {
509         ti = proto_tree_add_item(tree, proto_srvloc, tvb, offset, -1, FALSE);
510         srvloc_tree = proto_item_add_subtree(ti, ett_srvloc);
511
512         proto_tree_add_uint(srvloc_tree, hf_srvloc_version, tvb, offset, 1,
513                             version);
514         proto_tree_add_uint(srvloc_tree, hf_srvloc_function, tvb, offset + 1, 1,
515                             function);
516         if (version < 2) {
517             length = tvb_get_ntohs(tvb, offset + 2);
518             proto_tree_add_uint(srvloc_tree, hf_srvloc_pktlen, tvb, offset + 2, 2,
519                                 length);
520             flags = tvb_get_guint8(tvb, offset + 4);
521             tf = proto_tree_add_uint(srvloc_tree, hf_srvloc_flags_v1, tvb, offset + 4, 1,
522                                      flags);
523             srvloc_flags = proto_item_add_subtree(tf, ett_srvloc_flags);
524             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v1_overflow,
525                                    tvb, offset+4, 1, flags);
526             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v1_monolingual,
527                                    tvb, offset+4, 1, flags);
528             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v1_url_auth,
529                                    tvb, offset+4, 1, flags);
530             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v1_attribute_auth,
531                                    tvb, offset+4, 1, flags);
532             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v1_fresh,
533                                    tvb, offset+4, 1, flags);
534             proto_tree_add_text(srvloc_tree, tvb, offset + 5, 1, "Dialect: %u",
535                                 tvb_get_guint8(tvb, offset + 5));
536             proto_tree_add_text(srvloc_tree, tvb, offset + 6, 2, "Language: %s",
537                                 tvb_format_text(tvb, offset + 6, 2));
538             encoding = tvb_get_ntohs(tvb, offset + 8);
539             proto_tree_add_text(srvloc_tree, tvb, offset + 8, 2, "Encoding: %u (%s)",
540                                 encoding,
541                                 val_to_str(encoding, charsets, "Unknown"));
542             proto_tree_add_text(srvloc_tree, tvb, offset + 10, 2, "Transaction ID: %u",
543                                 tvb_get_ntohs(tvb, offset + 10));
544             offset += 12;
545
546             switch (function) {
547             case SRVREQ:
548                 length = tvb_get_ntohs(tvb, offset);
549                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreq_prlistlen, tvb, offset, 2, length);
550                 offset += 2;
551                 add_v1_string(srvloc_tree, hf_srvloc_srvreq_prlist, tvb, offset, length, encoding);
552                 offset += length;
553                 length = tvb_get_ntohs(tvb, offset);
554                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreq_predicatelen, tvb, offset, 2, length);
555                 offset += 2;
556                 add_v1_string(srvloc_tree, hf_srvloc_srvreq_predicate, tvb, offset, length, encoding);
557                 offset += length;
558                 break;
559                 
560             case SRVRPLY:
561                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
562                 offset += 2;
563                 count = tvb_get_ntohs(tvb, offset);
564                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvrply_urlcount, tvb, offset, 2, count);
565                 offset += 2;
566                 while (count > 0) {
567                     offset = dissect_url_entry_v1(tvb, offset, srvloc_tree,
568                                                   encoding, flags);
569                     count--;
570                 };
571             break;
572
573             case SRVREG:
574                 offset = dissect_url_entry_v1(tvb, offset, srvloc_tree, encoding,
575                                            flags);
576                 length = tvb_get_ntohs(tvb, offset);
577                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreg_attrlistlen, tvb, offset, 2, length);
578                 offset += 2;
579                 add_v1_string(srvloc_tree, hf_srvloc_srvreg_attrlist, tvb, offset, length, encoding);
580                 offset += length;
581                 if ( (flags & FLAG_A) == FLAG_A )
582                     offset = dissect_authblk(tvb, offset, srvloc_tree);
583             break;
584
585             case SRVDEREG:
586                 length = tvb_get_ntohs(tvb, offset);
587                 proto_tree_add_uint(tree, hf_srvloc_url_urllen, tvb, offset, 2, length);
588                 offset += 2;
589                 add_v1_string(tree, hf_srvloc_url_url, tvb, offset, length, encoding);
590                 offset += length;
591                 if ( (flags & FLAG_U) == FLAG_U )
592                     offset = dissect_authblk(tvb, offset, srvloc_tree);
593                 length = tvb_get_ntohs(tvb, offset);
594                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvdereg_taglistlen, tvb, offset, 2, length);
595                 offset += 2;
596                 add_v1_string(srvloc_tree, hf_srvloc_srvdereg_taglist, tvb, offset, length, encoding);
597                 offset += length;
598                 /*
599                  * XXX - this was there before, but RFC 2165 doesn't speak
600                  * of there being an attribute authentication block in
601                  * a Service Deregister message.  Is that a post-RFC-2165
602                  * addition?
603                  */
604                 if ( (flags & FLAG_A) == FLAG_A )
605                     offset = dissect_authblk(tvb, offset, srvloc_tree);
606             break;
607
608             case SRVACK:
609                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
610                 offset += 2;
611             break;
612
613             case ATTRRQST:
614                 length = tvb_get_ntohs(tvb, offset);
615                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_prlistlen, tvb, offset, 2, length);
616                 offset += 2;
617                 add_v1_string(srvloc_tree, hf_srvloc_attrreq_prlist, tvb, offset, length, encoding);
618                 offset += length;
619                 length = tvb_get_ntohs(tvb, offset);
620                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_urllen, tvb, offset, 2, length);
621                 offset += 2;
622                 add_v1_string(srvloc_tree, hf_srvloc_attrreq_url, tvb, offset, length, encoding);
623                 offset += length;
624                 length = tvb_get_ntohs(tvb, offset);
625                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_scopelistlen, tvb, offset, 2, length);
626                 offset += 2;
627                 add_v1_string(srvloc_tree, hf_srvloc_attrreq_scopelist, tvb, offset, length, encoding);
628                 offset += length;
629                 length = tvb_get_ntohs(tvb, offset);
630                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_attrlistlen, tvb, offset, 2, length);
631                 offset += 2;
632                 add_v1_string(srvloc_tree, hf_srvloc_attrreq_attrlist, tvb, offset, length, encoding);
633                 offset += length;
634             break;
635
636             case ATTRRPLY:
637                 proto_tree_add_item(srvloc_tree, hf_srvloc_error_v2, tvb, offset, 2, FALSE);
638                 offset += 2;
639                 length = tvb_get_ntohs(tvb, offset);
640                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrrply_attrlistlen, tvb, offset, 2, length);
641                 offset += 2;
642                 add_v1_string(srvloc_tree, hf_srvloc_attrrply_attrlist, tvb, offset, length, encoding);
643                 offset += length;
644                 if ( (flags & FLAG_A) == FLAG_A )
645                     offset = dissect_authblk(tvb, offset, srvloc_tree);
646             break;
647
648             case DAADVERT:
649                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
650                 offset += 2;
651                 length = tvb_get_ntohs(tvb, offset);
652                 proto_tree_add_uint(srvloc_tree, hf_srvloc_daadvert_urllen, tvb, offset, 2, length);
653                 offset += 2;
654                 add_v1_string(srvloc_tree, hf_srvloc_daadvert_url, tvb, offset, length, encoding);
655                 offset += length;
656                 length = tvb_get_ntohs(tvb, offset);
657                 proto_tree_add_uint(srvloc_tree, hf_srvloc_daadvert_scopelistlen, tvb, offset, 2, length);
658                 offset += 2;
659                 add_v1_string(srvloc_tree, hf_srvloc_daadvert_scopelist, tvb, offset, length, encoding);
660                 offset += length;
661             break;
662
663             case SRVTYPERQST:
664                 length = tvb_get_ntohs(tvb, offset);
665                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtypereq_prlistlen, tvb, offset, 2, length);
666                 offset += 2;
667                 add_v1_string(srvloc_tree, hf_srvloc_srvtypereq_prlist, tvb, offset, length, encoding);
668                 offset += length;
669                 length = tvb_get_ntohs(tvb, offset);
670                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtypereq_nameauthlistlen, tvb, offset, 2, length);
671                 offset += 2;
672                 add_v1_string(srvloc_tree, hf_srvloc_srvtypereq_nameauthlist, tvb, offset, length, encoding);
673                 offset += length;
674                 length = tvb_get_ntohs(tvb, offset);
675                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtypereq_scopelistlen, tvb, offset, 2, length);
676                 offset += 2;
677                 add_v1_string(srvloc_tree, hf_srvloc_srvtypereq_scopelist, tvb, offset, length, encoding);
678                 offset += length;
679             break;
680
681             case SRVTYPERPLY:
682                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
683                 offset += 2;
684                 count = tvb_get_ntohs(tvb, offset);
685                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Service Type Count: %u",
686                                     count);
687                 offset += 2;
688                 while (count > 0) {
689                     length = tvb_get_ntohs(tvb, offset);
690                     proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtyperply_srvtypelen, tvb, offset, 2, length);
691                     offset += 2;
692                     add_v1_string(srvloc_tree, hf_srvloc_srvtyperply_srvtype, tvb, offset, length, encoding);
693                     offset += length;
694                     count--;
695                 };
696             break;
697
698             default:
699                 proto_tree_add_text(srvloc_tree, tvb, offset, -1, "Unknown Function Type");
700             };
701         }
702         else { /* Version 2 */
703             length = tvb_get_ntoh24(tvb, offset + 2);
704             proto_tree_add_uint(srvloc_tree, hf_srvloc_pktlen, tvb, offset + 2, 3,
705                                 length);
706             flags = tvb_get_ntohs(tvb, offset + 5);
707             tf = proto_tree_add_uint(srvloc_tree, hf_srvloc_flags_v2, tvb, offset + 5, 2,
708                                      flags);
709             srvloc_flags = proto_item_add_subtree(tf, ett_srvloc_flags);
710             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v2_overflow,
711                                    tvb, offset+5, 1, flags);
712             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v2_fresh,
713                                    tvb, offset+5, 1, flags);
714             proto_tree_add_boolean(srvloc_flags, hf_srvloc_flags_v2_reqmulti,
715                                    tvb, offset+5, 1, flags);
716
717             next_ext_off = tvb_get_ntoh24(tvb, offset + 7);
718             proto_tree_add_uint(srvloc_tree, hf_srvloc_nextextoff, tvb, offset + 7, 3,
719                                 next_ext_off);
720             proto_tree_add_uint(srvloc_tree, hf_srvloc_xid, tvb, offset + 10, 2,
721                                 tvb_get_ntohs(tvb, offset + 10));
722             lang_tag_len = tvb_get_ntohs(tvb, offset + 12);
723             proto_tree_add_uint(srvloc_tree, hf_srvloc_langtaglen, tvb, offset + 12, 2, lang_tag_len);
724             proto_tree_add_item(srvloc_tree, hf_srvloc_langtag, tvb, offset + 14, lang_tag_len, TRUE);
725             offset += 14+lang_tag_len;
726
727             switch (function) {
728             case SRVREQ: /* RFC2608 8.1 */
729                 length = tvb_get_ntohs(tvb, offset);
730                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreq_prlistlen, tvb, offset, 2, length);
731                 offset += 2;
732                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreq_prlist, tvb, offset, length, TRUE);
733                 offset += length;
734                 length = tvb_get_ntohs(tvb, offset);
735                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreq_srvtypelen, tvb, offset, 2, length);
736                 offset += 2;
737                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreq_srvtypelist, tvb, offset, length, TRUE);
738                 offset += length;
739                 length = tvb_get_ntohs(tvb, offset);
740                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreq_scopelistlen, tvb, offset, 2, length);
741                 offset += 2;
742                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreq_scopelist, tvb, offset, length, TRUE);
743                 offset += length;
744                 length = tvb_get_ntohs(tvb, offset);
745                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreq_predicatelen, tvb, offset, 2, length);
746                 offset += 2;
747                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreq_predicate, tvb, offset, length, TRUE);
748                 offset += length;
749                 length = tvb_get_ntohs(tvb, offset);
750                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreq_slpspilen, tvb, offset, 2, length);
751                 offset += 2;
752                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreq_slpspi, tvb, offset, length, TRUE);
753                 offset += length;
754                 break;
755                 
756             case SRVRPLY: /* RFC2608 8.2 */
757                 proto_tree_add_item(srvloc_tree, hf_srvloc_error_v2, tvb, offset, 2, FALSE);
758                 offset += 2;
759                 count = tvb_get_ntohs(tvb, offset);
760                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvrply_urlcount, tvb, offset, 2, count);
761                 offset += 2;
762                 while (count > 0) {
763                     offset = dissect_url_entry_v2(tvb, offset, srvloc_tree);
764                     count--;
765                 };
766             break;
767
768             case SRVREG: /* RFC2608 8.3 */
769                 offset = dissect_url_entry_v2(tvb, offset, srvloc_tree);
770                 length = tvb_get_ntohs(tvb, offset);
771                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreg_srvtypelen, tvb, offset, 2, length);
772                 offset += 2;
773                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreg_srvtype, tvb, offset, length, TRUE);
774                 offset += length;
775                 length = tvb_get_ntohs(tvb, offset);
776                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreg_scopelistlen, tvb, offset, 2, length);
777                 offset += 2;
778                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreg_scopelist, tvb, offset, length, TRUE);
779                 offset += length;
780                 length = tvb_get_ntohs(tvb, offset);
781                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreg_attrlistlen, tvb, offset, 2, length);
782                 offset += 2;
783                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvreg_attrlist, tvb, offset, length, TRUE);
784                 offset += length;
785                 count = tvb_get_guint8(tvb, offset);
786                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvreg_attrauthcount, tvb, offset, 1, count);
787                 offset += 1;
788                 while (count > 0) {
789                     offset = dissect_attrauthblk_v2(tvb, offset, srvloc_tree);
790                     count--;
791                 }
792                 break;
793
794             case SRVDEREG: /* RFC2608 10.6 */
795                 length = tvb_get_ntohs(tvb, offset);
796                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvdereg_scopelistlen, tvb, offset, 2, length);
797                 offset += 2;
798                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvdereg_scopelist, tvb, offset, length, TRUE);
799                 offset += length;
800                 offset = dissect_url_entry_v2(tvb, offset, srvloc_tree);
801                 length = tvb_get_ntohs(tvb, offset);
802                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvdereg_taglistlen, tvb, offset, 2, length);
803                 offset += 2;
804                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvdereg_taglist, tvb, offset, length, TRUE);
805                 offset += length;
806                 break;
807             
808             case SRVACK: /* RFC2608 8.4 */
809                 proto_tree_add_item(srvloc_tree, hf_srvloc_error_v2, tvb, offset, 2, FALSE);
810                 offset += 2;
811             break;
812
813             case ATTRRQST: /* RFC2608 10.3*/
814                 length = tvb_get_ntohs(tvb, offset);
815                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_prlistlen, tvb, offset, 2, length);
816                 offset += 2;
817                 proto_tree_add_item(srvloc_tree, hf_srvloc_attrreq_prlist, tvb, offset, length, TRUE);
818                 offset += length;
819                 length = tvb_get_ntohs(tvb, offset);
820                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_urllen, tvb, offset, 2, length);
821                 offset += 2;
822                 proto_tree_add_item(srvloc_tree, hf_srvloc_attrreq_url, tvb, offset, length, TRUE);
823                 offset += length;
824                 length = tvb_get_ntohs(tvb, offset);
825                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_scopelistlen, tvb, offset, 2, length);
826                 offset += 2;
827                 proto_tree_add_item(srvloc_tree, hf_srvloc_attrreq_scopelist, tvb, offset, length, TRUE);
828                 offset += length;
829                 length = tvb_get_ntohs(tvb, offset);
830                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_taglistlen, tvb, offset, 2, length);
831                 offset += 2;
832                 proto_tree_add_item(srvloc_tree, hf_srvloc_attrreq_taglist, tvb, offset, length, TRUE);
833                 offset += length;
834                 length = tvb_get_ntohs(tvb, offset);
835                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrreq_slpspilen, tvb, offset, 2, length);
836                 offset += 2;
837                 proto_tree_add_item(srvloc_tree, hf_srvloc_attrreq_slpspi, tvb, offset, length, TRUE);
838                 offset += length;
839             break;
840
841             case ATTRRPLY: /* RFC2608 10.4 */
842                 proto_tree_add_item(srvloc_tree, hf_srvloc_error_v2, tvb, offset, 2, FALSE);
843                 offset += 2;
844                 length = tvb_get_ntohs(tvb, offset);
845                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrrply_attrlistlen, tvb, offset, 2, length);
846                 offset += 2;
847                 proto_tree_add_item(srvloc_tree, hf_srvloc_attrrply_attrlist, tvb, offset, length, TRUE);
848                 offset += length;
849                 count = tvb_get_guint8(tvb, offset); 
850                 proto_tree_add_uint(srvloc_tree, hf_srvloc_attrrply_attrauthcount, tvb, offset, 1, count);
851                 offset += 1;
852                 while (count > 0) {
853                     offset = dissect_attrauthblk_v2(tvb, offset, srvloc_tree);
854                     count--;
855                 }
856             break;
857             
858             case DAADVERT: /* RCC 2608 8.5 */
859                 proto_tree_add_item(srvloc_tree, hf_srvloc_error_v2, tvb, offset, 2, FALSE);
860                 offset += 2;
861                 ts.nsecs = 0;
862                 ts.secs = tvb_get_ntohl(tvb, offset);
863                 proto_tree_add_time(srvloc_tree, hf_srvloc_daadvert_timestamp, tvb, offset, 4,
864                                     &ts);
865                 offset += 4;
866                 length = tvb_get_ntohs(tvb, offset);
867                 proto_tree_add_uint(srvloc_tree, hf_srvloc_daadvert_urllen, tvb, offset, 2, length);
868                 offset += 2;
869                 proto_tree_add_item(srvloc_tree, hf_srvloc_daadvert_url, tvb, offset, length, TRUE);
870                 offset += length;
871                 length = tvb_get_ntohs(tvb, offset);
872                 proto_tree_add_uint(srvloc_tree, hf_srvloc_daadvert_scopelistlen, tvb, offset, 2, length);
873                 offset += 2;
874                 proto_tree_add_item(srvloc_tree, hf_srvloc_daadvert_scopelist, tvb, offset, length, TRUE);
875                 offset += length;
876                 length = tvb_get_ntohs(tvb, offset);
877                 proto_tree_add_uint(srvloc_tree, hf_srvloc_daadvert_attrlistlen, tvb, offset, 2, length);
878                 offset += 2;
879                 proto_tree_add_item(srvloc_tree, hf_srvloc_daadvert_attrlist, tvb, offset, length, TRUE);
880                 offset += length;
881                 length = tvb_get_ntohs(tvb, offset);
882                 proto_tree_add_uint(srvloc_tree, hf_srvloc_daadvert_slpspilen, tvb, offset, 2, length);
883                 offset += 2;
884                 proto_tree_add_item(srvloc_tree, hf_srvloc_daadvert_slpspi, tvb, offset, length, TRUE);
885                 offset += length;
886                 count = tvb_get_guint8(tvb, offset); 
887                 proto_tree_add_uint(srvloc_tree, hf_srvloc_daadvert_authcount, tvb, offset, 1, count);
888                 offset += 1;
889                 while (count > 0) {
890                     offset = dissect_authblk_v2(tvb, offset, srvloc_tree);
891                     count--;
892                 }
893             break;
894
895             case SRVTYPERQST: /* RFC2608 10.1 */
896                 length = tvb_get_ntohs(tvb, offset);
897                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtypereq_prlistlen, tvb, offset, 2, length);
898                 offset += 2;
899                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvtypereq_prlist, tvb, offset, length, TRUE);
900                 offset += length;
901                 length = tvb_get_ntohs(tvb, offset);
902                 if (0xFFFF == length) {
903                     proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtypereq_nameauthlistlenall, tvb, offset, 2, length);
904                     offset += 2;
905                 } else {
906                     proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtypereq_nameauthlistlen, tvb, offset, 2, length);
907                     offset += 2;
908                     proto_tree_add_item(srvloc_tree, hf_srvloc_srvtypereq_nameauthlist, tvb, offset, length, TRUE);
909                     offset += length;
910                 }
911                 length = tvb_get_ntohs(tvb, offset);
912                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtypereq_scopelistlen, tvb, offset, 2, length);
913                 offset += 2;
914                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvtypereq_scopelist, tvb, offset, length, TRUE);
915                 offset += length;
916             break;
917
918             case SRVTYPERPLY: /* rfc2608 10.2 */
919                 proto_tree_add_item(srvloc_tree, hf_srvloc_error_v2, tvb, offset, 2, FALSE);
920                 offset += 2;
921                 length = tvb_get_ntohs(tvb, offset);
922                 proto_tree_add_uint(srvloc_tree, hf_srvloc_srvtyperply_srvtypelistlen, tvb, offset, 2, length);
923                 offset += 2;
924                 proto_tree_add_item(srvloc_tree, hf_srvloc_srvtyperply_srvtypelist, tvb, offset, length, TRUE);
925             break;
926
927             case SAADVERT: /* rfc2608 10.2 */
928                 length = tvb_get_ntohs(tvb, offset);
929                 proto_tree_add_uint(srvloc_tree, hf_srvloc_saadvert_urllen, tvb, offset, 2,
930                                     length);
931                 offset += 2;
932                 proto_tree_add_item(srvloc_tree, hf_srvloc_saadvert_url, tvb, offset, length, TRUE);
933                 offset += length;
934                 length = tvb_get_ntohs(tvb, offset);
935                 proto_tree_add_uint(srvloc_tree, hf_srvloc_saadvert_scopelistlen, tvb, offset, 2, length);
936                 offset += 2;
937                 proto_tree_add_item(srvloc_tree, hf_srvloc_saadvert_scopelist, tvb, offset, length, TRUE);
938                 offset += length;
939                 length = tvb_get_ntohs(tvb, offset);
940                 proto_tree_add_uint(srvloc_tree, hf_srvloc_saadvert_attrlistlen, tvb, offset, 2, length);
941                 offset += 2;
942                 proto_tree_add_item(srvloc_tree, hf_srvloc_saadvert_attrlist, tvb, offset, length, TRUE);
943                 offset += length;
944                 count = tvb_get_guint8(tvb, offset);
945                 proto_tree_add_uint(srvloc_tree, hf_srvloc_saadvert_authcount, tvb, offset, 1, length);
946                 offset += 1;
947                 while (count > 0) {
948                     offset = dissect_authblk_v2(tvb, offset, srvloc_tree);
949                     count--;
950                 }
951                 break;
952
953             default:
954                 proto_tree_add_text(srvloc_tree, tvb, offset, -1, "Unknown Function Type");
955             };
956         };
957     }
958 }
959
960 static guint
961 get_srvloc_pdu_len(tvbuff_t *tvb, int offset)
962 {
963     /*
964      * Get the length of the SRVLOC packet.
965      */
966     return tvb_get_ntohs(tvb, offset + 2);
967 }
968
969 static void
970 dissect_srvloc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
971 {
972     proto_tree      *srvloc_tree = NULL;
973     proto_item      *ti;
974
975     if (check_col(pinfo->cinfo, COL_PROTOCOL))
976         col_set_str(pinfo->cinfo, COL_PROTOCOL, "SRVLOC");
977
978     if (check_col(pinfo->cinfo, COL_INFO))
979         col_clear(pinfo->cinfo, COL_INFO);
980         
981     if (tree) {
982         ti = proto_tree_add_item(tree, proto_srvloc, tvb, 0, -1, FALSE);
983         srvloc_tree = proto_item_add_subtree(ti, ett_srvloc);
984     }
985     dissect_srvloc(tvb, pinfo, srvloc_tree);
986 }
987
988 static void
989 dissect_srvloc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
990 {
991     tcp_dissect_pdus(tvb, pinfo, tree, srvloc_desegment, 0, get_srvloc_pdu_len,
992         dissect_srvloc_pdu);
993 }
994
995 /* Register protocol with Ethereal. */
996
997 void
998 proto_register_srvloc(void)
999 {
1000     static hf_register_info hf[] = {
1001         /* Helper functions for the Version 1 Header*/
1002         {&hf_srvloc_error,
1003             {"Error Code", "srvloc.err",
1004             FT_UINT16, BASE_DEC, VALS(srvloc_errs), 0x0,
1005             "", HFILL }
1006         },
1007
1008         /* Helper function for the Version 2 Header */
1009         {&hf_srvloc_error_v2,
1010             {"Error Code", "srvloc.errv2",
1011             FT_UINT16, BASE_DEC, VALS(srvloc_errs_v2), 0x0,
1012             "", HFILL }
1013         },
1014         {&hf_srvloc_xid,
1015             {"XID", "srvloc.xid", 
1016             FT_UINT24, BASE_DEC, NULL, 0x0, 
1017             "Transaction ID", HFILL }
1018         },
1019         {&hf_srvloc_langtag,
1020             {"Lang Tag", "srvloc.langtag", 
1021             FT_STRING, BASE_NONE, NULL, 0x0, 
1022             "", HFILL }
1023         },
1024         {&hf_srvloc_langtaglen,
1025             {"Lang Tag Len", "srvloc.langtaglen", 
1026             FT_UINT16, BASE_DEC, NULL, 0x0, 
1027             "", HFILL }
1028         },
1029         {&hf_srvloc_nextextoff,
1030             {"Next Extension Offset", "srvloc.nextextoff", 
1031             FT_UINT24, BASE_DEC, NULL, 0x0, 
1032             "", HFILL }
1033         },
1034
1035         /* Helper functions for URL and URL Entry parsing - both versions */
1036         {&hf_srvloc_url_reserved,
1037          {"Reserved", "srvloc.url.reserved",
1038           FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }
1039         },
1040         {&hf_srvloc_url_lifetime,
1041          {"URL lifetime", "srvloc.url.lifetime",
1042           FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
1043         },
1044         {&hf_srvloc_url_urllen,
1045          {"URL Length", "srvloc.url.urllen",
1046           FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
1047         },
1048         {&hf_srvloc_url_url,
1049          {"URL", "srvloc.url.url",
1050           FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }
1051         },
1052         {&hf_srvloc_url_numauths,
1053          {"Num Auths", "srvloc.url.numauths",
1054           FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
1055         },
1056
1057         /* Helper functions for the common header fields */
1058         {&hf_srvloc_function,
1059             {"Function", "srvloc.function",
1060             FT_UINT8, BASE_DEC, VALS(srvloc_functions), 0x0,
1061             "", HFILL }
1062         },
1063
1064         {&hf_srvloc_pktlen,
1065             {"Packet Length", "srvloc.pktlen", 
1066             FT_UINT24, BASE_DEC, NULL, 0x0, 
1067             "", HFILL }
1068         },
1069
1070         { &hf_srvloc_version,
1071             { "Version",           "srvloc.version",
1072             FT_UINT8, BASE_DEC, NULL, 0x0,
1073             "", HFILL }
1074         },
1075
1076         {&hf_srvloc_flags_v1,
1077             {"Flags", "srvloc.flags_v1",
1078             FT_UINT8, BASE_HEX, NULL, 0x0,
1079             "", HFILL }
1080         },
1081
1082         { &hf_srvloc_flags_v1_overflow,
1083           { "Overflow", "srvloc.flags_v1.overflow.", FT_BOOLEAN, 8,
1084             TFS(&tfs_srvloc_flags_overflow), FLAG_O, "Can whole packet fit into a datagram?", HFILL }},
1085
1086         { &hf_srvloc_flags_v1_monolingual,
1087           { "Monolingual", "srvloc.flags_v1.monolingual", FT_BOOLEAN, 8,
1088             TFS(&tfs_srvloc_flags_v1_monolingual), FLAG_M, "Can whole packet fit into a datagram?", HFILL }},
1089
1090         { &hf_srvloc_flags_v1_url_auth,
1091           { "URL Authentication", "srvloc.flags_v1.url_auth", FT_BOOLEAN, 8,
1092             TFS(&tfs_srvloc_flags_v1_url_auth), FLAG_U, "Can whole packet fit into a datagram?", HFILL }},
1093
1094         { &hf_srvloc_flags_v1_attribute_auth,
1095           { "Attribute Authentication", "srvloc.flags_v1.attribute_auth", FT_BOOLEAN, 8,
1096             TFS(&tfs_srvloc_flags_v1_attribute_auth), FLAG_A, "Can whole packet fit into a datagram?", HFILL }},
1097
1098         { &hf_srvloc_flags_v1_fresh,
1099           { "Fresh Registration", "srvloc.flags_v1.fresh", FT_BOOLEAN, 8,
1100             TFS(&tfs_srvloc_flags_fresh), FLAG_F, "Is this a new registration?", HFILL }},
1101
1102         {&hf_srvloc_flags_v2,
1103             {"Flags", "srvloc.flags_v2", 
1104             FT_UINT16, BASE_HEX, NULL, 0x0, 
1105              "", HFILL }
1106          },
1107
1108         { &hf_srvloc_flags_v2_overflow,
1109           { "Overflow", "srvloc.flags_v2.overflow", FT_BOOLEAN, 16,
1110             TFS(&tfs_srvloc_flags_overflow), FLAG_O_V2, "Can whole packet fit into a datagram?", HFILL }},
1111
1112         { &hf_srvloc_flags_v2_fresh,
1113           { "Fresh Registration", "srvloc.flags_v2.fresh", FT_BOOLEAN, 16,
1114             TFS(&tfs_srvloc_flags_fresh), FLAG_F_V2, "Is this a new registration?", HFILL }},
1115
1116         { &hf_srvloc_flags_v2_reqmulti,
1117           { "Multicast requested", "srvloc.flags_v2.reqmulti", FT_BOOLEAN, 16,
1118             TFS(&tfs_srvloc_flags_v2_reqmulti), FLAG_R_V2, "Do we want multicast?", HFILL }},
1119
1120         /* collection of helper functions for dissect_authblk_v2 */
1121         { &hf_srvloc_authblkv2_bsd,
1122           { "BSD", "srvloc.authblkv2_bsd", FT_UINT16, BASE_HEX, NULL, 0x0,
1123             "Block Structure Descriptor", HFILL}
1124         },
1125         { &hf_srvloc_authblkv2_len,
1126           { "Length", "srvloc.authblkv2_len", FT_UINT16, BASE_DEC, NULL, 0x0,
1127             "Length of Authentication Block", HFILL}
1128         },
1129         { &hf_srvloc_authblkv2_timestamp,
1130           { "Timestamp", "srvloc.authblkv2.timestamp", FT_ABSOLUTE_TIME, BASE_NONE,
1131             NULL, 0, "Timestamp on Authentication Block", HFILL }
1132         },
1133         { &hf_srvloc_authblkv2_slpspilen,
1134           { "SLP SPI Length", "srvloc.authblkv2.slpspilen", FT_UINT16, BASE_DEC, NULL, 0x0,
1135             "Length of the SLP SPI", HFILL}
1136         },
1137         { &hf_srvloc_authblkv2_slpspi,
1138           { "SLP SPI", "srvloc.authblkv2.slpspi", FT_STRING, BASE_NONE, NULL, 0x0,
1139             "", HFILL}
1140         },
1141
1142         /* collection of helper functions for Service Request */
1143         { &hf_srvloc_srvreq_prlistlen,
1144           { "Previous Response List Length", "srvloc.srvreq.prlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1145             "Length of Previous Response List", HFILL}
1146         },
1147         { &hf_srvloc_srvreq_prlist,
1148           { "Previous Response List", "srvloc.srvreq.prlist", FT_STRING, BASE_NONE, NULL, 0x0,
1149             "Previous Response List", HFILL}
1150         },
1151         { &hf_srvloc_srvreq_srvtypelen,
1152           { "Service Type Length", "srvloc.srvreq.srvtypelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1153             "Length of Service Type List", HFILL}
1154         },
1155         { &hf_srvloc_srvreq_srvtypelist,
1156           { "Service Type List", "srvloc.srvreq.srvtypelist", FT_STRING, BASE_NONE, NULL, 0x0,
1157             "", HFILL}
1158         },
1159         { &hf_srvloc_srvreq_scopelistlen,
1160           { "Scope List Length", "srvloc.srvreq.scopelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1161             "Length of the Scope List", HFILL}
1162         },
1163         { &hf_srvloc_srvreq_scopelist,
1164           { "Scope List", "srvloc.srvreq.scopelist", FT_STRING, BASE_NONE, NULL, 0x0,
1165             "", HFILL}
1166         },
1167         { &hf_srvloc_srvreq_predicatelen,
1168           { "Predicate Length", "srvloc.srvreq.predicatelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1169             "Length of the Predicate", HFILL}
1170         },
1171         { &hf_srvloc_srvreq_predicate,
1172           { "Predicate", "srvloc.srvreq.predicate", FT_STRING, BASE_NONE, NULL, 0x0,
1173             "", HFILL}
1174         },
1175         { &hf_srvloc_srvreq_slpspilen,
1176           { "SLP SPI Length", "srvloc.srvreq.slpspilen", FT_UINT16, BASE_DEC, NULL, 0x0,
1177             "Length of the SLP SPI", HFILL}
1178         },
1179         { &hf_srvloc_srvreq_slpspi,
1180           { "SLP SPI", "srvloc.srvreq.slpspi", FT_STRING, BASE_NONE, NULL, 0x0,
1181             "", HFILL}
1182         },
1183
1184         /* Helper function for Service Request */
1185         { &hf_srvloc_srvrply_urlcount,
1186           { "Number of URLs", "srvloc.srvreq.urlcount", FT_UINT16, BASE_DEC, NULL, 0x0,
1187             "", HFILL}
1188         },
1189
1190         /* Helper functions for Service Registration */
1191         { &hf_srvloc_srvreg_srvtypelen,
1192           { "Service Type Length", "srvloc.srvreq.srvtypelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1193             "", HFILL}
1194         },
1195         { &hf_srvloc_srvreg_srvtype,
1196           { "Service Type", "srvloc.srvreq.srvtype", FT_STRING, BASE_NONE, NULL, 0x0,
1197             "", HFILL}
1198         },
1199         { &hf_srvloc_srvreg_scopelistlen,
1200           { "Scope List Length", "srvloc.srvreq.scopelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1201             "", HFILL}
1202         },
1203         { &hf_srvloc_srvreg_scopelist,
1204           { "Scope List", "srvloc.srvreq.scopelist", FT_STRING, BASE_NONE, NULL, 0x0,
1205             "", HFILL}
1206         },
1207         { &hf_srvloc_srvreg_attrlistlen,
1208           { "Attribute List Length", "srvloc.srvreq.attrlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1209             "", HFILL}
1210         },
1211         { &hf_srvloc_srvreg_attrlist,
1212           { "Attribute List", "srvloc.srvreq.attrlist", FT_STRING, BASE_NONE, NULL, 0x0,
1213             "", HFILL}
1214         },
1215         { &hf_srvloc_srvreg_attrauthcount,
1216           { "Attr Auths", "srvloc.srvreq.attrauthcount", FT_UINT8, BASE_DEC, NULL, 0x0,
1217             "Number of Attribute Authentication Blocks", HFILL}
1218         },
1219
1220         /* Helper functions for Service Deregistration */
1221         { &hf_srvloc_srvdereg_scopelistlen,
1222           { "Scope List Length", "srvloc.srvdereq.scopelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1223             "", HFILL}
1224         },
1225         { &hf_srvloc_srvdereg_scopelist,
1226           { "Scope List", "srvloc.srvdereq.scopelist", FT_STRING, BASE_NONE, NULL, 0x0,
1227             "", HFILL}
1228         },
1229         { &hf_srvloc_srvdereg_taglistlen,
1230           { "Tag List Length", "srvloc.srvdereq.taglistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1231             "", HFILL}
1232         },
1233         { &hf_srvloc_srvdereg_taglist,
1234           { "Tag List", "srvloc.srvdereq.taglist", FT_STRING, BASE_NONE, NULL, 0x0,
1235             "", HFILL}
1236         },
1237
1238
1239         /* collection of helper functions for Attribute Request */
1240         { &hf_srvloc_attrreq_prlistlen,
1241           { "Previous Response List Length", "srvloc.attrreq.prlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1242             "Length of Previous Response List", HFILL}
1243         },
1244         { &hf_srvloc_attrreq_prlist,
1245           { "Previous Response List", "srvloc.attrreq.prlist", FT_STRING, BASE_NONE, NULL, 0x0,
1246             "Previous Response List", HFILL}
1247         },
1248         { &hf_srvloc_attrreq_urllen,
1249           { "URL Length", "srvloc.attrreq.urllen", FT_UINT16, BASE_DEC, NULL, 0x0,
1250             "", HFILL}
1251         },
1252         { &hf_srvloc_attrreq_url,
1253           { "Service URL", "srvloc.attrreq.url", FT_STRING, BASE_NONE, NULL, 0x0,
1254             "URL of service", HFILL}
1255         },
1256         { &hf_srvloc_attrreq_scopelistlen,
1257           { "Scope List Length", "srvloc.attrreq.scopelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1258             "Length of the Scope List", HFILL}
1259         },
1260         { &hf_srvloc_attrreq_scopelist,
1261           { "Scope List", "srvloc.attrreq.scopelist", FT_STRING, BASE_NONE, NULL, 0x0,
1262             "", HFILL}
1263         },
1264         { &hf_srvloc_attrreq_attrlistlen,
1265           { "Attribute List Length", "srvloc.attrreq.attrlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1266             "", HFILL}
1267         },
1268         { &hf_srvloc_attrreq_attrlist,
1269           { "Attribute List", "srvloc.attrreq.attrlist", FT_STRING, BASE_NONE, NULL, 0x0,
1270             "", HFILL}
1271         },
1272         { &hf_srvloc_attrreq_taglistlen,
1273           { "Tag List Length", "srvloc.attrreq.taglistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1274             "", HFILL}
1275         },
1276         { &hf_srvloc_attrreq_taglist,
1277           { "Tag List", "srvloc.attrreq.taglist", FT_STRING, BASE_NONE, NULL, 0x0,
1278             "", HFILL}
1279         },
1280         { &hf_srvloc_attrreq_slpspilen,
1281           { "SLP SPI Length", "srvloc.attrreq.slpspilen", FT_UINT16, BASE_DEC, NULL, 0x0,
1282             "Length of the SLP SPI", HFILL}
1283         },
1284         { &hf_srvloc_attrreq_slpspi,
1285           { "SLP SPI", "srvloc.attrreq.slpspi", FT_STRING, BASE_NONE, NULL, 0x0,
1286             "", HFILL}
1287         },
1288
1289         /* collection of helper functions for Attribute Reply */
1290         { &hf_srvloc_attrrply_attrlistlen,
1291           { "Attribute List Length", "srvloc.attrrply.attrlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1292             "Length of Attribute List", HFILL}
1293         },
1294         { &hf_srvloc_attrrply_attrlist,
1295           { "Attribute List", "srvloc.attrrply.attrlist", FT_STRING, BASE_NONE, NULL, 0x0,
1296             "", HFILL}
1297         },
1298         { &hf_srvloc_attrrply_attrauthcount,
1299           { "Attr Auths", "srvloc.srvreq.attrauthcount", FT_UINT8, BASE_DEC, NULL, 0x0,
1300             "Number of Attribute Authentication Blocks", HFILL}
1301         },
1302
1303         /* collection of helper functions for DA Advertisement */
1304         { &hf_srvloc_daadvert_timestamp,
1305           { "DAADVERT Timestamp", "srvloc.daadvert.timestamp", FT_ABSOLUTE_TIME, BASE_NONE,
1306             NULL, 0, "Timestamp on DA Advert", HFILL }
1307         },
1308         { &hf_srvloc_daadvert_urllen,
1309           { "URL Length", "srvloc.daadvert.urllen", FT_UINT16, BASE_DEC, NULL, 0x0,
1310             "", HFILL}
1311         },
1312         { &hf_srvloc_daadvert_url,
1313           { "URL", "srvloc.daadvert.url", FT_STRING, BASE_NONE, NULL, 0x0,
1314             "", HFILL}
1315         },
1316         { &hf_srvloc_daadvert_scopelistlen,
1317           { "Scope List Length", "srvloc.daadvert.scopelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1318             "Length of the Scope List", HFILL}
1319         },
1320         { &hf_srvloc_daadvert_scopelist,
1321           { "Scope List", "srvloc.daadvert.scopelist", FT_STRING, BASE_NONE, NULL, 0x0,
1322             "", HFILL}
1323         },
1324         { &hf_srvloc_daadvert_attrlistlen,
1325           { "Attribute List Length", "srvloc.daadvert.attrlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1326             "", HFILL}
1327         },
1328         { &hf_srvloc_daadvert_attrlist,
1329           { "Attribute List", "srvloc.daadvert.attrlist", FT_STRING, BASE_NONE, NULL, 0x0,
1330             "", HFILL}
1331         },
1332         { &hf_srvloc_daadvert_slpspilen,
1333           { "SLP SPI Length", "srvloc.daadvert.slpspilen", FT_UINT16, BASE_DEC, NULL, 0x0,
1334             "Length of the SLP SPI", HFILL}
1335         },
1336         { &hf_srvloc_daadvert_slpspi,
1337           { "SLP SPI", "srvloc.daadvert.slpspi", FT_STRING, BASE_NONE, NULL, 0x0,
1338             "", HFILL}
1339         },
1340         { &hf_srvloc_daadvert_authcount,
1341           { "Auths", "srvloc.daadvert.authcount", FT_UINT8, BASE_DEC, NULL, 0x0,
1342             "Number of Authentication Blocks", HFILL}
1343         },
1344
1345         /* collection of helper functions for Service Type Request */
1346         { &hf_srvloc_srvtypereq_prlistlen,
1347           { "Previous Response List Length", "srvloc.srvtypereq.prlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1348             "Length of Previous Response List", HFILL}
1349         },
1350         { &hf_srvloc_srvtypereq_prlist,
1351           { "Previous Response List", "srvloc.srvtypereq.prlist", FT_STRING, BASE_NONE, NULL, 0x0,
1352             "Previous Response List", HFILL}
1353         },
1354         { &hf_srvloc_srvtypereq_nameauthlistlen,
1355           { "Naming Authority List Length", "srvloc.srvtypereq.nameauthlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1356             "Length of the Naming Authority List", HFILL}
1357         },
1358         { &hf_srvloc_srvtypereq_nameauthlistlenall,
1359           { "Naming Authority List Length (All Naming Authorities)", "srvloc.srvtypereq.nameauthlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1360             "Length of the Naming Authority List", HFILL}
1361         },
1362         { &hf_srvloc_srvtypereq_nameauthlist,
1363           { "Naming Authority List", "srvloc.srvtypereq.nameauthlist", FT_STRING, BASE_NONE, NULL, 0x0,
1364             "", HFILL}
1365         },
1366         { &hf_srvloc_srvtypereq_scopelistlen,
1367           { "Scope List Length", "srvloc.srvtypereq.scopelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1368             "Length of the Scope List", HFILL}
1369         },
1370         { &hf_srvloc_srvtypereq_scopelist,
1371           { "Scope List", "srvloc.srvtypereq.scopelist", FT_STRING, BASE_NONE, NULL, 0x0,
1372             "", HFILL}
1373         },
1374
1375         /* collection of helper functions for Service Type Replies */
1376         { &hf_srvloc_srvtyperply_srvtypelen,
1377           { "Service Type Length", "srvloc.srvtypereq.srvtypelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1378             "Length of the Service Type", HFILL}
1379         },
1380         { &hf_srvloc_srvtyperply_srvtype,
1381           { "Service Type", "srvloc.srvtyperply.srvtype", FT_STRING, BASE_NONE, NULL, 0x0,
1382             "", HFILL}
1383         },
1384         { &hf_srvloc_srvtyperply_srvtypelistlen,
1385           { "Service Type List Length", "srvloc.srvtypereq.srvtypelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1386             "Length of the Service Type List", HFILL}
1387         },
1388         { &hf_srvloc_srvtyperply_srvtypelist,
1389           { "Service Type List", "srvloc.srvtyperply.srvtypelist", FT_STRING, BASE_NONE, NULL, 0x0,
1390             "", HFILL}
1391         },
1392
1393         /* collection of helper functions for SA Advertisement */
1394         { &hf_srvloc_saadvert_urllen,
1395           { "URL Length", "srvloc.saadvert.urllen", FT_UINT16, BASE_DEC, NULL, 0x0,
1396             "", HFILL}
1397         },
1398         { &hf_srvloc_saadvert_url,
1399           { "URL", "srvloc.saadvert.url", FT_STRING, BASE_NONE, NULL, 0x0,
1400             "", HFILL}
1401         },
1402         { &hf_srvloc_saadvert_scopelistlen,
1403           { "Scope List Length", "srvloc.saadvert.scopelistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1404             "Length of the Scope List", HFILL}
1405         },
1406         { &hf_srvloc_saadvert_scopelist,
1407           { "Scope List", "srvloc.saadvert.scopelist", FT_STRING, BASE_NONE, NULL, 0x0,
1408             "", HFILL}
1409         },
1410         { &hf_srvloc_saadvert_attrlistlen,
1411           { "Attribute List Length", "srvloc.saadvert.attrlistlen", FT_UINT16, BASE_DEC, NULL, 0x0,
1412             "", HFILL}
1413         },
1414         { &hf_srvloc_saadvert_attrlist,
1415           { "Attribute List", "srvloc.saadvert.attrlist", FT_STRING, BASE_NONE, NULL, 0x0,
1416             "", HFILL}
1417         },
1418         { &hf_srvloc_saadvert_authcount,
1419           { "Auths", "srvloc.saadvert.authcount", FT_UINT8, BASE_DEC, NULL, 0x0,
1420             "Number of Authentication Blocks", HFILL}
1421         }
1422
1423     };
1424
1425     static gint *ett[] = {
1426         &ett_srvloc,
1427         &ett_srvloc_flags,
1428     };
1429         module_t *srvloc_module;
1430
1431     proto_srvloc = proto_register_protocol("Service Location Protocol",
1432                                            "SRVLOC", "srvloc");
1433     proto_register_field_array(proto_srvloc, hf, array_length(hf));
1434     proto_register_subtree_array(ett, array_length(ett));
1435         srvloc_module = prefs_register_protocol(proto_srvloc, NULL);
1436         prefs_register_bool_preference(srvloc_module, "desegment_tcp",
1437             "Desegment all SRVLOC messages spanning multiple TCP segments",
1438             "Whether the SRVLOC dissector should desegment all messages spanning multiple TCP segments",
1439             &srvloc_desegment);
1440 }
1441
1442 void
1443 proto_reg_handoff_srvloc(void)
1444 {
1445     dissector_handle_t srvloc_handle, srvloc_tcp_handle;
1446
1447     srvloc_handle = create_dissector_handle(dissect_srvloc, proto_srvloc);
1448     dissector_add("udp.port", UDP_PORT_SRVLOC, srvloc_handle);
1449     srvloc_tcp_handle = create_dissector_handle(dissect_srvloc_tcp,
1450                                                 proto_srvloc);
1451     dissector_add("tcp.port", TCP_PORT_SRVLOC, srvloc_tcp_handle);
1452 }