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