Get rid of the last global variable.
[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.29 2002/01/24 09:20:51 guy Exp $
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
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 <epan/packet.h>
56 #include <epan/strutil.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     { 0, NULL }
110 };
111
112 /* List to resolve flag values to names */
113
114
115 /* Define flag masks */
116
117 #define FLAG_O          0x80
118 #define FLAG_M          0x40
119 #define FLAG_U          0x20
120 #define FLAG_A          0x10
121 #define FLAG_F          0x08
122
123 /* Define Error Codes */
124
125 #define SUCCESS         0
126 #define LANG_NOT_SPTD   1
127 #define PROT_PARSE_ERR  2
128 #define INVLD_REG       3
129 #define SCOPE_NOT_SPTD  4
130 #define CHRSET_NOT_UND  5
131 #define AUTH_ABSENT     6
132 #define AUTH_FAILED     7
133
134 /* List to resolve error codes to names */
135
136 static const value_string srvloc_errs[] = {
137     { SUCCESS, "No Error" },
138     { LANG_NOT_SPTD, "Language not supported" },
139     { PROT_PARSE_ERR, "Protocol parse error" },
140     { INVLD_REG, "Invalid registration" },
141     { SCOPE_NOT_SPTD, "Scope not supported" },
142     { CHRSET_NOT_UND, "Character set not understood" },
143     { AUTH_ABSENT, "Authentication absent" },
144     { AUTH_FAILED, "Authentication failed" },
145     { 0, NULL }
146 };
147
148 /*
149  * Character encodings.
150  * This is a small subset of what's in
151  *
152  *      http://www.isi.edu/in-notes/iana/assignments/character-sets
153  *
154  * XXX - we should do something useful with this, i.e. properly
155  * handle strings based on the character set they're in.
156  *
157  * XXX - what does "properly handle strings" mean?  How do we know
158  * what character set the terminal can handle (for tty-based code)
159  * or the GUI can handle (for GUI code)?
160  *
161  * XXX - the Ethereal core really should be what does all the
162  * character set handling for strings, and it should be stuck with
163  * the task of figuring out how to properly handle them.
164  */
165 #define CHARSET_ASCII           3
166 #define CHARSET_ISO_10646_UTF_1 27
167 #define CHARSET_ISO_646_BASIC   28
168 #define CHARSET_ISO_646_IRV     30
169 #define CHARSET_ISO_8859_1      4
170 #define CHARSET_ISO_10646_UCS_2 1000    /* a/k/a Unicode */
171 #define CHARSET_UTF_7           1012
172 #define CHARSET_UTF_8           106
173
174 static const value_string charsets[] = {
175         { CHARSET_ASCII, "US-ASCII" },
176         { CHARSET_ISO_10646_UTF_1, "ISO 10646 UTF-1" },
177         { CHARSET_ISO_646_BASIC, "ISO 646 basic:1983" },
178         { CHARSET_ISO_646_IRV, "ISO 646 IRV:1983" },
179         { CHARSET_ISO_8859_1, "ISO 8859-1" },
180         { CHARSET_ISO_10646_UCS_2, "Unicode" },
181         { CHARSET_UTF_7, "UTF-7" },
182         { CHARSET_UTF_8, "UTF-8" },
183         { 0, NULL }
184 };
185
186 static int
187 dissect_authblk(tvbuff_t *tvb, int offset, proto_tree *tree)
188 {
189     struct tm *stamp;
190     time_t seconds;
191     double floatsec;
192     guint16 length;
193     
194     seconds = tvb_get_ntohl(tvb, offset) - 2208988800ul;
195     stamp = gmtime(&seconds);
196     if (stamp != NULL) {
197       floatsec = stamp->tm_sec + tvb_get_ntohl(tvb, offset + 4) / 4294967296.0;
198       proto_tree_add_text(tree, tvb, offset, 8,
199                           "Timestamp: %04d-%02d-%02d %02d:%02d:%07.4f UTC",
200                           stamp->tm_year + 1900, stamp->tm_mon + 1,
201                           stamp->tm_mday, stamp->tm_hour, stamp->tm_min,
202                           floatsec);
203     } else {
204       proto_tree_add_text(tree, tvb, offset, 8, "Timestamp not representable");
205     }
206     proto_tree_add_text(tree, tvb, offset + 8, 2, "Block Structure Desciptor: %u",
207                         tvb_get_ntohs(tvb, offset + 8));
208     length = tvb_get_ntohs(tvb, offset + 10);
209     proto_tree_add_text(tree, tvb, offset + 10, 2, "Authenticator length: %u",
210                         length);
211     offset += 12;
212     proto_tree_add_text(tree, tvb, offset, length, "Authentication block: %s",
213                         tvb_format_text(tvb, offset, length));
214     offset += length;
215     return offset;
216 }
217
218 /* Packet dissection routine called by tcp & udp when port 427 detected */
219
220 static void
221 dissect_srvloc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
222 {
223     int offset = 0;
224     proto_item *ti, *tf;
225     proto_tree *srvloc_tree, *srvloc_flags;
226     guint8 version;
227     guint8 function;
228     guint16 encoding;
229     guint16 length;
230     guint8 flags;
231     guint32 count;
232
233     if (check_col(pinfo->cinfo, COL_PROTOCOL))
234         col_set_str(pinfo->cinfo, COL_PROTOCOL, "SRVLOC");
235     
236     if (check_col(pinfo->cinfo, COL_INFO))
237         col_clear(pinfo->cinfo, COL_INFO);
238
239     version = tvb_get_guint8(tvb, offset);
240     function = tvb_get_guint8(tvb, offset + 1);
241
242     if (check_col(pinfo->cinfo, COL_INFO))
243         col_add_str(pinfo->cinfo, COL_INFO,
244             val_to_str(function, srvloc_functions, "Unknown Function (%u)"));
245         
246     if (tree) {
247         ti = proto_tree_add_item(tree, proto_srvloc, tvb, offset, -1, FALSE);
248         srvloc_tree = proto_item_add_subtree(ti, ett_srvloc);
249     
250         proto_tree_add_uint(srvloc_tree, hf_srvloc_version, tvb, offset, 1,
251                             version);
252         proto_tree_add_uint(srvloc_tree, hf_srvloc_function, tvb, offset + 1, 1,
253                             function);
254         length = tvb_get_ntohs(tvb, offset + 2);
255         proto_tree_add_text(srvloc_tree, tvb, offset + 2, 2, "Length: %u",
256                             length);
257         flags = tvb_get_guint8(tvb, offset + 4);
258         tf = proto_tree_add_uint(srvloc_tree, hf_srvloc_flags, tvb, offset + 4, 1,
259                                  flags);
260         srvloc_flags = proto_item_add_subtree(tf, ett_srvloc_flags);
261         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Overflow                          %d... .xxx", (flags & FLAG_O) >> 7 );
262         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Monolingual                       .%d.. .xxx", (flags & FLAG_M) >> 6 );
263         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "URL Authentication Present        ..%d. .xxx", (flags & FLAG_U) >> 5 );
264         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Attribute Authentication Present  ...%d .xxx", (flags & FLAG_A) >> 4 );
265         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Fresh Service Entry               .... %dxxx", (flags & FLAG_F) >> 3 );
266         proto_tree_add_text(srvloc_tree, tvb, offset + 5, 1, "Dialect: %u",
267                             tvb_get_guint8(tvb, offset + 5));
268         proto_tree_add_text(srvloc_tree, tvb, offset + 6, 2, "Language: %s",
269                             tvb_format_text(tvb, offset + 6, 2));
270         encoding = tvb_get_ntohs(tvb, offset + 8);
271         proto_tree_add_text(srvloc_tree, tvb, offset + 8, 2, "Encoding: %u (%s)",
272                             encoding,
273                             val_to_str(encoding, charsets, "Unknown"));
274         proto_tree_add_text(srvloc_tree, tvb, offset + 10, 2, "Transaction ID: %u",
275                             tvb_get_ntohs(tvb, offset + 10));
276         offset += 12;
277         
278         switch (function) {
279             case SRVREQ:
280                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Request");
281                 length = tvb_get_ntohs(tvb, offset);
282                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Previous Response List Length: %u",
283                                     length);
284                 offset += 2;
285                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Previous Response List: %s",
286                                     tvb_format_text(tvb, offset, length));
287                 offset += length;
288                 length = tvb_get_ntohs(tvb, offset);
289                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Predicate length: %u",
290                                     length);
291                 offset += 2;
292                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Predicate: %s",
293                                     tvb_format_text(tvb, offset, length));
294                 offset += length;
295             break;
296             
297             case SRVRPLY:
298                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Reply");
299                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
300                 offset += 2;
301                 count = tvb_get_ntohs(tvb, offset);
302                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL Count: %u",
303                                     count);
304                 offset += 2;
305                 while (count > 0) {
306                     proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL lifetime: %u",
307                                         tvb_get_ntohs(tvb, offset));
308                     offset += 2;
309                     length = tvb_get_ntohs(tvb, offset);
310                     proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
311                                         length);
312                     offset += 2;
313                     proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
314                                         tvb_format_text(tvb, offset, length));
315                     offset += length;
316                     if ( (flags & FLAG_U) == FLAG_U ) 
317                         offset = dissect_authblk(tvb, offset, srvloc_tree);
318                     count--;
319                 };
320             break;
321
322             case SRVREG:
323                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Registration");
324                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL lifetime: %u",
325                                     tvb_get_ntohs(tvb, offset));
326                 offset += 2;
327                 length = tvb_get_ntohs(tvb, offset);
328                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
329                                     length);
330                 offset += 2;
331                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
332                                     tvb_format_text(tvb, offset, length));
333                 offset += length;
334                 if ( (flags & FLAG_U) == FLAG_U ) 
335                     offset = dissect_authblk(tvb, offset, srvloc_tree);
336                 length = tvb_get_ntohs(tvb, offset);
337                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
338                                     length);
339                 offset += 2;
340                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
341                                     tvb_format_text(tvb, offset, length));
342                 offset += length;
343                 if ( (flags & FLAG_A) == FLAG_A ) 
344                     offset = dissect_authblk(tvb, offset, srvloc_tree);
345             break;
346
347             case SRVDEREG:
348                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Deregister");
349                 length = tvb_get_ntohs(tvb, offset);
350                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
351                                     length);
352                 offset += 2;
353                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
354                                     tvb_format_text(tvb, offset, length));
355                 offset += length;
356                 if ( (flags & FLAG_U) == FLAG_U ) 
357                     offset = dissect_authblk(tvb, offset, srvloc_tree);
358                 length = tvb_get_ntohs(tvb, offset);
359                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
360                                     length);
361                 offset += 2;
362                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
363                                     tvb_format_text(tvb, offset, length));
364                 offset += length;
365                 if ( (flags & FLAG_A) == FLAG_A ) 
366                     offset = dissect_authblk(tvb, offset, srvloc_tree);
367             break;
368             
369             case SRVACK:
370                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Acknowledge");
371                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
372                 offset += 2;
373             break;
374
375             case ATTRRQST:
376                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Attribute Request");
377                 length = tvb_get_ntohs(tvb, offset);
378                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Previous Response List Length: %u",
379                                     length);
380                 offset += 2;
381                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Previous Response List: %s",
382                                     tvb_format_text(tvb, offset, length));
383                 offset += length;
384                 length = tvb_get_ntohs(tvb, offset);
385                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
386                                     length);
387                 offset += 2;
388                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
389                                     tvb_format_text(tvb, offset, length));
390                 offset += length;
391                 length = tvb_get_ntohs(tvb, offset);
392                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Scope List Length: %u",
393                                     length);
394                 offset += 2;
395                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Scope Response List: %s",
396                                     tvb_format_text(tvb, offset, length));
397                 offset += length;
398                 length = tvb_get_ntohs(tvb, offset);
399                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
400                                     length);
401                 offset += 2;
402                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
403                                     tvb_format_text(tvb, offset, length));
404                 offset += length;
405             break;
406             
407             case ATTRRPLY:
408                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Attribute Reply");
409                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
410                 offset += 2;
411                 length = tvb_get_ntohs(tvb, offset);
412                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
413                                     length);
414                 offset += 2;
415                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
416                                     tvb_format_text(tvb, offset, length));
417                 offset += length;
418                 if ( (flags & FLAG_A) == FLAG_A ) 
419                     offset = dissect_authblk(tvb, offset, srvloc_tree);
420             break;
421             
422             case DAADVERT:
423                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "DA Advertisement");
424                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
425                 offset += 2;
426                 length = tvb_get_ntohs(tvb, offset);
427                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
428                                     length);
429                 offset += 2;
430                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
431                                     tvb_format_text(tvb, offset, length));
432                 offset += length;
433                 length = tvb_get_ntohs(tvb, offset);
434                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Scope List Length: %u",
435                                     length);
436                 offset += 2;
437                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Scope Response List: %s",
438                                     tvb_format_text(tvb, offset, length));
439                 offset += length;
440             break;
441
442             case SRVTYPERQST:
443                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Type Request");
444                 length = tvb_get_ntohs(tvb, offset);
445                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Previous Response List Length: %u",
446                                     length);
447                 offset += 2;
448                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Previous Response List: %s",
449                                     tvb_format_text(tvb, offset, length));
450                 offset += length;
451                 length = tvb_get_ntohs(tvb, offset);
452                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Naming Authority List length: %u",
453                                     length);
454                 offset += 2;
455                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Naming Authority List: %s",
456                                     tvb_format_text(tvb, offset, length));
457                 offset += length;
458                 length = tvb_get_ntohs(tvb, offset);
459                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Scope List Length: %u",
460                                     length);
461                 offset += 2;
462                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Scope Response List: %s",
463                                     tvb_format_text(tvb, offset, length));
464                 offset += length;
465             break;
466
467             case SRVTYPERPLY:
468                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Type Reply");
469                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
470                 offset += 2;
471                 count = tvb_get_ntohs(tvb, offset);
472                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Service Type Count: %u",
473                                     count);
474                 offset += 2;
475                 while (count > 0) {
476                     length = tvb_get_ntohs(tvb, offset);
477                     proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Service Type List length: %u",
478                                         length);
479                     offset += 2;
480                     proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service Type List: %s",
481                                         tvb_format_text(tvb, offset, length));
482                     offset += length;
483                     count--;
484                 };
485             break;
486
487             default:
488                 proto_tree_add_text(srvloc_tree, tvb, offset, -1, "Unknown Function Type");
489         };
490     };
491 }
492
493 /* Register protocol with Ethereal. */
494
495 void
496 proto_register_srvloc(void)
497 {
498     static hf_register_info hf[] = {
499         { &hf_srvloc_version,
500             { "Version",           "srvloc.version",
501             FT_UINT8, BASE_DEC, NULL, 0x0,
502             "", HFILL }
503         },
504       
505         {&hf_srvloc_function,
506             {"Function", "srvloc.function", 
507             FT_UINT8, BASE_DEC, VALS(srvloc_functions), 0x0, 
508             "", HFILL }
509         },
510
511         {&hf_srvloc_flags,
512             {"Flags", "srvloc.flags", 
513             FT_UINT8, BASE_HEX, NULL, 0x0, 
514             "", HFILL }
515         },
516         
517         {&hf_srvloc_error,
518             {"Error Code", "srvloc.err",
519             FT_UINT16, BASE_DEC, VALS(srvloc_errs), 0x0,
520             "", HFILL }
521         },
522     };
523                   
524     static gint *ett[] = {
525         &ett_srvloc,
526         &ett_srvloc_flags,
527     };
528
529     proto_srvloc = proto_register_protocol("Service Location Protocol",
530                                            "SRVLOC", "srvloc");
531     proto_register_field_array(proto_srvloc, hf, array_length(hf));
532     proto_register_subtree_array(ett, array_length(ett));
533 };
534
535 void
536 proto_reg_handoff_srvloc(void)
537 {
538     dissector_handle_t srvloc_handle;
539
540     srvloc_handle = create_dissector_handle(dissect_srvloc, proto_srvloc);
541     dissector_add("tcp.port", TCP_PORT_SRVLOC, srvloc_handle);
542     dissector_add("udp.port", UDP_PORT_SRVLOC, srvloc_handle);
543 }