From Clinton Work: dissect Cisco PID 0x010b as STP (it's actually their
[obnox/wireshark/wip.git] / packet-mmse.c
1 /* packet-mmse.c
2  * Routines for MMS Message Encapsulation dissection
3  * Copyright 2001, Tom Uijldert <tom.uijldert@cmg.nl>
4  *
5  * $Id: packet-mmse.c,v 1.32 2004/02/06 01:07:51 obiot Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  * ----------
25  *
26  * Dissector of an encoded Multimedia message PDU, as defined by the WAPForum
27  * (http://www.wapforum.org) in "WAP-209-MMSEncapsulation-20020105-a".
28  */
29
30 /* This file has been edited with 8-space tabs and 4-space indentation */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <glib.h>
41
42 #include <epan/packet.h>
43 #include "packet-wap.h"
44 #include "packet-wsp.h"
45 /* #include "packet-mmse.h" */          /* We autoregister      */
46
47 #define MM_QUOTE                0x7F    /* Quoted string        */
48
49 #define MMS_CONTENT_TYPE        0x3E    /* WINA-value for mms-message   */
50
51 /* General-purpose debug logger.
52  * Requires double parentheses because of variable arguments of printf().
53  *
54  * Enable debug logging for MMSE by defining AM_CFLAGS
55  * so that it contains "-DDEBUG_mmse"
56  */
57 #ifdef DEBUG_mmse
58 #define DebugLog(x) \
59         printf("%s:%u: ", __FILE__, __LINE__); \
60         printf x; \
61         fflush(stdout)
62 #else
63 #define DebugLog(x) ;
64 #endif
65
66
67 /*
68  * Forward declarations
69  */
70 static void dissect_mmse_standalone(tvbuff_t *, packet_info *, proto_tree *);
71 static void dissect_mmse_encapsulated(tvbuff_t *, packet_info *, proto_tree *);
72 static void dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
73         guint8 pdut, char *message_type);
74
75 /*
76  * Header field values
77  */
78 #define MM_BCC_HDR              0x81    /* Bcc                  */
79 #define MM_CC_HDR               0x82    /* Cc                   */
80 #define MM_CLOCATION_HDR        0x83    /* Content-Location     */
81 #define MM_CTYPE_HDR            0x84    /* Content-Type         */
82 #define MM_DATE_HDR             0x85    /* Date                 */
83 #define MM_DREPORT_HDR          0x86    /* Delivery-Report      */
84 #define MM_DTIME_HDR            0x87    /* Delivery-Time        */
85 #define MM_EXPIRY_HDR           0x88    /* Expiry               */
86 #define MM_FROM_HDR             0x89    /* From                 */
87 #define MM_MCLASS_HDR           0x8A    /* Message-Class        */
88 #define MM_MID_HDR              0x8B    /* Message-ID           */
89 #define MM_MTYPE_HDR            0x8C    /* Message-Type         */
90 #define MM_VERSION_HDR          0x8D    /* MMS-Version          */
91 #define MM_MSIZE_HDR            0x8E    /* Message-Size         */
92 #define MM_PRIORITY_HDR         0x8F    /* Priority             */
93 #define MM_RREPLY_HDR           0x90    /* Read-Reply           */
94 #define MM_RALLOWED_HDR         0x91    /* Report-Allowed       */
95 #define MM_RSTATUS_HDR          0x92    /* Response-Status      */
96 #define MM_RTEXT_HDR            0x93    /* Response-Text        */
97 #define MM_SVISIBILITY_HDR      0x94    /* Sender-Visibility    */
98 #define MM_STATUS_HDR           0x95    /* Status               */
99 #define MM_SUBJECT_HDR          0x96    /* Subject              */
100 #define MM_TO_HDR               0x97    /* To                   */
101 #define MM_TID_HDR              0x98    /* Transaction-Id       */
102
103 static const value_string vals_mm_header_names[] = {
104         { MM_BCC_HDR,                   "Bcc" },
105         { MM_CC_HDR,                    "Cc" },
106         { MM_CLOCATION_HDR,             "Content-Location" },
107         { MM_CTYPE_HDR,                 "Content-Type" },
108         { MM_DATE_HDR,                  "Date" },
109         { MM_DREPORT_HDR,               "Delivery-Report" },
110         { MM_DTIME_HDR,                 "Delivery-Time" },
111         { MM_EXPIRY_HDR,                "Expiry" },
112         { MM_FROM_HDR,                  "From" },
113         { MM_MCLASS_HDR,                "Message-Class" },
114         { MM_MID_HDR,                   "Message-ID" },
115         { MM_MTYPE_HDR,                 "Message-Type" },
116         { MM_VERSION_HDR,               "MMS-Version" },
117         { MM_MSIZE_HDR,                 "Message-Size" },
118         { MM_PRIORITY_HDR,              "Priority" },
119         { MM_RREPLY_HDR,                "Read-Reply" },
120         { MM_RALLOWED_HDR,              "Report-Allowed" },
121         { MM_RSTATUS_HDR,               "Response-Status" },
122         { MM_RTEXT_HDR,                 "Response-Text" },
123         { MM_SVISIBILITY_HDR,   "Sender-Visibility" },
124         { MM_STATUS_HDR,                "Status" },
125         { MM_SUBJECT_HDR,               "Subject" },
126         { MM_TO_HDR,                    "To" },
127         { MM_TID_HDR,                   "Transaction-Id" },
128
129         { 0x00, NULL },
130 };
131 /*
132  * Initialize the protocol and registered fields
133  */
134 static int proto_mmse = -1;
135
136 static int hf_mmse_message_type         = -1;
137 static int hf_mmse_transaction_id       = -1;
138 static int hf_mmse_mms_version          = -1;
139 static int hf_mmse_bcc                  = -1;
140 static int hf_mmse_cc                   = -1;
141 static int hf_mmse_content_location     = -1;
142 static int hf_mmse_date                 = -1;
143 static int hf_mmse_delivery_report      = -1;
144 static int hf_mmse_delivery_time_abs    = -1;
145 static int hf_mmse_delivery_time_rel    = -1;
146 static int hf_mmse_expiry_abs           = -1;
147 static int hf_mmse_expiry_rel           = -1;
148 static int hf_mmse_from                 = -1;
149 static int hf_mmse_message_class_id     = -1;
150 static int hf_mmse_message_class_str    = -1;
151 static int hf_mmse_message_id           = -1;
152 static int hf_mmse_message_size         = -1;
153 static int hf_mmse_priority             = -1;
154 static int hf_mmse_read_reply           = -1;
155 static int hf_mmse_report_allowed       = -1;
156 static int hf_mmse_response_status      = -1;
157 static int hf_mmse_response_text        = -1;
158 static int hf_mmse_sender_visibility    = -1;
159 static int hf_mmse_status               = -1;
160 static int hf_mmse_subject              = -1;
161 static int hf_mmse_to                   = -1;
162 static int hf_mmse_content_type         = -1;
163 static int hf_mmse_ffheader             = -1;
164
165 /*
166  * Initialize the subtree pointers
167  */
168 static gint ett_mmse = -1;
169
170 /*
171  * Valuestrings for header contents
172  */
173
174 #define PDU_M_SEND_REQ          0x80
175 #define PDU_M_SEND_CONF         0x81
176 #define PDU_M_NOTIFICATION_IND  0x82
177 #define PDU_M_NOTIFYRESP_IND    0x83
178 #define PDU_M_RETRIEVE_CONF     0x84
179 #define PDU_M_ACKNOWLEDGE_IND   0x85
180 #define PDU_M_DELIVERY_IND      0x86
181
182 #define pdu_has_content(pdut) \
183         (  ((pdut) == PDU_M_SEND_REQ) \
184         || ((pdut) == PDU_M_DELIVERY_IND) )
185
186 static const value_string vals_message_type[] = {
187     { PDU_M_SEND_REQ,           "m-send-req" },
188     { PDU_M_SEND_CONF,          "m-send-conf" },
189     { PDU_M_NOTIFICATION_IND,   "m-notification-ind" },
190     { PDU_M_NOTIFYRESP_IND,     "m-notifyresp-ind" },
191     { PDU_M_RETRIEVE_CONF,      "m-retrieve-conf" },
192     { PDU_M_ACKNOWLEDGE_IND,    "m-acknowledge-ind" },
193     { PDU_M_DELIVERY_IND,       "m-delivery-ind" },
194     { 0x00, NULL },
195 };
196
197 static const value_string vals_yes_no[] = {
198     { 0x80, "Yes" },
199     { 0x81, "No" },
200     { 0x00, NULL },
201 };
202
203 static const value_string vals_message_class[] = {
204     { 0x80, "Personal" },
205     { 0x81, "Advertisement" },
206     { 0x82, "Informational" },
207     { 0x83, "Auto" },
208     { 0x00, NULL },
209 };
210
211 static const value_string vals_priority[] = {
212     { 0x80, "Low" },
213     { 0x81, "Normal" },
214     { 0x82, "High" },
215     { 0x00, NULL },
216 };
217
218 static const value_string vals_response_status[] = {
219     { 0x80, "Ok" },
220     { 0x81, "Unspecified" },
221     { 0x82, "Service denied" },
222     { 0x83, "Message format corrupt" },
223     { 0x84, "Sending address unresolved" },
224     { 0x85, "Message not found" },
225     { 0x86, "Network problem" },
226     { 0x87, "Content not accepted" },
227     { 0x88, "Unsupported message" },
228     { 0x00, NULL },
229 };
230
231 static const value_string vals_sender_visibility[] = {
232     { 0x80, "Hide" },
233     { 0x81, "Show" },
234     { 0x00, NULL },
235 };
236
237 static const value_string vals_message_status[] = {
238     { 0x80, "Expired" },
239     { 0x81, "Retrieved" },
240     { 0x82, "Rejected" },
241     { 0x83, "Deferred" },
242     { 0x84, "Unrecognized" },
243     { 0x00, NULL },
244 };
245
246 /*!
247  * Decodes a Text-string from the protocol data
248  *      Text-string = [Quote] *TEXT End-of-string
249  *      Quote       = <Octet 127>
250  *      End-of-string = <Octet 0>
251  *
252  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
253  *
254  * \param       tvb     The buffer with PDU-data
255  * \param       offset  Offset within that buffer
256  * \param       strval  Pointer to variable into which to put pointer to
257  *                      buffer allocated to hold the text; must be freed
258  *                      when no longer used
259  *
260  * \return              The length in bytes of the entire field
261  */
262 static guint
263 get_text_string(tvbuff_t *tvb, guint offset, char **strval)
264 {
265     guint        len;
266
267     DebugLog(("get_text_string(tvb = %p, offset = %u, **strval) - start\n", 
268                 vb, offset));
269     len = tvb_strsize(tvb, offset);
270     DebugLog((" [1] tvb_strsize(tvb, offset) == %u\n", len));
271     if (tvb_get_guint8(tvb, offset) == MM_QUOTE)
272         *strval = (char *)tvb_memdup(tvb, offset + 1, len - 1);
273     else
274         *strval = (char *)tvb_memdup(tvb, offset, len);
275     DebugLog((" [3] Return(len) == %u\n", len));
276     return len;
277 }
278
279 /*!
280  * Decodes a Value-length from the protocol data.
281  *      Value-length = Short-length | (Length-quote Length)
282  *      Short-length = <Any octet 0-30>
283  *      Length-quote = <Octet 31>
284  *      Length       = Uintvar-integer
285  *
286  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
287  *
288  * \param       tvb             The buffer with PDU-data
289  * \param       offset          Offset within that buffer
290  * \param       byte_count      Returns the length in bytes of
291  *                              the "Value-length" field.
292  *
293  * \return                      The actual value of "Value-length"
294  */
295 static guint
296 get_value_length(tvbuff_t *tvb, guint offset, guint *byte_count)
297 {
298     guint        field;
299
300     field = tvb_get_guint8(tvb, offset++);
301     if (field < 31)
302         *byte_count = 1;
303     else {                      /* Must be 31 so, Uintvar follows       */
304         field = tvb_get_guintvar(tvb, offset, byte_count);
305         (*byte_count)++;
306     }
307     return field;
308 }
309
310 /*!
311  * Decodes an Encoded-string-value from the protocol data
312  *      Encoded-string-value = Text-string | Value-length Char-set Text-string
313  *
314  * \param       tvb     The buffer with PDU-data
315  * \param       offset  Offset within that buffer
316  * \param       strval  Pointer to variable into which to put pointer to
317  *                      buffer allocated to hold the text; must be freed
318  *                      when no longer used
319  *
320  * \return              The length in bytes of the entire field
321  */
322 static guint
323 get_encoded_strval(tvbuff_t *tvb, guint offset, char **strval)
324 {
325     guint        field;
326     guint        length;
327     guint        count;
328
329     field = tvb_get_guint8(tvb, offset);
330
331     if (field < 32) {
332         length = get_value_length(tvb, offset, &count);
333         /* \todo        Something with "Char-set", skip for now */
334         *strval = (char *)tvb_get_string(tvb, offset + count + 1, length - 1);
335         return count + length;
336     } else
337         return get_text_string(tvb, offset, strval);
338 }
339
340 /*!
341  * Decodes a Long-integer from the protocol data
342  *      Long-integer = Short-length Multi-octet-integer
343  *      Short-length = <Any octet 0-30>
344  *      Multi-octet-integer = 1*30OCTET
345  *
346  * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
347  *
348  * \param       tvb             The buffer with PDU-data
349  * \param       offset          Offset within that buffer
350  * \param       byte_count      Returns the length in bytes of the field
351  *
352  * \return                      The value of the Long-integer
353  *
354  * \note        A maximum of 4-byte integers will be handled.
355  */
356 static guint
357 get_long_integer(tvbuff_t *tvb, guint offset, guint *byte_count)
358 {
359     guint        val;
360
361     *byte_count = tvb_get_guint8(tvb, offset++);
362     switch (*byte_count) {
363         case 1:
364             val = tvb_get_guint8(tvb, offset);
365             break;
366         case 2:
367             val = tvb_get_ntohs(tvb, offset);
368             break;
369         case 3:
370             val = tvb_get_ntoh24(tvb, offset);
371             break;
372         case 4:
373             val = tvb_get_ntohl(tvb, offset);
374             break;
375         default:
376             val = 0;
377             break;
378     }
379     (*byte_count)++;
380     return val;
381 }
382
383 /* Code to actually dissect the packets */
384 static gboolean
385 dissect_mmse_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
386 {
387     guint8       pdut;
388
389         DebugLog(("dissect_mmse_heur()\n"));
390     /*
391      * Check if data makes sense for it to be dissected as MMSE:  Message-type
392      * field must make sense and followed by either Transaction-Id
393      * or MMS-Version header
394      */
395     if (tvb_get_guint8(tvb, 0) != MM_MTYPE_HDR)
396         return FALSE;
397     pdut = tvb_get_guint8(tvb, 1);
398     if (match_strval(pdut, vals_message_type) == NULL)
399         return FALSE;
400     if ((tvb_get_guint8(tvb, 2) != MM_TID_HDR) &&
401         (tvb_get_guint8(tvb, 2) != MM_VERSION_HDR))
402         return FALSE;
403     dissect_mmse_standalone(tvb, pinfo, tree);
404     return TRUE;
405 }
406
407 static void
408 dissect_mmse_standalone(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
409 {
410     guint8       pdut;
411     char         *message_type;
412
413     DebugLog(("dissect_mmse_standalone() - START (Packet %u)\n",
414                 pinfo->fd->num));
415
416     pdut = tvb_get_guint8(tvb, 1);
417     message_type = match_strval(pdut, vals_message_type);
418
419     /* Make entries in Protocol column and Info column on summary display */
420     if (check_col(pinfo->cinfo, COL_PROTOCOL))
421         col_set_str(pinfo->cinfo, COL_PROTOCOL, "MMSE");
422
423     if (check_col(pinfo->cinfo, COL_INFO)) {
424         col_clear(pinfo->cinfo, COL_INFO);
425         col_add_fstr(pinfo->cinfo, COL_INFO, "MMS %s", message_type);
426     }
427
428     dissect_mmse(tvb, pinfo, tree, pdut, message_type);
429 }
430
431 static void
432 dissect_mmse_encapsulated(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
433 {
434     guint8       pdut;
435     char         *message_type;
436
437     DebugLog(("dissect_mmse_encapsulated() - START (Packet %u)\n",
438                 pinfo->fd->num));
439
440     pdut = tvb_get_guint8(tvb, 1);
441     message_type = match_strval(pdut, vals_message_type);
442
443     /* Make entries in Info column on summary display */
444     if (check_col(pinfo->cinfo, COL_INFO)) {
445         col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(MMS %s)",
446                 message_type);
447     }
448
449     dissect_mmse(tvb, pinfo, tree, pdut, message_type);
450 }
451
452 static void
453 dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 pdut,
454         char *message_type)
455 {
456     guint        offset;
457     guint8       field = 0;
458     char         *strval;
459     guint        length;
460     guint        count;
461
462     /* Set up structures needed to add the protocol subtree and manage it */
463     proto_item  *ti = NULL;
464     proto_tree  *mmse_tree = NULL;
465
466     DebugLog(("dissect_mmse() - START (Packet %u)\n", pinfo->fd->num));
467
468     /* If tree == NULL then we are only interested in protocol dissection
469      * up to reassembly and handoff to subdissectors if applicable; the
470      * columns must be set appropriately too.
471      * If tree != NULL then we also want to display the protocol tree
472      * with its fields.
473      * 
474      * In the interest of speed, skip protocol tree item generation
475      * if tree is NULL.
476      */
477     if (tree) {
478         DebugLog(("tree != NULL\n"));
479
480         ti = proto_tree_add_item(tree, proto_mmse, tvb, 0, -1, FALSE);
481         proto_item_append_text(ti, ", Type: %s", message_type);
482         /* create display subtree for the protocol */
483         mmse_tree = proto_item_add_subtree(ti, ett_mmse);
484
485         /* Report PDU-type      */
486         proto_tree_add_uint(mmse_tree, hf_mmse_message_type, tvb, 0, 2, pdut);
487     }
488
489     offset = 2;                 /* Skip Message-Type    */
490
491     /*
492      * Cycle through MMS-headers
493      *
494      * NOTE - some PDUs may convey content which can be handed off
495      *        to subdissectors.
496      */
497     if (tree || pdu_has_content(pdut)) {
498         while ((offset < tvb_reported_length(tvb)) &&
499                (field = tvb_get_guint8(tvb, offset++)) != MM_CTYPE_HDR)
500         {
501             DebugLog(("\tField =  0x%02X (offset = %u): %s\n",
502                         field, offset,
503                         val_to_str(field, vals_mm_header_names,
504                             "Unknown MMS header 0x%02X")));
505             switch (field)
506             {
507                 case MM_TID_HDR:                /* Text-string  */
508                     length = get_text_string(tvb, offset, &strval);
509                     if (tree) {
510                         proto_tree_add_string(mmse_tree, hf_mmse_transaction_id,
511                                 tvb, offset - 1, length + 1,strval);
512                     }
513                     g_free(strval);
514                     offset += length;
515                     break;
516                 case MM_VERSION_HDR:            /* nibble-Major/nibble-minor*/
517                     field = tvb_get_guint8(tvb, offset++);
518                     if (tree) {
519                         guint8   major, minor;
520
521                         major = (field & 0x70) >> 4;
522                         minor = field & 0x0F;
523                         if (minor == 0x0F)
524                             strval = g_strdup_printf("%u", major);
525                         else
526                             strval = g_strdup_printf("%u.%u", major, minor);
527                         proto_tree_add_string(mmse_tree, hf_mmse_mms_version,
528                                 tvb, offset - 2, 2, strval);
529                         g_free(strval);
530                     }
531                     break;
532                 case MM_BCC_HDR:                /* Encoded-string-value */
533                     length = get_encoded_strval(tvb, offset, &strval);
534                     if (tree) {
535                         proto_tree_add_string(mmse_tree, hf_mmse_bcc, tvb,
536                                 offset - 1, length + 1, strval);
537                     }
538                     g_free(strval);
539                     offset += length;
540                     break;
541                 case MM_CC_HDR:                 /* Encoded-string-value */
542                     length = get_encoded_strval(tvb, offset, &strval);
543                     if (tree) {
544                         proto_tree_add_string(mmse_tree, hf_mmse_cc, tvb,
545                                 offset - 1, length + 1, strval);
546                     }
547                     g_free(strval);
548                     offset += length;
549                     break;
550                 case MM_CLOCATION_HDR:          /* Uri-value            */
551                     length = get_text_string(tvb, offset, &strval);
552                     if (tree) {
553                         proto_tree_add_string(mmse_tree,
554                                 hf_mmse_content_location,
555                                 tvb, offset - 1, length + 1,strval);
556                     }
557                     g_free(strval);
558                     offset += length;
559                     break;
560                 case MM_DATE_HDR:               /* Long-integer         */
561                     {
562                         guint            tval;
563                         nstime_t         tmptime;
564
565                         tval = get_long_integer(tvb, offset, &count);
566                         tmptime.secs = tval;
567                         tmptime.nsecs = 0;
568                         if (tree) {
569                             proto_tree_add_time(mmse_tree, hf_mmse_date, tvb,
570                                     offset - 1, count + 1, &tmptime);
571                         }
572                     }
573                     offset += count;
574                     break;
575                 case MM_DREPORT_HDR:            /* Yes|No               */
576                     field = tvb_get_guint8(tvb, offset++);
577                     if (tree) {
578                         proto_tree_add_uint(mmse_tree,
579                                 hf_mmse_delivery_report,
580                                 tvb, offset - 2, 2, field);
581                     }
582                     break;
583                 case MM_DTIME_HDR:
584                     /*
585                      * Value-length(Absolute-token Date-value|
586                      *              Relative-token Delta-seconds-value)
587                      */
588                     length = get_value_length(tvb, offset, &count);
589                     field = tvb_get_guint8(tvb, offset + count);
590                     if (tree) {
591                         guint            tval;
592                         nstime_t         tmptime;
593                         guint            cnt;
594
595                         tval =  get_long_integer(tvb, offset + count + 1, &cnt);
596                         tmptime.secs = tval;
597                         tmptime.nsecs = 0;
598
599                         if (field == 0x80)
600                             proto_tree_add_time(mmse_tree,
601                                     hf_mmse_delivery_time_abs,
602                                     tvb, offset - 1,
603                                     length + count + 1, &tmptime);
604                         else
605                             proto_tree_add_time(mmse_tree,
606                                     hf_mmse_delivery_time_rel,
607                                     tvb, offset - 1,
608                                     length + count + 1, &tmptime);
609                     }
610                     offset += length + count;
611                     break;
612                 case MM_EXPIRY_HDR:
613                     /*
614                      * Value-length(Absolute-token Date-value|
615                      *              Relative-token Delta-seconds-value)
616                      */
617                     length = get_value_length(tvb, offset, &count);
618                     field = tvb_get_guint8(tvb, offset + count);
619                     if (tree) {
620                         guint            tval;
621                         nstime_t         tmptime;
622                         guint            cnt;
623
624                         tval = get_long_integer(tvb, offset + count + 1, &cnt);
625                         tmptime.secs = tval;
626                         tmptime.nsecs = 0;
627
628                         if (field == 0x80)
629                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_abs,
630                                     tvb, offset - 1,
631                                     length + count + 1, &tmptime);
632                         else
633                             proto_tree_add_time(mmse_tree, hf_mmse_expiry_rel,
634                                     tvb, offset - 1,
635                                     length + count + 1, &tmptime);
636                     }
637                     offset += length + count;
638                     break;
639                 case MM_FROM_HDR:
640                     /*
641                      * Value-length(Address-present-token Encoded-string-value
642                      *              |Insert-address-token)
643                      */
644                     length = get_value_length(tvb, offset, &count);
645                     if (tree) {
646                         field = tvb_get_guint8(tvb, offset + count);
647                         if (field == 0x81) {
648                             proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
649                                     offset-1, length + count + 1,
650                                     "<insert address>");
651                         } else {
652                             (void) get_encoded_strval(tvb, offset + count + 1,
653                                                       &strval);
654                             proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
655                                     offset-1, length + count + 1, strval);
656                             g_free(strval);
657                         }
658                     }
659                     offset += length + count;
660                     break;
661                 case MM_MCLASS_HDR:
662                     /*
663                      * Class-identifier|Text-string
664                      */
665                     field = tvb_get_guint8(tvb, offset);
666                     if (field & 0x80) {
667                         offset++;
668                         if (tree) {
669                             proto_tree_add_uint(mmse_tree,
670                                     hf_mmse_message_class_id,
671                                     tvb, offset - 2, 2, field);
672                         }
673                     } else {
674                         length = get_text_string(tvb, offset, &strval);
675                         if (tree) {
676                             proto_tree_add_string(mmse_tree,
677                                     hf_mmse_message_class_str,
678                                     tvb, offset - 1, length + 1,
679                                     strval);
680                         }
681                         g_free(strval);
682                         offset += length;
683                     }
684                     break;
685                 case MM_MID_HDR:                /* Text-string          */
686                     length = get_text_string(tvb, offset, &strval);
687                     if (tree) {
688                         proto_tree_add_string(mmse_tree, hf_mmse_message_id,
689                                 tvb, offset - 1, length + 1, strval);
690                     }
691                     g_free(strval);
692                     offset += length;
693                     break;
694                 case MM_MSIZE_HDR:              /* Long-integer         */
695                     length = get_long_integer(tvb, offset, &count);
696                     if (tree) {
697                         proto_tree_add_uint(mmse_tree, hf_mmse_message_size,
698                                 tvb, offset - 1, count + 1, length);
699                     }
700                     offset += count;
701                     break;
702                 case MM_PRIORITY_HDR:           /* Low|Normal|High      */
703                     field = tvb_get_guint8(tvb, offset++);
704                     if (tree) {
705                         proto_tree_add_uint(mmse_tree, hf_mmse_priority, tvb,
706                                 offset - 2, 2, field);
707                     }
708                     break;
709                 case MM_RREPLY_HDR:             /* Yes|No               */
710                     field = tvb_get_guint8(tvb, offset++);
711                     if (tree) {
712                         proto_tree_add_uint(mmse_tree, hf_mmse_read_reply, tvb,
713                                 offset - 2, 2, field);
714                     }
715                     break;
716                 case MM_RALLOWED_HDR:           /* Yes|No               */
717                     field = tvb_get_guint8(tvb, offset++);
718                     if (tree) {
719                         proto_tree_add_uint(mmse_tree, hf_mmse_report_allowed,
720                                 tvb, offset - 2, 2, field);
721                     }
722                     break;
723                 case MM_RSTATUS_HDR:
724                     field = tvb_get_guint8(tvb, offset++);
725                     if (tree) {
726                         proto_tree_add_uint(mmse_tree, hf_mmse_response_status,
727                                 tvb, offset - 2, 2, field);
728                     }
729                     break;
730                 case MM_RTEXT_HDR:              /* Encoded-string-value */
731                     length = get_encoded_strval(tvb, offset, &strval);
732                     if (tree) {
733                         proto_tree_add_string(mmse_tree, hf_mmse_response_text,
734                                 tvb, offset - 1, length + 1, strval);
735                     }
736                     g_free(strval);
737                     offset += length;
738                     break;
739                 case MM_SVISIBILITY_HDR:        /* Hide|Show            */
740                     field = tvb_get_guint8(tvb, offset++);
741                     if (tree) {
742                         proto_tree_add_uint(mmse_tree,hf_mmse_sender_visibility,
743                                 tvb, offset - 2, 2, field);
744                     }
745                     break;
746                 case MM_STATUS_HDR:
747                     field = tvb_get_guint8(tvb, offset++);
748                     if (tree) {
749                         proto_tree_add_uint(mmse_tree, hf_mmse_status, tvb,
750                                 offset - 2, 2, field);
751                     }
752                     break;
753                 case MM_SUBJECT_HDR:            /* Encoded-string-value */
754                     length = get_encoded_strval(tvb, offset, &strval);
755                     if (tree) {
756                         proto_tree_add_string(mmse_tree, hf_mmse_subject, tvb,
757                                 offset - 1, length + 1, strval);
758                     }
759                     g_free(strval);
760                     offset += length;
761                     break;
762                 case MM_TO_HDR:                 /* Encoded-string-value */
763                     length = get_encoded_strval(tvb, offset, &strval);
764                     if (tree) {
765                         proto_tree_add_string(mmse_tree, hf_mmse_to, tvb,
766                                 offset - 1, length + 1, strval);
767                     }
768                     g_free(strval);
769                     offset += length;
770                     break;
771                 default:
772                     if (field & 0x80) {
773                         if (tree) {
774                             proto_tree_add_text(mmse_tree, tvb, offset - 1, 1,
775                                     "Unknown field (0x%02x)", field);
776                         }
777                     } else {
778                         guint    length2;
779                         char     *strval2;
780
781                         --offset;
782                         length = get_text_string(tvb, offset, &strval);
783                         CLEANUP_PUSH(g_free, strval);
784                         length2= get_text_string(tvb, offset+length, &strval2);
785
786                         if (tree) {
787                             proto_tree_add_string_format(mmse_tree,
788                                     hf_mmse_ffheader, tvb, offset,
789                                     length + length2,
790                                     (const char *) tvb_get_ptr(
791                                         tvb, offset, length + length2),
792                                     "%s: %s",strval,strval2);
793                         }
794                         g_free(strval2);
795                         offset += length + length2;
796                         CLEANUP_CALL_AND_POP;
797                     }
798                     break;
799             }
800             DebugLog(("\tEnd(case)\n"));
801         }
802         DebugLog(("\tEnd(switch)\n"));
803         if (field == MM_CTYPE_HDR) {
804             /*
805              * Eeehh, we're now actually back to good old WSP content-type
806              * encoding. Let's steal that from the WSP-dissector.
807              */
808             tvbuff_t    *tmp_tvb;
809             guint        type;
810             const char  *type_str;
811
812             DebugLog(("Content-Type: [from WSP dissector]\n"));
813             DebugLog(("Calling add_content_type() in WSP dissector\n"));
814             offset = add_content_type(mmse_tree, tvb, offset, &type, &type_str);
815             DebugLog(("Generating new TVB subset (offset = %u)\n", offset));
816             tmp_tvb = tvb_new_subset(tvb, offset, -1, -1);
817             DebugLog(("Add POST data\n"));
818             add_post_data(mmse_tree, tmp_tvb, type, type_str, pinfo);
819             DebugLog(("Done!\n"));
820         }
821     } else {
822         DebugLog(("tree == NULL and PDU has no potential content\n"));
823     }
824
825     /* If this protocol has a sub-dissector call it here, see section 1.8 */
826     DebugLog(("dissect_mmse() - END\n"));
827 }
828
829
830 /* Register the protocol with Ethereal */
831
832 /* this format is required because a script is used to build the C function
833  * that calls all the protocol registration.
834  */
835 void
836 proto_register_mmse(void)
837 {
838     /* Setup list of header fields  See Section 1.6.1 for details       */
839     static hf_register_info hf[] = {
840         {   &hf_mmse_message_type,
841             {   "Message-Type", "mmse.message_type",
842                 FT_UINT8, BASE_HEX, VALS(vals_message_type), 0x00,
843                 "Specifies the transaction type. Effectively defines PDU.",
844                 HFILL
845             }
846         },
847         {   &hf_mmse_transaction_id,
848             {   "Transaction-ID", "mmse.transaction_id",
849                 FT_STRING, BASE_NONE, NULL, 0x00,
850                 "A unique identifier for this transaction. "
851                 "Identifies request and corresponding response only.",
852                 HFILL
853             }
854         },
855         {   &hf_mmse_mms_version,
856             {   "MMS-Version", "mmse.mms_version",
857                 FT_STRING, BASE_NONE, NULL, 0x00,
858                 "Version of the protocol used.",
859                 HFILL
860             }
861         },
862         {   &hf_mmse_bcc,
863             {   "Bcc", "mmse.bcc",
864                 FT_STRING, BASE_NONE, NULL, 0x00,
865                 "Blind carbon copy.",
866                 HFILL
867             }
868         },
869         {   &hf_mmse_cc,
870             {   "Cc", "mmse.cc",
871                 FT_STRING, BASE_NONE, NULL, 0x00,
872                 "Carbon copy.",
873                 HFILL
874             }
875         },
876         {   &hf_mmse_content_location,
877             {   "Content-Location", "mmse.content_location",
878                 FT_STRING, BASE_NONE, NULL, 0x00,
879                 "Defines the location of the message.",
880                 HFILL
881             }
882         },
883         {   &hf_mmse_date,
884             {   "Date", "mmse.date",
885                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
886                 "Arrival timestamp of the message or sending timestamp.",
887                 HFILL
888             }
889         },
890         {   &hf_mmse_delivery_report,
891             {   "Delivery-Report", "mmse.delivery_report",
892                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
893                 "Whether a report of message delivery is wanted or not.",
894                 HFILL
895             }
896         },
897         {   &hf_mmse_delivery_time_abs,
898             {   "Delivery-Time", "mmse.delivery_time.abs",
899                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
900                 "The time at which message delivery is desired.",
901                 HFILL
902             }
903         },
904         {   &hf_mmse_delivery_time_rel,
905             {   "Delivery-Time", "mmse.delivery_time.rel",
906                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
907                 "The desired message delivery delay.",
908                 HFILL
909             }
910         },
911         {   &hf_mmse_expiry_abs,
912             {   "Expiry", "mmse.expiry.abs",
913                 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
914                 "Time when message expires and need not be delivered anymore.",
915                 HFILL
916             }
917         },
918         {   &hf_mmse_expiry_rel,
919             {   "Expiry", "mmse.expiry.rel",
920                 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
921                 "Delay before message expires and need not be delivered anymore.",
922                 HFILL
923             }
924         },
925         {   &hf_mmse_from,
926             {   "From", "mmse.from",
927                 FT_STRING, BASE_NONE, NULL, 0x00,
928                 "Address of the message sender.",
929                 HFILL
930             }
931         },
932         {   &hf_mmse_message_class_id,
933             {   "Message-Class", "mmse.message_class.id",
934                 FT_UINT8, BASE_HEX, VALS(vals_message_class), 0x00,
935                 "Of what category is the message.",
936                 HFILL
937             }
938         },
939         {   &hf_mmse_message_class_str,
940             {   "Message-Class", "mmse.message_class.str",
941                 FT_STRING, BASE_NONE, NULL, 0x00,
942                 "Of what category is the message.",
943                 HFILL
944             }
945         },
946         {   &hf_mmse_message_id,
947             {   "Message-Id", "mmse.message_id",
948                 FT_STRING, BASE_NONE, NULL, 0x00,
949                 "Unique identification of the message.",
950                 HFILL
951             }
952         },
953         {   &hf_mmse_message_size,
954             {   "Message-Size", "mmse.message_size",
955                 FT_UINT32, BASE_DEC, NULL, 0x00,
956                 "The size of the message in octets.",
957                 HFILL
958             }
959         },
960         {   &hf_mmse_priority,
961             {   "Priority", "mmse.priority",
962                 FT_UINT8, BASE_HEX, VALS(vals_priority), 0x00,
963                 "Priority of the message.",
964                 HFILL
965             }
966         },
967         {   &hf_mmse_read_reply,
968             {   "Read-Reply", "mmse.read_reply",
969                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
970                 "Whether a read report from every recipient is wanted.",
971                 HFILL
972             }
973         },
974         {   &hf_mmse_report_allowed,
975             {   "Report-Allowed", "mmse.report_allowed",
976                 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
977                 "Sending of delivery report allowed or not.",
978                 HFILL
979             }
980         },
981         {   &hf_mmse_response_status,
982             {   "Response-Status", "mmse.response_status",
983                 FT_UINT8, BASE_HEX, VALS(vals_response_status), 0x00,
984                 "MMS-specific result of a message submission or retrieval.",
985                 HFILL
986             }
987         },
988         {   &hf_mmse_response_text,
989             {   "Response-Text", "mmse.response_text",
990                 FT_STRING, BASE_NONE, NULL, 0x00,
991                 "Additional information on MMS-specific result.",
992                 HFILL
993             }
994         },
995         {   &hf_mmse_sender_visibility,
996             {   "Sender-Visibility", "mmse.sender_visibility",
997                 FT_UINT8, BASE_HEX, VALS(vals_sender_visibility), 0x00,
998                 "Disclose sender identity to receiver or not.",
999                 HFILL
1000             }
1001         },
1002         {   &hf_mmse_status,
1003             {   "Status", "mmse.status",
1004                 FT_UINT8, BASE_HEX, VALS(vals_message_status), 0x00,
1005                 "Current status of the message.",
1006                 HFILL
1007             }
1008         },
1009         {   &hf_mmse_subject,
1010             {   "Subject", "mmse.subject",
1011                 FT_STRING, BASE_NONE, NULL, 0x00,
1012                 "Subject of the message.",
1013                 HFILL
1014             }
1015         },
1016         {   &hf_mmse_to,
1017             {   "To", "mmse.to",
1018                 FT_STRING, BASE_NONE, NULL, 0x00,
1019                 "Recipient(s) of the message.",
1020                 HFILL
1021             }
1022         },
1023         {   &hf_mmse_content_type,
1024             {   "Data", "mmse.content_type",
1025                 FT_NONE, BASE_NONE, NULL, 0x00,
1026                 "Media content of the message.",
1027                 HFILL
1028             }
1029         },
1030         {   &hf_mmse_ffheader,
1031             {   "Free format (not encoded) header", "mmse.ffheader",
1032                 FT_STRING, BASE_NONE, NULL, 0x00,
1033                 "Application header without corresponding encoding.",
1034                 HFILL
1035             }
1036         },
1037     };
1038     /* Setup protocol subtree array */
1039     static gint *ett[] = {
1040         &ett_mmse,
1041     };
1042
1043     /* Register the protocol name and description */
1044     proto_mmse = proto_register_protocol("MMS Message Encapsulation",
1045                                          "MMSE", "mmse");
1046
1047     /* Required function calls to register header fields and subtrees used */
1048     proto_register_field_array(proto_mmse, hf, array_length(hf));
1049     proto_register_subtree_array(ett, array_length(ett));
1050 }
1051
1052 /* If this dissector uses sub-dissector registration add registration routine.
1053  * This format is required because a script is used to find these routines and
1054  * create the code that calls these routines.
1055  */
1056 void
1057 proto_reg_handoff_mmse(void)
1058 {
1059     dissector_handle_t mmse_standalone_handle;
1060     dissector_handle_t mmse_encapsulated_handle;
1061
1062     heur_dissector_add("wsp", dissect_mmse_heur, proto_mmse);
1063     mmse_standalone_handle = create_dissector_handle(
1064             dissect_mmse_standalone, proto_mmse);
1065     mmse_encapsulated_handle = create_dissector_handle(
1066             dissect_mmse_encapsulated, proto_mmse);
1067         /* As the media types for WSP and HTTP are the same, the WSP dissector
1068          * uses the same string dissector table as the HTTP protocol. */
1069     dissector_add_string("media_type",
1070             "application/vnd.wap.mms-message", mmse_standalone_handle);
1071     dissector_add_string("multipart_media_type",
1072             "application/vnd.wap.mms-message", mmse_encapsulated_handle);
1073 }