1 /* packet-wsp.c (c) 2000 Neil Hunter
2 * Based on original work by Ben Fowler
4 * Routines to dissect WSP component of WAP traffic.
6 * $Id: packet-wsp.c,v 1.1 2000/11/04 03:30:40 guy Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@zing.org>
10 * Copyright 1998 Didier Jorand
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
42 #ifdef NEED_SNPRINTF_H
48 # include "snprintf.h"
54 #include "packet-wap.h"
55 #include "packet-wsp.h"
57 /* File scoped variables for the protocol and registered fields */
58 static int proto_wsp = HF_EMPTY;
60 /* These fields used by fixed part of header */
61 static int hf_wsp_header_tid = HF_EMPTY;
62 static int hf_wsp_header_pdu_type = HF_EMPTY;
63 static int hf_wsp_version_major = HF_EMPTY;
64 static int hf_wsp_version_minor = HF_EMPTY;
65 static int hf_wsp_capability_length = HF_EMPTY;
66 static int hf_wsp_capabilities_section = HF_EMPTY;
67 static int hf_wsp_header_uri_len = HF_EMPTY;
68 static int hf_wsp_header_uri = HF_EMPTY;
69 static int hf_wsp_server_session_id = HF_EMPTY;
70 static int hf_wsp_header_status = HF_EMPTY;
71 static int hf_wsp_header_length = HF_EMPTY;
72 static int hf_wsp_headers_section = HF_EMPTY;
73 static int hf_wsp_header = HF_EMPTY;
74 static int hf_wsp_content_type = HF_EMPTY;
75 static int hf_wsp_parameter_well_known_charset = HF_EMPTY;
76 static int hf_wsp_reply_data = HF_EMPTY;
77 static int hf_wsp_post_data = HF_EMPTY;
79 static int hf_wsp_header_accept = HF_EMPTY;
80 static int hf_wsp_header_accept_str = HF_EMPTY;
81 static int hf_wsp_header_accept_charset = HF_EMPTY;
82 static int hf_wsp_header_accept_language = HF_EMPTY;
83 static int hf_wsp_header_accept_ranges = HF_EMPTY;
84 static int hf_wsp_header_cache_control = HF_EMPTY;
85 static int hf_wsp_header_content_length = HF_EMPTY;
86 static int hf_wsp_header_age = HF_EMPTY;
87 static int hf_wsp_header_date = HF_EMPTY;
88 static int hf_wsp_header_etag = HF_EMPTY;
89 static int hf_wsp_header_expires = HF_EMPTY;
90 static int hf_wsp_header_last_modified = HF_EMPTY;
91 static int hf_wsp_header_location = HF_EMPTY;
92 static int hf_wsp_header_if_modified_since = HF_EMPTY;
93 static int hf_wsp_header_server = HF_EMPTY;
94 static int hf_wsp_header_user_agent = HF_EMPTY;
95 static int hf_wsp_header_application_header = HF_EMPTY;
96 static int hf_wsp_header_application_value = HF_EMPTY;
97 static int hf_wsp_header_x_wap_tod = HF_EMPTY;
99 /* Initialize the subtree pointers */
100 static gint ett_wsp = ETT_EMPTY;
101 static gint ett_header = ETT_EMPTY;
102 static gint ett_headers = ETT_EMPTY;
103 static gint ett_capabilities = ETT_EMPTY;
104 static gint ett_content_type = ETT_EMPTY;
106 static const value_string vals_pdu_type[] = {
107 { 0x00, "Reserved" },
109 { 0x02, "ConnectReply" },
110 { 0x03, "Redirect" },
112 { 0x05, "Disconnect" },
114 { 0x07, "ConfirmedPush" },
118 /* 0x10 - 0x3F Unassigned */
126 /* 0x45 - 0x4F Unassigned (Get PDU) */
127 /* 0x50 - 0x5F Extended method (Get PDU) */
132 /* 0x62 - 0x6F Unassigned (Post PDU) */
133 /* 0x70 - 0x7F Extended method (Post PDU) */
134 /* 0x80 - 0xFF Reserved */
138 static const value_string vals_status[] = {
139 /* 0x00 - 0x0F Reserved */
141 { 0x10, "Continue" },
142 { 0x11, "Switching Protocols" },
146 { 0x22, "Accepted" },
147 { 0x23, "Non-Authoritative Information" },
148 { 0x24, "No Content" },
149 { 0x25, "Reset Content" },
150 { 0x26, "Partial Content" },
152 { 0x30, "Multiple Choices" },
153 { 0x31, "Moved Permanently" },
154 { 0x32, "Moved Temporarily" },
155 { 0x33, "See Other" },
156 { 0x34, "Not Modified" },
157 { 0x35, "Use Proxy" },
159 { 0x40, "Bad Request" },
160 { 0x41, "Unauthorised" },
161 { 0x42, "Payment Required" },
162 { 0x43, "Forbidden" },
163 { 0x44, "Not Found" },
164 { 0x45, "Method Not Allowed" },
165 { 0x46, "Not Acceptable" },
166 { 0x47, "Proxy Authentication Required" },
167 { 0x48, "Request Timeout" },
168 { 0x49, "Conflict" },
170 { 0x4B, "Length Required" },
171 { 0x4C, "Precondition Failed" },
172 { 0x4D, "Request Entity Too Large" },
173 { 0x4E, "Request-URI Too Large" },
174 { 0x4F, "Unsupported Media Type" },
176 { 0x60, "Internal Server Error" },
177 { 0x61, "Not Implemented" },
178 { 0x62, "Bad Gateway" },
179 { 0x63, "Service Unavailable" },
180 { 0x64, "Gateway Timeout" },
181 { 0x65, "HTTP Version Not Supported" },
184 static const value_string vals_content_types[] = {
187 { 0x02, "text/html" },
188 { 0x03, "text/plain" },
189 { 0x04, "text/x-hdml" },
190 { 0x05, "text/x-ttml" },
191 { 0x06, "text/x-vCalendar" },
192 { 0x07, "text/x-vCard" },
193 { 0x08, "text/vnd.wap.wml" },
194 { 0x09, "text/vnd.wap.wmlscript" },
195 { 0x0A, "text/vnd.wap.channel" },
196 { 0x0B, "Multipart/*" },
197 { 0x0C, "Multipart/mixed" },
198 { 0x0D, "Multipart/form-data" },
199 { 0x0E, "Multipart/byteranges" },
200 { 0x0F, "Multipart/alternative" },
201 { 0x10, "application/*" },
202 { 0x11, "application/java-vm" },
203 { 0x12, "application/x-www-form-urlencoded" },
204 { 0x13, "application/x-hdmlc" },
205 { 0x14, "application/vnd.wap.wmlc" },
206 { 0x15, "application/vnd.wap.wmlscriptc" },
207 { 0x16, "application/vnd.wap.channelc" },
208 { 0x17, "application/vnd.wap.uaprof" },
209 { 0x18, "application/vnd.wap.wtls-ca-certificate" },
210 { 0x19, "application/vnd.wap.wtls-user-certificate" },
211 { 0x1A, "application/x-x509-ca-cert" },
212 { 0x1B, "application/x-x509-user-cert" },
214 { 0x1D, "image/gif" },
215 { 0x1E, "image/jpeg" },
216 { 0x1F, "image/tiff" },
217 { 0x20, "image/png" },
218 { 0x21, "image/vnd.wap.wbmp" },
219 { 0x22, "application/vnd.wap.multipart.*" },
220 { 0x23, "application/vnd.wap.multipart.mixed" },
221 { 0x24, "application/vnd.wap.multipart.form-data" },
222 { 0x25, "application/vnd.wap.multipart.byteranges" },
223 { 0x26, "application/vnd.wap.multipart.alternative" },
224 { 0x27, "application/xml" },
225 { 0x28, "text/xml" },
226 { 0x29, "application/vnd.wap.wbxml" },
227 { 0x2A, "application/x-x968-cross-cert" },
228 { 0x2B, "application/x-x968-ca-cert" },
229 { 0x2C, "application/x-x968-user-cert" },
230 { 0x2D, "text/vnd.wap.si" },
231 { 0x2E, "application/vnd.wap.sic" },
232 { 0x2F, "text/vnd.wap.sl" },
233 { 0x30, "application/vnd.wap.slc" },
234 { 0x31, "text/vnd.wap.co" },
235 { 0x32, "application/vnd.wap.coc" },
236 { 0x33, "application/vnd.wap.multipart.related" },
237 { 0x34, "application/vnd.wap.sia" },
240 static const value_string vals_character_sets[] = {
241 { 0x0003, "us-ascii" },
242 { 0x0004, "iso-8859-1" },
243 { 0x0005, "iso-8859-2" },
244 { 0x0006, "iso-8859-3" },
245 { 0x0007, "iso-8859-4" },
246 { 0x0008, "iso-8859-5" },
247 { 0x0009, "iso-8859-6" },
248 { 0x000A, "iso-8859-7" },
249 { 0x000B, "iso-8859-8" },
250 { 0x000C, "iso-8859-9" },
251 { 0x0011, "shift_JIS" },
253 { 0x03E8, "iso-10646-ucs-2" },
257 static const value_string vals_languages[] = {
258 { 0x19, "English (en)" },
261 static const value_string vals_accept_ranges[] = {
266 static const value_string vals_cache_control[] = {
267 { 0x80, "No-cache" },
268 { 0x81, "No-store" },
270 { 0x83, "Max-stale" },
271 { 0x84, "Min-fresh" },
272 { 0x85, "Only-if-cached" },
275 { 0x88, "No-transform" },
276 { 0x89, "Must-revalidate" },
277 { 0x8A, "Proxy-revalidate" },
284 REDIRECT = 0x03, /* No sample data */
287 PUSH = 0x06, /* No sample data */
288 CONFIRMEDPUSH = 0x07, /* No sample data */
289 SUSPEND = 0x08, /* No sample data */
290 RESUME = 0x09, /* No sample data */
293 OPTIONS = 0x41, /* No sample data */
294 HEAD = 0x42, /* No sample data */
295 DELETE = 0x43, /* No sample data */
296 TRACE = 0x44, /* No sample data */
299 PUT = 0x61, /* No sample data */
302 void add_uri (proto_tree *, tvbuff_t *, guint, guint);
303 void add_headers (proto_tree *, tvbuff_t *);
304 void add_header (proto_tree *, tvbuff_t *, tvbuff_t *);
305 guint get_value_length (tvbuff_t *, guint, guint *);
306 guint add_content_type (proto_tree *, tvbuff_t *, guint, guint *);
307 guint add_parameter (proto_tree *, tvbuff_t *, guint);
308 guint add_parameter_charset (proto_tree *, tvbuff_t *, guint, guint);
309 void add_post_data (proto_tree *, tvbuff_t *, guint);
310 void add_post_variable (proto_tree *, tvbuff_t *, guint, guint, guint, guint);
313 * Accessor to retrieve variable length int as used in WAP protocol.
314 * The value is encoded in the lower 7 bits. If the top bit is set, then the
315 * value continues into the next byte.
316 * The octetCount parameter holds the number of bytes read in order to return
317 * the final value. Can be pre-initialised to start at offset+count.
320 tvb_get_guintvar (tvbuff_t *tvb, guint offset, guint *octetCount)
327 if (octetCount != NULL)
330 fprintf (stderr, "dissect_wsp: Starting tvb_get_guintvar at offset %d, count=NULL\n", offset);
336 fprintf (stderr, "dissect_wsp: Starting tvb_get_guintvar at offset %d, count=%d\n", offset, *octetCount);
338 counter = *octetCount;
343 value<<=7; /* Value only exists in 7 of the 8 bits */
344 octet = tvb_get_guint8 (tvb, offset+counter);
346 value += (octet & 0x7F);
347 cont = (octet & 0x80);
349 fprintf (stderr, "dissect_wsp: octet is %d (0x%02x), count=%d, value=%d, cont=%d\n", octet, octet, counter, value, cont);
353 if (octetCount != NULL)
355 *octetCount = counter;
357 fprintf (stderr, "dissect_wsp: Leaving tvb_get_guintvar count=%d\n", *octetCount);
365 dissect_wsp_no_tvbuff(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
367 packet_info *pinfo = π
368 tvbuff_t *tvb = tvb_create_from_top(offset);
369 dissect_wsp (tvb, pinfo, tree);
372 /* Code to actually dissect the packets */
374 dissect_wsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
376 frame_data *fdata = pinfo->fd;
386 guint capabilityLength = 0;
387 guint capabilityStart = 0;
388 guint headersLength = 0;
389 guint headerLength = 0;
390 guint headerStart = 0;
391 guint nextOffset = 0;
392 guint contentTypeStart = 0;
393 guint contentType = 0;
396 /* Set up structures we will need to add the protocol subtree and manage it */
398 proto_tree *wsp_tree;
399 /* proto_tree *wsp_header_fixed; */
400 proto_tree *wsp_capabilities;
402 /* This field shows up as the "Info" column in the display; you should make
403 it, if possible, summarize what's in the packet, so that a user looking
404 at the list of packets can tell what type of packet it is.
405 "col_add_fstr()" can be used instead of "col_add_str()"; it takes
406 "printf()"-like arguments. */
408 /* Display protocol type depending on the port */
409 if (check_col(fdata, COL_PROTOCOL))
411 switch ( pinfo->match_port )
414 col_add_fstr(fdata, COL_PROTOCOL, "WSP" );
416 case UDP_PORT_WTLS_WSP:
417 col_add_fstr(fdata, COL_PROTOCOL, "WTLS+WSP" );
422 /* Connection-less mode has a TID first */
423 if ((pinfo->match_port == UDP_PORT_WSP) || (pinfo->match_port == UDP_PORT_WTLS_WSP))
428 /* Find the PDU type */
429 pdut = tvb_get_guint8 (tvb, offset);
431 /* Develop the string to put in the Info column */
432 cchInfo = snprintf( szInfo, sizeof( szInfo ), "WSP %s",
433 match_strval (( int )pdut, vals_pdu_type));
434 if (check_col(fdata, COL_INFO)) {
435 col_add_str(fdata, COL_INFO, szInfo );
438 /* In the interest of speed, if "tree" is NULL, don't do any work not
439 necessary to generate protocol tree items. */
441 /* NOTE: The offset and length values in the previous call to
442 "proto_tree_add_item()" define what data bytes to highlight in the hex
443 display window when the line in the protocol tree display
444 corresponding to that item is selected.
446 END_OF_FRAME is a handy way to highlight all data from the offset to
447 the end of the packet. */
448 /* ti = proto_tree_add_item(tree, proto_wsp, NullTVB, offset, END_OF_FRAME, NULL); */
450 ti = proto_tree_add_item(tree, proto_wsp, tvb, offset, END_OF_FRAME, NULL);
451 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
454 ti = proto_tree_add_item(tree, proto_wsp, tvb, 0, END_OF_FRAME, bo_little_endian);
455 wsp_tree = proto_item_add_subtree(ti, ett_wsp);
457 /* Code to process the packet goes here */
459 wsp_header_fixed = proto_item_add_subtree(
465 /* Add common items: only TID and PDU Type */
467 /* TID Field is always first (if it exists) */
468 if ((pinfo->match_port == UDP_PORT_WSP) || (pinfo->match_port == UDP_PORT_WTLS_WSP))
470 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_tid,tvb,0,1,bo_little_endian);
473 ti = proto_tree_add_item(
475 hf_wsp_header_pdu_type, /* id */
477 offset++, /* start of high light */
478 1, /* length of high light */
479 bo_little_endian /* value */
485 ti = proto_tree_add_item (wsp_tree, hf_wsp_version_major,tvb,offset,1,bo_little_endian);
486 ti = proto_tree_add_item (wsp_tree, hf_wsp_version_minor,tvb,offset,1,bo_little_endian);
488 capabilityStart = offset;
489 capabilityLength = tvb_get_guintvar (tvb, offset, &count);
491 ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
493 headerStart = offset;
494 headerLength = tvb_get_guintvar (tvb, offset, &count);
496 ti = proto_tree_add_uint (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,headerLength);
497 if (capabilityLength > 0)
499 ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
500 wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
501 offset += capabilityLength;
504 if (headerLength > 0)
506 tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
507 add_headers (wsp_tree, tmp_tvb);
513 value = tvb_get_guintvar (tvb, offset, &count);
514 ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
517 capabilityStart = offset;
518 capabilityLength = tvb_get_guintvar (tvb, offset, &count);
520 ti = proto_tree_add_uint (wsp_tree, hf_wsp_capability_length,tvb,capabilityStart,count,capabilityLength);
522 headerStart = offset;
523 headerLength = tvb_get_guintvar (tvb, offset, &count);
525 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,bo_little_endian);
526 if (capabilityLength > 0)
528 ti = proto_tree_add_item (wsp_tree, hf_wsp_capabilities_section,tvb,offset,capabilityLength,bo_little_endian);
529 wsp_capabilities = proto_item_add_subtree( ti, ett_capabilities );
530 offset += capabilityLength;
533 if (headerLength > 0)
537 ti = proto_tree_add_item (wsp_tree, hf_wsp_headers_section,tvb,offset,headerLength,bo_little_endian);
538 wsp_headers = proto_item_add_subtree( ti, ett_headers );
540 tmp_tvb = tvb_new_subset (tvb, offset, headerLength, headerLength);
541 add_headers (wsp_tree, tmp_tvb);
547 value = tvb_get_guintvar (tvb, offset, &count);
548 ti = proto_tree_add_uint (wsp_tree, hf_wsp_server_session_id,tvb,offset,count,value);
552 /* Length of URI and size of URILen field */
553 value = tvb_get_guintvar (tvb, offset, &count);
554 nextOffset = offset + count;
555 add_uri (wsp_tree, tvb, offset, nextOffset);
557 tmp_tvb = tvb_new_subset (tvb, offset, -1, -1);
558 add_headers (wsp_tree, tmp_tvb);
563 uriLength = tvb_get_guintvar (tvb, offset, &count);
564 headerStart = uriStart+count;
565 headersLength = tvb_get_guintvar (tvb, headerStart, &count);
566 offset = headerStart + count;
568 add_uri (wsp_tree, tvb, uriStart, offset);
571 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,headerStart,count,bo_little_endian);
573 contentTypeStart = offset;
574 nextOffset = add_content_type (wsp_tree, tvb, offset, &contentType);
576 /* Add headers subtree that will hold the headers fields */
577 /* Runs from nextOffset for value-(length of content-type field)*/
578 headerLength = headersLength-(nextOffset-contentTypeStart);
579 tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
580 add_headers (wsp_tree, tmp_tvb);
582 /* TODO: Post DATA */
583 /* Runs from start of headers+headerLength to END_OF_FRAME */
584 offset = nextOffset+headerLength;
585 tmp_tvb = tvb_new_subset (tvb, offset, tvb_reported_length (tvb)-offset, tvb_reported_length (tvb)-offset);
586 add_post_data (wsp_tree, tmp_tvb, contentType);
590 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian);
591 value = tvb_get_guintvar (tvb, offset+1, &count);
592 nextOffset = offset + 1 + count;
593 ti = proto_tree_add_item (wsp_tree, hf_wsp_header_length,tvb,offset+1,count,bo_little_endian);
595 contentTypeStart = nextOffset;
596 nextOffset = add_content_type (wsp_tree, tvb, nextOffset, &contentType);
598 /* Add headers subtree that will hold the headers fields */
599 /* Runs from nextOffset for value-(length of content-type field)*/
600 headerLength = value-(nextOffset-contentTypeStart);
601 tmp_tvb = tvb_new_subset (tvb, nextOffset, headerLength, headerLength);
602 add_headers (wsp_tree, tmp_tvb);
603 offset += count+value+1;
605 /* TODO: Data - decode WMLC */
606 /* Runs from offset+1+count+value+1 to END_OF_FRAME */
607 if (offset < tvb_reported_length (tvb))
609 ti = proto_tree_add_item (wsp_tree, hf_wsp_reply_data,tvb,offset,END_OF_FRAME,bo_little_endian);
617 add_uri (proto_tree *tree, tvbuff_t *tvb, guint URILenOffset, guint URIOffset)
620 guint8 terminator = 0;
624 guint uriLen = tvb_get_guintvar (tvb, URILenOffset, &count);
626 ti = proto_tree_add_uint (tree, hf_wsp_header_uri_len,tvb,URILenOffset,count,uriLen);
628 /* If string doesn't end with a 0x00, we need to add one to be on the safe side */
629 terminator = tvb_get_guint8 (tvb, URIOffset+uriLen-1);
632 newBuffer = g_malloc (uriLen+1);
633 strncpy (newBuffer, tvb_get_ptr (tvb, URIOffset, uriLen), uriLen);
634 newBuffer[uriLen] = 0;
635 ti = proto_tree_add_string (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,newBuffer);
640 ti = proto_tree_add_item (tree, hf_wsp_header_uri,tvb,URIOffset,uriLen,bo_little_endian);
645 add_headers (proto_tree *tree, tvbuff_t *tvb)
648 proto_tree *wsp_headers;
650 guint headersLen = tvb_reported_length (tvb);
651 guint8 headerStart = 0;
653 tvbuff_t *header_buff;
654 tvbuff_t *value_buff;
656 guint valueStart = 0;
660 fprintf (stderr, "dissect_wsp: Offset is %d, size is %d\n", offset, headersLen);
670 fprintf (stderr, "dissect_wsp: Headers to process\n");
673 ti = proto_tree_add_item (tree, hf_wsp_headers_section,tvb,offset,headersLen,bo_little_endian);
674 wsp_headers = proto_item_add_subtree( ti, ett_headers );
678 while (offset < headersLen)
680 /* Loop round each header */
681 headerStart = offset;
682 peek = tvb_get_guint8 (tvb, headerStart);
684 if (peek < 32) /* Short-cut shift delimeter */
686 fprintf (stderr, "dissect_wsp: header: short-cut shift %d (0x%02X)\n", peek, peek);
689 else if (peek == 0x7F) /* Shift delimeter */
691 fprintf (stderr, "dissect_wsp: header: shift delimeter %d (0x%02X)\n", peek, peek);
697 fprintf (stderr, "dissect_wsp: header: application-header start %d (0x%02X)\n", peek, peek);
699 while (tvb_get_guint8 (tvb, offset++)) { /* Do nothing, just look for NULL */ }
701 else if (peek & 0x80) /* Well-known header */
704 fprintf (stderr, "dissect_wsp: header: well-known %d (0x%02X)\n", peek, peek);
709 /* Get value part of header */
711 peek = tvb_get_guint8 (tvb, valueStart);
715 fprintf (stderr, "dissect_wsp: Looking for %d octets\n", peek);
718 valueEnd = offset+1+peek;
724 fprintf (stderr, "dissect_wsp: Looking for uintvar octets\n");
726 tvb_get_guintvar (tvb, valueStart, &count);
727 valueEnd = offset+1+count;
730 else if (peek <= 127)
733 fprintf (stderr, "dissect_wsp: Looking for NULL-terminated string\n");
735 valueEnd = valueStart+1;
736 while (tvb_get_guint8 (tvb, valueEnd++)) { /* Do nothing, just look for NULL */ }
742 fprintf (stderr, "dissect_wsp: Value is %d\n", (peek & 0x7F));
748 fprintf (stderr, "dissect_wsp: Creating value buffer from offset %d, size=%d\n", headerStart, (offset-headerStart));
751 header_buff = tvb_new_subset (tvb, headerStart, (offset-headerStart), (offset-headerStart));
752 value_buff = tvb_new_subset (tvb, valueStart, (valueEnd-valueStart), (valueEnd-valueStart));
754 add_header (wsp_headers, header_buff, value_buff);
759 add_header (proto_tree *tree, tvbuff_t *header_buff, tvbuff_t *value_buff)
762 guint8 headerType = 0;
764 guint headerLen = tvb_reported_length (header_buff);
765 guint valueLen = tvb_reported_length (value_buff);
767 struct timeval timeValue;
770 headerType = tvb_get_guint8 (header_buff, 0);
771 peek = tvb_get_guint8 (value_buff, 0);
773 fprintf (stderr, "dissect_wsp: Got header 0x%02x\n", headerType);
774 fprintf (stderr, "dissect_wsp: First value octet is 0x%02x\n", peek);
777 if (headerType == 0x7F)
780 else if (headerType < 0x1F)
783 else if (headerType & 0x80)
785 headerType = headerType & 0x7F;
788 case 0x00: /* Accept */
791 proto_tree_add_uint (tree, hf_wsp_header_accept, header_buff, offset, headerLen, (peek & 0x7F));
795 proto_tree_add_string (tree, hf_wsp_header_accept_str,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
799 case 0x01: /* Accept-Charset */
802 /* Peek contains the number of octets to follow */
806 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_guint8 (value_buff, 1) );
809 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_ntohs (value_buff, 1) );
812 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, tvb_get_ntohl (value_buff, 1) );
815 fprintf (stderr, "dissect_wsp: accept-charset size %d NYI\n", peek);
818 else if (peek & 0x80)
820 proto_tree_add_uint (tree, hf_wsp_header_accept_charset, header_buff, offset, headerLen, (peek & 0x7F) );
824 fprintf (stderr, "dissect_wsp: Accept-Charset value %d (0x%02X) NYI\n", peek, peek);
828 case 0x03: /* Accept-Language */
829 proto_tree_add_uint (tree, hf_wsp_header_accept_language, header_buff, offset, headerLen, (peek & 0x7F));
832 case 0x04: /* Accept-Ranges */
833 if ((peek == 128) || (peek == 129))
835 proto_tree_add_uint (tree, hf_wsp_header_accept_ranges, header_buff, offset, headerLen, peek);
839 fprintf (stderr, "dissect_wsp: accept-ranges NYI\n");
848 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_guint8 (value_buff, 0));
851 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohs (value_buff, 0));
854 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntoh24 (value_buff, 0));
857 proto_tree_add_uint (tree, hf_wsp_header_age, header_buff, offset, headerLen, tvb_get_ntohl (value_buff, 0));
862 case 0x08: /* Cache-Control */
865 if (valueLen == 1) /* Well-known value */
867 proto_tree_add_uint (tree, hf_wsp_header_cache_control, header_buff, offset, headerLen, peek);
871 if ((peek == 0x82) || (peek == 0x83) || (peek == 0x84)) /* Delta seconds value to follow */
873 value = tvb_get_guint8 (value_buff, 1);
876 proto_tree_add_text (tree, header_buff, 0, headerLen, "Cache-Control: %s %d (0x%02X)",
877 match_strval ((int) peek, vals_cache_control), (value & 0x7F), peek);
881 fprintf (stderr, "dissect_wsp: Cache-Control integer value Delta seconds NYI\n");
884 else if ((peek == 0x80) || (peek == 0x87)) /* Fields to follow */
886 fprintf (stderr, "dissect_wsp: Cache-Control field values NYI\n");
890 fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
896 fprintf (stderr, "dissect_wsp: Cache-Control cache extension NYI\n");
900 case 0x0D: /* Content-Length */
903 proto_tree_add_uint (tree, hf_wsp_header_content_length, header_buff, offset, headerLen, (peek & 0x7F));
907 fprintf (stderr, "dissect_wsp: Content-Length long-integer size NYI\n");
911 case 0x12: /* Date */
912 timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
913 ti = proto_tree_add_time (tree, hf_wsp_header_date, header_buff, offset, headerLen, &timeValue);
916 case 0x13: /* Etag */
917 ti = proto_tree_add_string (tree, hf_wsp_header_etag,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
920 case 0x14: /* Expires */
925 fprintf (stderr, "dissect_wsp: Expires value length %d NYI\n", valueLen);
928 timeValue.tv_sec = tvb_get_ntoh24 (value_buff, 0);
931 timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
934 ti = proto_tree_add_time (tree, hf_wsp_header_expires, header_buff, offset, headerLen, &timeValue);
937 case 0x17: /* If-Modified-Since */
940 timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
944 timeValue.tv_sec = 0;
946 ti = proto_tree_add_time (tree, hf_wsp_header_if_modified_since, header_buff, offset, headerLen, &timeValue);
949 case 0x1C: /* Location */
950 ti = proto_tree_add_string (tree, hf_wsp_header_location,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
953 case 0x1D: /* Last-Modified */
954 timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
955 ti = proto_tree_add_time (tree, hf_wsp_header_last_modified, header_buff, offset, headerLen, &timeValue);
958 case 0x1F: /* Pragma */
961 proto_tree_add_text (tree, header_buff, 0, headerLen, "Pragma: No-cache");
965 proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
969 case 0x26: /* Server */
970 ti = proto_tree_add_string (tree, hf_wsp_header_server,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
973 case 0x29: /* User-Agent */
974 ti = proto_tree_add_string (tree, hf_wsp_header_user_agent,header_buff,offset,headerLen,tvb_get_ptr (value_buff, 0, valueLen));
978 ti = proto_tree_add_text (tree, header_buff, 0, headerLen, "Unsupported Header (0x%02X)", (tvb_get_guint8 (header_buff, 0) & 0x7F));
984 /* Special case header X-WAP.TOD that is sometimes followed
985 * by a 4-byte date value */
986 if (strncasecmp ("x-wap.tod", tvb_get_ptr (header_buff, 0, headerLen), 9) == 0)
988 if (tvb_reported_length (value_buff) == 4) /* Probably a date value */
990 timeValue.tv_sec = tvb_get_ntohl (value_buff, 0);
991 ti = proto_tree_add_time (tree, hf_wsp_header_x_wap_tod, header_buff, offset, headerLen, &timeValue);
995 ti = proto_tree_add_text (tree, header_buff, 0, headerLen, "%s: %s", tvb_get_ptr (header_buff, 0, headerLen), tvb_get_ptr (value_buff, 0, valueLen));
1000 ti = proto_tree_add_text (tree, header_buff, 0, headerLen, "%s: %s", tvb_get_ptr (header_buff, 0, headerLen), tvb_get_ptr (value_buff, 0, valueLen));
1007 get_value_length (tvbuff_t *tvb, guint offset, guint *nextOffset)
1011 guint octet = tvb_get_guint8 (tvb, offset);
1013 if (octet <= 30) /* Short length */
1016 *nextOffset = offset+1;
1018 else if (octet == 31)
1020 value = tvb_get_guintvar (tvb, offset+1, &count);
1021 *nextOffset = offset+1+count;
1025 fprintf (stderr, "dissect_wsp: get_value_length: case NYI\n");
1032 add_content_type (proto_tree *tree, tvbuff_t *tvb, guint offset, guint *contentType)
1034 proto_tree *contentTypeTree;
1035 guint nextOffset = offset;
1036 guint fieldLength = 0;
1037 guint octet = tvb_get_guint8 (tvb, offset);
1038 guint totalSizeOfField = 0;
1042 fieldLength = get_value_length (tvb, offset, &nextOffset);
1043 totalSizeOfField = (nextOffset-offset)+fieldLength;
1045 else if (octet & 0x80)
1048 totalSizeOfField = 1;
1052 fprintf (stderr, "dissect-wsp: Content-type is un-supported\n");
1055 *contentType = (tvb_get_guint8 (tvb, nextOffset) & 0x7F);
1056 contentTypeTree = proto_tree_add_uint (tree, hf_wsp_content_type, tvb, offset, totalSizeOfField, (tvb_get_guint8(tvb,nextOffset++) & 0x7F));
1058 while (nextOffset < (offset+totalSizeOfField))
1061 nextOffset = add_parameter (contentTypeTree, tvb, nextOffset);
1064 return (offset+totalSizeOfField);
1068 add_parameter (proto_tree *tree, tvbuff_t *tvb, guint offset)
1070 guint octet = tvb_get_guint8 (tvb, offset);
1071 if (octet & 0x80) /* Short integer */
1074 octet = octet & 0x7F;
1078 offset = add_parameter_charset (tree, tvb, offset, offset-1);
1082 fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
1087 fprintf (stderr, "dissect-wsp: add_parameter octet=0x%02x\n", octet);
1094 add_parameter_charset (proto_tree *tree, tvbuff_t *tvb, guint offset, guint startOffset)
1096 guint octet = tvb_get_guint8 (tvb, offset);
1100 proto_tree_add_item (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset+1, octet, bo_big_endian);
1102 else if (octet & 0x80)
1105 proto_tree_add_uint (tree, hf_wsp_parameter_well_known_charset, tvb, startOffset, offset-startOffset, (octet & 0x7F));
1112 add_post_data (proto_tree *tree, tvbuff_t *tvb, guint contentType)
1115 guint variableStart = 0;
1116 guint variableEnd = 0;
1117 guint valueStart = 0;
1122 ti = proto_tree_add_item (tree, hf_wsp_post_data,tvb,offset,END_OF_FRAME,bo_little_endian);
1124 if (contentType == 0x12) /* URL Encoded data */
1126 /* Iterate through post data */
1127 for (offset = 0; offset < tvb_reported_length (tvb); offset++)
1129 peek = tvb_get_guint8 (tvb, offset);
1132 variableEnd = offset-1;
1133 valueStart = offset+1;
1135 else if (peek == '&')
1137 if (variableEnd > 0)
1139 add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
1141 variableStart = offset+1;
1148 /* See if there's outstanding data */
1149 if (variableEnd > 0)
1151 add_post_variable (ti, tvb, variableStart, variableEnd, valueStart, offset);
1157 add_post_variable (proto_tree *tree, tvbuff_t *tvb, guint variableStart, guint variableEnd, guint valueStart, guint valueEnd)
1159 int variableLength = variableEnd-variableStart;
1160 int valueLength = 0;
1161 char *variableBuffer;
1164 variableBuffer = g_malloc (variableLength+1);
1165 strncpy (variableBuffer, tvb_get_ptr (tvb, variableStart, variableLength), variableLength+1);
1166 variableBuffer[variableLength+1] = 0;
1170 valueBuffer = g_malloc (1);
1172 valueEnd = valueStart;
1176 valueLength = valueEnd-valueStart;
1177 valueBuffer = g_malloc (valueLength+1);
1178 strncpy (valueBuffer, tvb_get_ptr (tvb, valueStart, valueLength), valueLength);
1179 valueBuffer[valueLength] = 0;
1182 /* Check for variables with no value */
1183 if (valueStart >= tvb_reported_length (tvb))
1185 valueStart = tvb_reported_length (tvb);
1186 valueEnd = valueStart;
1188 valueLength = valueEnd-valueStart;
1190 proto_tree_add_text (tree, tvb, variableStart, valueEnd-variableStart, "%s: %s", variableBuffer, valueBuffer);
1192 g_free (variableBuffer);
1193 g_free (valueBuffer);
1196 /* Register the protocol with Ethereal */
1198 proto_register_wsp(void)
1201 /* Setup list of header fields */
1202 static hf_register_info hf[] = {
1203 { &hf_wsp_header_tid,
1204 { "Transmission ID",
1206 FT_UINT8, BASE_HEX, NULL, 0x00,
1210 { &hf_wsp_header_pdu_type,
1213 FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x00,
1217 { &hf_wsp_version_major,
1218 { "Version (Major)",
1219 "wsp.version.major",
1220 FT_UINT8, BASE_DEC, NULL, 0xF0,
1224 { &hf_wsp_version_minor,
1225 { "Version (Minor)",
1226 "wsp.version.minor",
1227 FT_UINT8, BASE_DEC, NULL, 0x0F,
1231 { &hf_wsp_capability_length,
1232 { "Capability Length",
1233 "wsp.capability.length",
1234 FT_UINT32, BASE_DEC, NULL, 0x00,
1238 { &hf_wsp_header_length,
1240 "wsp.headers-length",
1241 FT_UINT32, BASE_DEC, NULL, 0x00,
1245 { &hf_wsp_capabilities_section,
1248 FT_NONE, BASE_DEC, NULL, 0x00,
1252 { &hf_wsp_headers_section,
1255 FT_NONE, BASE_DEC, NULL, 0x00,
1261 "wsp.headers.header",
1262 FT_NONE, BASE_DEC, NULL, 0x00,
1266 { &hf_wsp_header_uri_len,
1269 FT_UINT32, BASE_DEC, NULL, 0x00,
1273 { &hf_wsp_header_uri,
1276 FT_STRING, BASE_NONE, NULL, 0x00,
1280 { &hf_wsp_server_session_id,
1281 { "Server Session ID",
1282 "wsp.server.session-id",
1283 FT_UINT32, BASE_DEC, NULL, 0x00,
1287 { &hf_wsp_header_status,
1290 FT_UINT8, BASE_HEX, VALS( vals_status ), 0x00,
1294 { &hf_wsp_content_type,
1296 "wsp.content-type.type",
1297 FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
1301 { &hf_wsp_parameter_well_known_charset,
1303 "wsp.content-type.parameter.charset",
1304 FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
1308 { &hf_wsp_reply_data,
1311 FT_NONE, BASE_NONE, NULL, 0x00,
1315 { &hf_wsp_header_accept,
1317 "wsp.header.accept",
1318 /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1319 FT_UINT8, BASE_HEX, VALS ( vals_content_types ), 0x00,
1323 { &hf_wsp_header_accept_str,
1325 "wsp.header.accept.string",
1326 FT_STRING, BASE_NONE, NULL, 0x00,
1330 { &hf_wsp_header_accept_charset,
1332 "wsp.header.accept-charset",
1333 FT_UINT16, BASE_HEX, VALS ( vals_character_sets ), 0x00,
1337 { &hf_wsp_header_accept_language,
1338 { "Accept-Language",
1339 "wsp.header.accept-language",
1340 FT_UINT8, BASE_HEX, VALS ( vals_languages ), 0x00,
1344 { &hf_wsp_header_accept_ranges,
1346 "wsp.header.accept-ranges",
1347 FT_UINT8, BASE_HEX, VALS ( vals_accept_ranges ), 0x00,
1351 { &hf_wsp_header_age,
1354 FT_UINT32, BASE_DEC, NULL, 0x00,
1358 { &hf_wsp_header_cache_control,
1360 "wsp.header.cache-control",
1361 FT_UINT8, BASE_HEX, VALS ( vals_cache_control ), 0x00,
1365 { &hf_wsp_header_content_length,
1367 "wsp.header.content-length",
1368 FT_UINT32, BASE_DEC, NULL, 0x00,
1372 { &hf_wsp_header_date,
1375 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1379 { &hf_wsp_header_etag,
1382 /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1383 FT_STRING, BASE_NONE, NULL, 0x00,
1387 { &hf_wsp_header_expires,
1389 "wsp.header.expires",
1390 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1394 { &hf_wsp_header_last_modified,
1396 "wsp.header.last-modified",
1397 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1401 { &hf_wsp_header_location,
1403 "wsp.header.location",
1404 FT_STRING, BASE_NONE, NULL, 0x00,
1408 { &hf_wsp_header_if_modified_since,
1409 { "If-Modified-Since",
1410 "wsp.header.if-modified-since",
1411 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1415 { &hf_wsp_header_server,
1417 "wsp.header.server",
1418 /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1419 FT_STRING, BASE_NONE, NULL, 0x00,
1423 { &hf_wsp_header_user_agent,
1425 "wsp.header.user-agent",
1426 /*FT_NONE, BASE_DEC, NULL, 0x00,*/
1427 FT_STRING, BASE_NONE, NULL, 0x00,
1431 { &hf_wsp_header_application_header,
1432 { "Application Header",
1433 "wsp.header.application-header",
1434 FT_STRING, BASE_NONE, NULL, 0x00,
1435 "Application Header"
1438 { &hf_wsp_header_application_value,
1439 { "Application Header Value",
1440 "wsp.header.application-header.value",
1441 FT_STRING, BASE_NONE, NULL, 0x00,
1442 "Application Header Value"
1445 { &hf_wsp_header_x_wap_tod,
1447 "wsp.header.x_wap_tod",
1448 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
1452 { &hf_wsp_post_data,
1455 FT_NONE, BASE_NONE, NULL, 0x00,
1461 /* Setup protocol subtree array */
1462 static gint *ett[] = {
1470 /* Register the protocol name and description */
1471 proto_wsp = proto_register_protocol(
1472 "Wireless Session Protocol", /* protocol name for use by ethereal */
1473 "wap-wsp" /* Abbreviated protocol name, should Match IANA
1474 < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
1478 /* Required function calls to register the header fields and subtrees used */
1479 proto_register_field_array(proto_wsp, hf, array_length(hf));
1480 proto_register_subtree_array(ett, array_length(ett));
1484 proto_reg_handoff_wsp(void)
1486 /* Only connection-less WSP has no previous handler */
1487 // dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp_no_tvbuff);
1488 dissector_add("udp.port", UDP_PORT_WSP, dissect_wsp);
1489 /* dissector_add("udp.port", UDP_PORT_WTP_WSP, dissect_wsp_no_tvbuff); */
1490 /* dissector_add("udp.port", UDP_PORT_WTLS_WSP, dissect_wsp_no_tvbuff); */
1491 /* dissector_add("udp.port", UDP_PORT_WTLS_WTP_WSP, dissect_wsp_no_tvbuff); */