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