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