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