Add routines for adding items to a protocol tree that take arguments of
[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.9 2000/05/31 05:07:48 guy 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 #ifdef NEED_SNPRINTF_H
48 # ifdef HAVE_STDARG_H
49 #  include <stdarg.h>
50 # else
51 #  include <varargs.h>
52 # endif
53 # include "snprintf.h"
54 #endif
55
56 #include <string.h>
57 #include <time.h>
58 #include <glib.h>
59 #include "packet.h"
60 #include "packet-ipv6.h"
61
62 static int proto_srvloc = -1;
63 static int hf_srvloc_version = -1;
64 static int hf_srvloc_function = -1;
65 static int hf_srvloc_flags = -1;
66 static int hf_srvloc_error = -1;
67
68 static gint ett_srvloc = -1;
69 static gint ett_srvloc_flags = -1;
70
71 #define TCP_PORT_SRVLOC 427
72 #define UDP_PORT_SRVLOC 427
73
74 /* Define function types */
75
76 #define SRVREQ          1
77 #define SRVRPLY         2
78 #define SRVREG          3
79 #define SRVDEREG        4
80 #define SRVACK          5
81 #define ATTRRQST        6
82 #define ATTRRPLY        7
83 #define DAADVERT        8
84 #define SRVTYPERQST     9
85 #define SRVTYPERPLY     10
86
87 /* Create protocol header structure */
88
89 struct srvloc_hdr {
90     guint8      version;
91     guint8      function;
92     guint16     length;
93     guint8      flags;
94     guint8      dialect;
95     u_char      language[2];
96     guint16     encoding;
97     guint16     xid;
98 };
99
100 /* List to resolve function numbers to names */
101
102 static const value_string srvloc_functions[] = {
103     { SRVREQ, "Service Request" }, 
104     { SRVRPLY, "Service Reply" }, 
105     { SRVREG, "Service Registration" }, 
106     { SRVDEREG, "Service Deregister" }, 
107     { SRVACK, "Service Acknowledge" }, 
108     { ATTRRQST, "Attribute Request" }, 
109     { ATTRRPLY, "Attribute Reply" }, 
110     { DAADVERT, "DA Advertisement" }, 
111     { SRVTYPERQST, "Service Type Request" }, 
112     { SRVTYPERPLY, "Service Type Reply" }, 
113 };
114
115 /* List to resolve flag values to names */
116
117
118 /* Define flag masks */
119
120 #define FLAG_O          0x80
121 #define FLAG_M          0x40
122 #define FLAG_U          0x20
123 #define FLAG_A          0x10
124 #define FLAG_F          0x08
125
126 /* Define Error Codes */
127
128 #define SUCCESS         0
129 #define LANG_NOT_SPTD   1
130 #define PROT_PARSE_ERR  2
131 #define INVLD_REG       3
132 #define SCOPE_NOT_SPTD  4
133 #define CHRSET_NOT_UND  5
134 #define AUTH_ABSENT     6
135 #define AUTH_FAILED     7
136
137 /* List to resolve error codes to names */
138
139 static const value_string srvloc_errs[] = {
140     { SUCCESS, "No Error" },
141     { LANG_NOT_SPTD, "Language not supported" },
142     { PROT_PARSE_ERR, "Protocol parse error" },
143     { INVLD_REG, "Invalid registration" },
144     { SCOPE_NOT_SPTD, "Scope not supported" },
145     { CHRSET_NOT_UND, "Character set not understood" },
146     { AUTH_ABSENT, "Authentication absent" },
147     { AUTH_FAILED, "Authentication failed" },
148 };
149
150 void
151 dissect_authblk(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
152 {
153     struct tm *stamp;
154     time_t seconds;
155     double floatsec;
156     guint16 length;
157     
158     seconds = pntohl(&pd[offset]) - 2208988800ul;
159     stamp = gmtime(&seconds);
160     floatsec = stamp->tm_sec + pntohl(&pd[offset + 4]) / 4294967296.0;
161     proto_tree_add_text(tree, NullTVB, offset, 8,
162                         "Timestamp: %04d-%02d-%02d %02d:%02d:%07.4f UTC",
163                         stamp->tm_year + 1900, stamp->tm_mon + 1,
164                         stamp->tm_mday, stamp->tm_hour, stamp->tm_min,
165                         floatsec);
166     proto_tree_add_text(tree, NullTVB, offset + 8, 2, "Block Structure Desciptor: %u",
167                         pntohs(&pd[offset + 8]));
168     length = pntohs(&pd[offset + 10]);
169     proto_tree_add_text(tree, NullTVB, offset + 10, 2, "Authenticator length: %u",
170                         length);
171     offset += 12;
172     proto_tree_add_text(tree, NullTVB, offset, length, "Authentication block: %s",
173                         format_text(&pd[offset], length));
174     offset += length;
175 };
176
177 /* Packet dissection routine called by tcp & udp when port 427 detected */
178
179 static void
180 dissect_srvloc(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
181 {
182     proto_item *ti, *tf;
183     proto_tree *srvloc_tree, *srvloc_flags;
184     struct srvloc_hdr srvloc_hdr;
185     int count;
186     int length;
187     
188     if (check_col(fd, COL_PROTOCOL))
189         col_add_str(fd, COL_PROTOCOL, "SRVLOC");
190     
191     if (check_col(fd, COL_INFO))
192         col_add_str(fd, COL_INFO, val_to_str(pd[offset + 1], srvloc_functions, "Unknown Function (%d)"));
193         
194     if (tree) {
195         ti = proto_tree_add_item(tree, proto_srvloc, NullTVB, offset, END_OF_FRAME, FALSE);
196         srvloc_tree = proto_item_add_subtree(ti, ett_srvloc);
197     
198         if ( END_OF_FRAME > sizeof(srvloc_hdr) ) {
199             memcpy( &srvloc_hdr, &pd[offset], sizeof(srvloc_hdr) );
200             srvloc_hdr.length = pntohs(&srvloc_hdr.length);
201             srvloc_hdr.encoding = pntohs(&srvloc_hdr.encoding);
202             srvloc_hdr.xid = pntohs(&srvloc_hdr.xid);
203             proto_tree_add_uint(srvloc_tree, hf_srvloc_version, NullTVB, offset, 1, srvloc_hdr.version);
204             proto_tree_add_uint(srvloc_tree, hf_srvloc_function, NullTVB, offset + 1, 1, srvloc_hdr.function);
205             proto_tree_add_text(srvloc_tree, NullTVB, offset + 2, 2, "Length: %d",srvloc_hdr.length);
206             tf = proto_tree_add_uint(srvloc_tree, hf_srvloc_flags, NullTVB, offset + 4, 1, srvloc_hdr.flags);
207             srvloc_flags = proto_item_add_subtree(tf, ett_srvloc_flags);
208             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Overflow                          %d... .xxx", (srvloc_hdr.flags & FLAG_O) >> 7 );
209             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Monolingual                       .%d.. .xxx", (srvloc_hdr.flags & FLAG_M) >> 6 ); 
210             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "URL Authentication Present        ..%d. .xxx", (srvloc_hdr.flags & FLAG_U) >> 5 );
211             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Attribute Authentication Present  ...%d .xxx", (srvloc_hdr.flags & FLAG_A) >> 4 );
212             proto_tree_add_text(srvloc_flags, NullTVB, offset + 4, 0, "Fresh Service Entry               .... %dxxx", (srvloc_hdr.flags & FLAG_F) >> 3 );
213             proto_tree_add_text(srvloc_tree, NullTVB, offset + 5, 1, "Dialect: %d",srvloc_hdr.dialect); 
214             proto_tree_add_text(srvloc_tree, NullTVB, offset + 6, 2, "Language: %s", format_text(srvloc_hdr.language,2));
215             proto_tree_add_text(srvloc_tree, NullTVB, offset + 8, 2, "Encoding: %d", srvloc_hdr.encoding);
216             proto_tree_add_text(srvloc_tree, NullTVB, offset + 10, 2, "Transaction ID: %d", srvloc_hdr.xid);
217             offset += 12;
218         } else {
219         proto_tree_add_text(srvloc_tree, NullTVB, offset, END_OF_FRAME, "Invalid Packet: Length less than header.");
220         };
221         
222         if (( srvloc_hdr.length - 12 ) == END_OF_FRAME ) {
223             switch (srvloc_hdr.function) {
224                 case SRVREQ:
225                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Request");
226                     length = pntohs(&pd[offset]);
227                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Previous Response List Length: %d", length);
228                     offset += 2;
229                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Previous Response List: %s", format_text(&pd[offset], length)); 
230                     offset += length;
231                     length = pntohs(&pd[offset]);
232                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Predicate length: %d", length);
233                     offset += 2;
234                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Predicate: %s", format_text(&pd[offset], length));
235                     offset += length;
236                 break;
237             
238                 case SRVRPLY:
239                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Reply");
240                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pd[offset]);;
241                     offset += 2;
242                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL Count: %d", pntohs(&pd[offset]));
243                     offset += 2;
244                     for (count = pntohs(&pd[offset]) + 1; count > 0; count--, offset++) {
245                         proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL lifetime: %d", pntohs(&pd[offset]));
246                         offset += 2;
247                         length = pntohs(&pd[offset]);
248                         proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %d", length);
249                         offset += 2;
250                         proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
251                         offset += length;
252                         if ( (srvloc_hdr.flags & FLAG_U) == FLAG_U ) 
253                             dissect_authblk(pd, offset, fd, srvloc_tree);
254                     };
255                 break;
256
257                 case SRVREG:
258                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Registration");
259                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL lifetime: %d", pntohs(&pd[offset]));
260                     offset += 2;
261                     length = pntohs(&pd[offset]);
262                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %d", length);
263                     offset += 2;
264                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
265                     offset += length;
266                     if ( (srvloc_hdr.flags & FLAG_U) == FLAG_U ) 
267                         dissect_authblk(pd, offset, fd, srvloc_tree);
268                     length = pntohs(&pd[offset]);
269                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %d", length);
270                     offset += 2;
271                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
272                     offset += length;
273                     if ( (srvloc_hdr.flags & FLAG_A) == FLAG_A ) 
274                         dissect_authblk(pd, offset, fd, srvloc_tree);
275                 break;
276
277                 case SRVDEREG:
278                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Deregister");
279                     length = pntohs(&pd[offset]);
280                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %d", length);
281                     offset += 2;
282                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
283                     offset += length;
284                     if ( (srvloc_hdr.flags & FLAG_U) == FLAG_U ) 
285                         dissect_authblk(pd, offset, fd, srvloc_tree);
286                     length = pntohs(&pd[offset]);
287                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %d", length);
288                     offset += 2;
289                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
290                     offset += length;
291                     if ( (srvloc_hdr.flags & FLAG_A) == FLAG_A ) 
292                         dissect_authblk(pd, offset, fd, srvloc_tree);
293                 break;
294             
295                 case SRVACK:
296                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Acknowledge");
297                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pd[offset]);;
298                     offset += 2;
299                 break;
300
301                 case ATTRRQST:
302                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Attribute Request");
303                     length = pntohs(&pd[offset]);
304                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Previous Response List Length: %d", length);
305                     offset += 2;
306                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Previous Response List: %s", format_text(&pd[offset], length)); 
307                     offset += length;
308                     length = pntohs(&pd[offset]);
309                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %d", length);
310                     offset += 2;
311                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
312                     offset += length;
313                     length = pntohs(&pd[offset]);
314                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Scope List Length: %d", length);
315                     offset += 2;
316                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Scope Response List: %s", format_text(&pd[offset], length)); 
317                     offset += length;
318                     length = pntohs(&pd[offset]);
319                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %d", length);
320                     offset += 2;
321                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
322                     offset += length;
323                 break;
324             
325                 case ATTRRPLY:
326                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Attribute Reply");
327                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pd[offset]);;
328                     offset += 2;
329                     length = pntohs(&pd[offset]);
330                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Attribute List length: %d", length);
331                     offset += 2;
332                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Attribute List: %s", format_text(&pd[offset], length));
333                     offset += length;
334                     if ( (srvloc_hdr.flags & FLAG_A) == FLAG_A ) 
335                         dissect_authblk(pd, offset, fd, srvloc_tree);
336                 break;
337             
338                 case DAADVERT:
339                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "DA Advertisement");
340                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pd[offset]);;
341                     offset += 2;
342                     length = pntohs(&pd[offset]);
343                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "URL length: %d", length);
344                     offset += 2;
345                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service URL: %s", format_text(&pd[offset], length));
346                     offset += length;
347                     length = pntohs(&pd[offset]);
348                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Scope List Length: %d", length);
349                     offset += 2;
350                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Scope Response List: %s", format_text(&pd[offset], length)); 
351                     offset += length;
352                 break;
353
354                 case SRVTYPERQST:
355                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Type Request");
356                     length = pntohs(&pd[offset]);
357                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Previous Response List Length: %d", length);
358                     offset += 2;
359                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Previous Response List: %s", format_text(&pd[offset], length)); 
360                     offset += length;
361                     length = pntohs(&pd[offset]);
362                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Naming Authority List length: %d", length);
363                     offset += 2;
364                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Naming Authority List: %s", format_text(&pd[offset], length)); 
365                     offset += length;
366                     length = pntohs(&pd[offset]);
367                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Scope List Length: %d", length);
368                     offset += 2;
369                     proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Scope Response List: %s", format_text(&pd[offset], length)); 
370                     offset += length;
371                 break;
372
373                 case SRVTYPERPLY:
374                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 0, "Service Type Reply");
375                     proto_tree_add_uint(srvloc_tree, hf_srvloc_error, NullTVB, offset, 2, pd[offset]);;
376                     offset += 2;
377                     proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Service Type Count: %d", pntohs(&pd[offset]));
378                     offset += 2;
379                     for (count = pntohs(&pd[offset]) + 1; count > 0; count--, offset++) {
380                         length = pntohs(&pd[offset]);
381                         proto_tree_add_text(srvloc_tree, NullTVB, offset, 2, "Service Type List length: %d", length);
382                         offset += 2;
383                         proto_tree_add_text(srvloc_tree, NullTVB, offset, length, "Service Type List: %s", format_text(&pd[offset], length));
384                         offset += length;
385                     };
386                 break;
387
388                 default:
389                     proto_tree_add_text(srvloc_tree, NullTVB, offset, END_OF_FRAME, "Unknown Function Type");
390             };
391         } else { proto_tree_add_text(srvloc_tree, NullTVB, offset, END_OF_FRAME,"Invalid packet: Bad length value");
392         };        
393     };
394 };
395
396 /* Register protocol with Ethereal. */
397
398 void
399 proto_register_srvloc(void)
400 {
401     static hf_register_info hf[] = {
402         { &hf_srvloc_version,
403             { "Version",           "srvloc.version",
404             FT_UINT8, BASE_DEC, NULL, 0x0,
405             "" }
406         },
407       
408         {&hf_srvloc_function,
409             {"Function", "srvloc.function", 
410             FT_UINT8, BASE_DEC, VALS(srvloc_functions), 0x0, 
411             ""}
412         },
413
414         {&hf_srvloc_flags,
415             {"Flags", "srvloc.flags", 
416             FT_UINT8, BASE_HEX, NULL, 0x0, 
417             ""}
418         },
419         
420         {&hf_srvloc_error,
421             {"Error Code", "srvloc.err",
422             FT_UINT8, BASE_DEC, VALS(srvloc_errs), 0x0,
423             ""}
424         },
425    };
426                   
427    static gint *ett[] = {
428       &ett_srvloc,
429       &ett_srvloc_flags,
430    };
431
432     proto_srvloc = proto_register_protocol("Service Location Protocol", "srvloc");
433     proto_register_field_array(proto_srvloc, hf, array_length(hf));
434     proto_register_subtree_array(ett, array_length(ett));
435 };
436
437 void
438 proto_reg_handoff_srvloc(void)
439 {
440     dissector_add("tcp.port", TCP_PORT_SRVLOC, dissect_srvloc);
441     dissector_add("udp.port", UDP_PORT_SRVLOC, dissect_srvloc);
442 }
443