Miscellaneous code cleaning
[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  *
5  * NOTE: This is Alpha software not all features have been verified yet.
6  *       In particular I have not had an opportunity to see how it 
7  *       responds to SRVLOC over TCP.
8  *
9  * $Id: packet-srvloc.c,v 1.13 2000/08/11 13:34:57 deniel Exp $
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@zing.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * Service Location Protocol is RFC 2165
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  * 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * 
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46
47 #include <string.h>
48 #include <time.h>
49 #include <glib.h>
50
51 #ifdef NEED_SNPRINTF_H
52 # include "snprintf.h"
53 #endif
54
55 #include "packet.h"
56 #include "packet-ipv6.h"
57
58 static int proto_srvloc = -1;
59 static int hf_srvloc_version = -1;
60 static int hf_srvloc_function = -1;
61 static int hf_srvloc_flags = -1;
62 static int hf_srvloc_error = -1;
63
64 static gint ett_srvloc = -1;
65 static gint ett_srvloc_flags = -1;
66
67 #define TCP_PORT_SRVLOC 427
68 #define UDP_PORT_SRVLOC 427
69
70 /* Define function types */
71
72 #define SRVREQ          1
73 #define SRVRPLY         2
74 #define SRVREG          3
75 #define SRVDEREG        4
76 #define SRVACK          5
77 #define ATTRRQST        6
78 #define ATTRRPLY        7
79 #define DAADVERT        8
80 #define SRVTYPERQST     9
81 #define SRVTYPERPLY     10
82
83 /* Create protocol header structure */
84
85 struct srvloc_hdr {
86     guint8      version;
87     guint8      function;
88     guint16     length;
89     guint8      flags;
90     guint8      dialect;
91     u_char      language[2];
92     guint16     encoding;
93     guint16     xid;
94 };
95
96 /* List to resolve function numbers to names */
97
98 static const value_string srvloc_functions[] = {
99     { SRVREQ, "Service Request" }, 
100     { SRVRPLY, "Service Reply" }, 
101     { SRVREG, "Service Registration" }, 
102     { SRVDEREG, "Service Deregister" }, 
103     { SRVACK, "Service Acknowledge" }, 
104     { ATTRRQST, "Attribute Request" }, 
105     { ATTRRPLY, "Attribute Reply" }, 
106     { DAADVERT, "DA Advertisement" }, 
107     { SRVTYPERQST, "Service Type Request" }, 
108     { SRVTYPERPLY, "Service Type Reply" }, 
109 };
110
111 /* List to resolve flag values to names */
112
113
114 /* Define flag masks */
115
116 #define FLAG_O          0x80
117 #define FLAG_M          0x40
118 #define FLAG_U          0x20
119 #define FLAG_A          0x10
120 #define FLAG_F          0x08
121
122 /* Define Error Codes */
123
124 #define SUCCESS         0
125 #define LANG_NOT_SPTD   1
126 #define PROT_PARSE_ERR  2
127 #define INVLD_REG       3
128 #define SCOPE_NOT_SPTD  4
129 #define CHRSET_NOT_UND  5
130 #define AUTH_ABSENT     6
131 #define AUTH_FAILED     7
132
133 /* List to resolve error codes to names */
134
135 static const value_string srvloc_errs[] = {
136     { SUCCESS, "No Error" },
137     { LANG_NOT_SPTD, "Language not supported" },
138     { PROT_PARSE_ERR, "Protocol parse error" },
139     { INVLD_REG, "Invalid registration" },
140     { SCOPE_NOT_SPTD, "Scope not supported" },
141     { CHRSET_NOT_UND, "Character set not understood" },
142     { AUTH_ABSENT, "Authentication absent" },
143     { AUTH_FAILED, "Authentication failed" },
144 };
145
146 static int
147 dissect_authblk(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
148 {
149     struct tm *stamp;
150     time_t seconds;
151     double floatsec;
152     guint16 length;
153     
154     seconds = pntohl(&pd[offset]) - 2208988800ul;
155     stamp = gmtime(&seconds);
156     floatsec = stamp->tm_sec + pntohl(&pd[offset + 4]) / 4294967296.0;
157     proto_tree_add_text(tree, NullTVB, offset, 8,
158                         "Timestamp: %04d-%02d-%02d %02d:%02d:%07.4f UTC",
159                         stamp->tm_year + 1900, stamp->tm_mon + 1,
160                         stamp->tm_mday, stamp->tm_hour, stamp->tm_min,
161                         floatsec);
162     proto_tree_add_text(tree, NullTVB, offset + 8, 2, "Block Structure Desciptor: %u",
163                         pntohs(&pd[offset + 8]));
164     length = pntohs(&pd[offset + 10]);
165     proto_tree_add_text(tree, NullTVB, offset + 10, 2, "Authenticator length: %u",
166                         length);
167     offset += 12;
168     proto_tree_add_text(tree, NullTVB, offset, length, "Authentication block: %s",
169                         format_text(&pd[offset], length));
170     offset += length;
171     return offset;
172 };
173
174 /* Packet dissection routine called by tcp & udp when port 427 detected */
175
176 static void
177 dissect_srvloc(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
178 {
179     proto_item *ti, *tf;
180     proto_tree *srvloc_tree, *srvloc_flags;
181     struct srvloc_hdr srvloc_hdr;
182     guint32 count;
183     guint32 length;
184     
185     if (check_col(fd, COL_PROTOCOL))
186         col_add_str(fd, COL_PROTOCOL, "SRVLOC");
187     
188     if (check_col(fd, COL_INFO))
189         col_add_str(fd, COL_INFO, val_to_str(pd[offset + 1], srvloc_functions, "Unknown Function (%d)"));
190         
191     if (tree) {
192         ti = proto_tree_add_item(tree, proto_srvloc, NullTVB, offset, END_OF_FRAME, FALSE);
193         srvloc_tree = proto_item_add_subtree(ti, ett_srvloc);
194     
195         if ( END_OF_FRAME > sizeof(srvloc_hdr) ) {
196             memcpy( &srvloc_hdr, &pd[offset], sizeof(srvloc_hdr) );
197             srvloc_hdr.length = pntohs(&srvloc_hdr.length);
198             srvloc_hdr.encoding = pntohs(&srvloc_hdr.encoding);
199             srvloc_hdr.xid = pntohs(&srvloc_hdr.xid);
200             proto_tree_add_uint(srvloc_tree, hf_srvloc_version, NullTVB, offset, 1, srvloc_hdr.version);
201             proto_tree_add_uint(srvloc_tree, hf_srvloc_function, NullTVB, offset + 1, 1, srvloc_hdr.function);
202             proto_tree_add_text(srvloc_tree, NullTVB, offset + 2, 2, "Length: %d",srvloc_hdr.length);
203             tf = proto_tree_add_uint(srvloc_tree, hf_srvloc_flags, NullTVB, offset + 4, 1, srvloc_hdr.flags);
204             srvloc_flags = proto_item_add_subtree(tf, ett_srvloc_flags);
205             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Overflow                          %d... .xxx", (srvloc_hdr.flags & FLAG_O) >> 7 );
206             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Monolingual                       .%d.. .xxx", (srvloc_hdr.flags & FLAG_M) >> 6 ); 
207             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "URL Authentication Present        ..%d. .xxx", (srvloc_hdr.flags & FLAG_U) >> 5 );
208             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Attribute Authentication Present  ...%d .xxx", (srvloc_hdr.flags & FLAG_A) >> 4 );
209             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Fresh Service Entry               .... %dxxx", (srvloc_hdr.flags & FLAG_F) >> 3 );
210             proto_tree_add_text(srvloc_tree, NullTVB, offset + 5, 1, "Dialect: %d",srvloc_hdr.dialect); 
211             proto_tree_add_text(srvloc_tree, NullTVB, offset + 6, 2, "Language: %s", format_text(srvloc_hdr.language,2));
212             proto_tree_add_text(srvloc_tree, NullTVB, offset + 8, 2, "Encoding: %d", srvloc_hdr.encoding);
213             proto_tree_add_text(srvloc_tree, NullTVB, offset + 10, 2, "Transaction ID: %d", srvloc_hdr.xid);
214             offset += 12;
215         } else {
216         proto_tree_add_text(srvloc_tree, NullTVB, offset, END_OF_FRAME, "Invalid Packet: Length less than header.");
217         };
218         
219         if (( srvloc_hdr.length - 12 ) == END_OF_FRAME ) {
220             switch (srvloc_hdr.function) {
221                 case SRVREQ:
222                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Request");
223                     if (!BYTES_ARE_IN_FRAME(offset, 2))
224                         break;
225                     length = pntohs(&pd[offset]);
226                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Previous Response List Length: %u", length);
227                     offset += 2;
228                     if (!BYTES_ARE_IN_FRAME(offset, length))
229                         break;
230                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Previous Response List: %s", format_text(&pd[offset], length)); 
231                     offset += length;
232                     if (!BYTES_ARE_IN_FRAME(offset, 2))
233                         break;
234                     length = pntohs(&pd[offset]);
235                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Predicate length: %u", length);
236                     offset += 2;
237                     if (!BYTES_ARE_IN_FRAME(offset, length))
238                         break;
239                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Predicate: %s", format_text(&pd[offset], length));
240                     offset += length;
241                 break;
242             
243                 case SRVRPLY:
244                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Reply");
245                     if (!BYTES_ARE_IN_FRAME(offset, 2))
246                         break;
247                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pntohs(&pd[offset]));
248                     offset += 2;
249                     if (!BYTES_ARE_IN_FRAME(offset, 2))
250                         break;
251                     count = pntohs(&pd[offset]);
252                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL Count: %u", count);
253                     offset += 2;
254                     while (count > 0) {
255                         if (!BYTES_ARE_IN_FRAME(offset, 2))
256                             break;
257                         proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL lifetime: %d", pntohs(&pd[offset]));
258                         offset += 2;
259                         if (!BYTES_ARE_IN_FRAME(offset, 2))
260                             break;
261                         length = pntohs(&pd[offset]);
262                         proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %u", length);
263                         offset += 2;
264                         if (!BYTES_ARE_IN_FRAME(offset, length))
265                             break;
266                         proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
267                         offset += length;
268                         if ( (srvloc_hdr.flags & FLAG_U) == FLAG_U ) 
269                             offset = dissect_authblk(pd, offset, fd, srvloc_tree);
270                         count--;
271                     };
272                 break;
273
274                 case SRVREG:
275                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Registration");
276                     if (!BYTES_ARE_IN_FRAME(offset, 2))
277                         break;
278                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL lifetime: %d", pntohs(&pd[offset]));
279                     offset += 2;
280                     if (!BYTES_ARE_IN_FRAME(offset, 2))
281                         break;
282                     length = pntohs(&pd[offset]);
283                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %u", length);
284                     offset += 2;
285                     if (!BYTES_ARE_IN_FRAME(offset, length))
286                         break;
287                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
288                     offset += length;
289                     if ( (srvloc_hdr.flags & FLAG_U) == FLAG_U ) 
290                         offset = dissect_authblk(pd, offset, fd, srvloc_tree);
291                     if (!BYTES_ARE_IN_FRAME(offset, 2))
292                         break;
293                     length = pntohs(&pd[offset]);
294                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %u", length);
295                     offset += 2;
296                     if (!BYTES_ARE_IN_FRAME(offset, length))
297                         break;
298                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
299                     offset += length;
300                     if ( (srvloc_hdr.flags & FLAG_A) == FLAG_A ) 
301                         offset = dissect_authblk(pd, offset, fd, srvloc_tree);
302                 break;
303
304                 case SRVDEREG:
305                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Deregister");
306                     if (!BYTES_ARE_IN_FRAME(offset, 2))
307                         break;
308                     length = pntohs(&pd[offset]);
309                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %u", length);
310                     offset += 2;
311                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
312                     if (!BYTES_ARE_IN_FRAME(offset, length))
313                         break;
314                     offset += length;
315                     if ( (srvloc_hdr.flags & FLAG_U) == FLAG_U ) 
316                         offset = dissect_authblk(pd, offset, fd, srvloc_tree);
317                     if (!BYTES_ARE_IN_FRAME(offset, 2))
318                         break;
319                     length = pntohs(&pd[offset]);
320                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %u", length);
321                     offset += 2;
322                     if (!BYTES_ARE_IN_FRAME(offset, length))
323                         break;
324                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
325                     offset += length;
326                     if ( (srvloc_hdr.flags & FLAG_A) == FLAG_A ) 
327                         offset = dissect_authblk(pd, offset, fd, srvloc_tree);
328                 break;
329             
330                 case SRVACK:
331                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Acknowledge");
332                     if (!BYTES_ARE_IN_FRAME(offset, 2))
333                         break;
334                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pntohs(&pd[offset]));
335                     offset += 2;
336                 break;
337
338                 case ATTRRQST:
339                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Attribute Request");
340                     if (!BYTES_ARE_IN_FRAME(offset, 2))
341                         break;
342                     length = pntohs(&pd[offset]);
343                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Previous Response List Length: %u", length);
344                     offset += 2;
345                     if (!BYTES_ARE_IN_FRAME(offset, length))
346                         break;
347                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Previous Response List: %s", format_text(&pd[offset], length)); 
348                     offset += length;
349                     if (!BYTES_ARE_IN_FRAME(offset, 2))
350                         break;
351                     length = pntohs(&pd[offset]);
352                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %u", length);
353                     offset += 2;
354                     if (!BYTES_ARE_IN_FRAME(offset, length))
355                         break;
356                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
357                     offset += length;
358                     if (!BYTES_ARE_IN_FRAME(offset, 2))
359                         break;
360                     length = pntohs(&pd[offset]);
361                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Scope List Length: %u", length);
362                     offset += 2;
363                     if (!BYTES_ARE_IN_FRAME(offset, length))
364                         break;
365                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Scope Response List: %s", format_text(&pd[offset], length)); 
366                     offset += length;
367                     if (!BYTES_ARE_IN_FRAME(offset, 2))
368                         break;
369                     length = pntohs(&pd[offset]);
370                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %u", length);
371                     offset += 2;
372                     if (!BYTES_ARE_IN_FRAME(offset, length))
373                         break;
374                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
375                     offset += length;
376                 break;
377             
378                 case ATTRRPLY:
379                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Attribute Reply");
380                     if (!BYTES_ARE_IN_FRAME(offset, 2))
381                         break;
382                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pntohs(&pd[offset]));
383                     offset += 2;
384                     if (!BYTES_ARE_IN_FRAME(offset, 2))
385                         break;
386                     length = pntohs(&pd[offset]);
387                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %u", length);
388                     offset += 2;
389                     if (!BYTES_ARE_IN_FRAME(offset, length))
390                         break;
391                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
392                     offset += length;
393                     if ( (srvloc_hdr.flags & FLAG_A) == FLAG_A ) 
394                         offset = dissect_authblk(pd, offset, fd, srvloc_tree);
395                 break;
396             
397                 case DAADVERT:
398                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "DA Advertisement");
399                     if (!BYTES_ARE_IN_FRAME(offset, 2))
400                         break;
401                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pntohs(&pd[offset]));
402                     offset += 2;
403                     if (!BYTES_ARE_IN_FRAME(offset, 2))
404                         break;
405                     length = pntohs(&pd[offset]);
406                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %u", length);
407                     offset += 2;
408                     if (!BYTES_ARE_IN_FRAME(offset, length))
409                         break;
410                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
411                     offset += length;
412                     if (!BYTES_ARE_IN_FRAME(offset, 2))
413                         break;
414                     length = pntohs(&pd[offset]);
415                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Scope List Length: %u", length);
416                     offset += 2;
417                     if (!BYTES_ARE_IN_FRAME(offset, length))
418                         break;
419                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Scope Response List: %s", format_text(&pd[offset], length)); 
420                     offset += length;
421                 break;
422
423                 case SRVTYPERQST:
424                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Type Request");
425                     if (!BYTES_ARE_IN_FRAME(offset, 2))
426                         break;
427                     length = pntohs(&pd[offset]);
428                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Previous Response List Length: %u", length);
429                     offset += 2;
430                     if (!BYTES_ARE_IN_FRAME(offset, length))
431                         break;
432                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Previous Response List: %s", format_text(&pd[offset], length)); 
433                     offset += length;
434                     if (!BYTES_ARE_IN_FRAME(offset, 2))
435                         break;
436                     length = pntohs(&pd[offset]);
437                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Naming Authority List length: %u", length);
438                     offset += 2;
439                     if (!BYTES_ARE_IN_FRAME(offset, length))
440                         break;
441                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Naming Authority List: %s", format_text(&pd[offset], length)); 
442                     offset += length;
443                     if (!BYTES_ARE_IN_FRAME(offset, 2))
444                         break;
445                     length = pntohs(&pd[offset]);
446                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Scope List Length: %u", length);
447                     offset += 2;
448                     if (!BYTES_ARE_IN_FRAME(offset, length))
449                         break;
450                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Scope Response List: %s", format_text(&pd[offset], length)); 
451                     offset += length;
452                 break;
453
454                 case SRVTYPERPLY:
455                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Type Reply");
456                     if (!BYTES_ARE_IN_FRAME(offset, 2))
457                         break;
458                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pntohs(&pd[offset]));
459                     offset += 2;
460                     if (!BYTES_ARE_IN_FRAME(offset, 2))
461                         break;
462                     count = pntohs(&pd[offset]);
463                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Service Type Count: %u", count);
464                     offset += 2;
465                     while (count > 0) {
466                         if (!BYTES_ARE_IN_FRAME(offset, 2))
467                             break;
468                         length = pntohs(&pd[offset]);
469                         proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Service Type List length: %u", length);
470                         offset += 2;
471                         if (!BYTES_ARE_IN_FRAME(offset, length))
472                             break;
473                         proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service Type List: %s", format_text(&pd[offset], length));
474                         offset += length;
475                         count--;
476                     };
477                 break;
478
479                 default:
480                     proto_tree_add_text(srvloc_tree, NullTVB, offset, END_OF_FRAME, "Unknown Function Type");
481             };
482         } else { proto_tree_add_text(srvloc_tree, NullTVB, offset, END_OF_FRAME,"Invalid packet: Bad length value");
483         };        
484     };
485 };
486
487 /* Register protocol with Ethereal. */
488
489 void
490 proto_register_srvloc(void)
491 {
492     static hf_register_info hf[] = {
493         { &hf_srvloc_version,
494             { "Version",           "srvloc.version",
495             FT_UINT8, BASE_DEC, NULL, 0x0,
496             "" }
497         },
498       
499         {&hf_srvloc_function,
500             {"Function", "srvloc.function", 
501             FT_UINT8, BASE_DEC, VALS(srvloc_functions), 0x0, 
502             ""}
503         },
504
505         {&hf_srvloc_flags,
506             {"Flags", "srvloc.flags", 
507             FT_UINT8, BASE_HEX, NULL, 0x0, 
508             ""}
509         },
510         
511         {&hf_srvloc_error,
512             {"Error Code", "srvloc.err",
513             FT_UINT16, BASE_DEC, VALS(srvloc_errs), 0x0,
514             ""}
515         },
516    };
517                   
518    static gint *ett[] = {
519       &ett_srvloc,
520       &ett_srvloc_flags,
521    };
522
523     proto_srvloc = proto_register_protocol("Service Location Protocol", "srvloc");
524     proto_register_field_array(proto_srvloc, hf, array_length(hf));
525     proto_register_subtree_array(ett, array_length(ett));
526 };
527
528 void
529 proto_reg_handoff_srvloc(void)
530 {
531     old_dissector_add("tcp.port", TCP_PORT_SRVLOC, dissect_srvloc);
532     old_dissector_add("udp.port", UDP_PORT_SRVLOC, dissect_srvloc);
533 }
534