2 * Routines for MMS Message Encapsulation dissection
3 * Copyright 2001, Tom Uijldert <tom.uijldert@cmg.nl>
5 * $Id: packet-mmse.c,v 1.4 2001/12/10 00:25:30 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
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.
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.
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.
26 * Dissector of an encoded Multimedia message PDU, as defined by the WAPForum
27 * (http://www.wapforum.org) in "WAP-209.102-MMSEncapsulation" according
28 * the draft version of 8-February-2001.
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
49 #ifdef NEED_SNPRINTF_H
50 # include "snprintf.h"
54 #include "packet-wap.h"
55 #include "packet-wsp.h"
56 /* #include "packet-mmse.h" */ /* We autoregister */
58 #define MM_QUOTE 0x7F /* Quoted string */
60 #define MMS_CONTENT_TYPE 0x3E /* WINA-value for mms-message */
63 * Forward declarations
65 static void dissect_mmse(tvbuff_t *, packet_info *, proto_tree *);
70 #define MM_BCC_HDR 0x81 /* Bcc */
71 #define MM_CC_HDR 0x82 /* Cc */
72 #define MM_CLOCATION_HDR 0x83 /* Content-Location */
73 #define MM_CTYPE_HDR 0x84 /* Content-Type */
74 #define MM_DATE_HDR 0x85 /* Date */
75 #define MM_DREPORT_HDR 0x86 /* Delivery-Report */
76 #define MM_DTIME_HDR 0x87 /* Delivery-Time */
77 #define MM_EXPIRY_HDR 0x88 /* Expiry */
78 #define MM_FROM_HDR 0x89 /* From */
79 #define MM_MCLASS_HDR 0x8A /* Message-Class */
80 #define MM_MID_HDR 0x8B /* Message-ID */
81 #define MM_MTYPE_HDR 0x8C /* Message-Type */
82 #define MM_VERSION_HDR 0x8D /* MMS-Version */
83 #define MM_MSIZE_HDR 0x8E /* Message-Size */
84 #define MM_PRIORITY_HDR 0x8F /* Priority */
85 #define MM_RREPLY_HDR 0x90 /* Read-Reply */
86 #define MM_RALLOWED_HDR 0x91 /* Report-Allowed */
87 #define MM_RSTATUS_HDR 0x92 /* Response-Status */
88 #define MM_RTEXT_HDR 0x93 /* Response-Text */
89 #define MM_SVISIBILITY_HDR 0x94 /* Sender-Visibility */
90 #define MM_STATUS_HDR 0x95 /* Status */
91 #define MM_SUBJECT_HDR 0x96 /* Subject */
92 #define MM_TO_HDR 0x97 /* To */
93 #define MM_TID_HDR 0x98 /* Transaction-Id */
96 * Initialize the protocol and registered fields
98 static int proto_mmse = -1;
100 static int hf_mmse_message_type = -1;
101 static int hf_mmse_transaction_id = -1;
102 static int hf_mmse_mms_version = -1;
103 static int hf_mmse_bcc = -1;
104 static int hf_mmse_cc = -1;
105 static int hf_mmse_content_location = -1;
106 static int hf_mmse_date = -1;
107 static int hf_mmse_delivery_report = -1;
108 static int hf_mmse_delivery_time_abs = -1;
109 static int hf_mmse_delivery_time_rel = -1;
110 static int hf_mmse_expiry_abs = -1;
111 static int hf_mmse_expiry_rel = -1;
112 static int hf_mmse_from = -1;
113 static int hf_mmse_message_class_id = -1;
114 static int hf_mmse_message_class_str = -1;
115 static int hf_mmse_message_id = -1;
116 static int hf_mmse_message_size = -1;
117 static int hf_mmse_priority = -1;
118 static int hf_mmse_read_reply = -1;
119 static int hf_mmse_report_allowed = -1;
120 static int hf_mmse_response_status = -1;
121 static int hf_mmse_response_text = -1;
122 static int hf_mmse_sender_visibility = -1;
123 static int hf_mmse_status = -1;
124 static int hf_mmse_subject = -1;
125 static int hf_mmse_to = -1;
126 static int hf_mmse_content_type = -1;
127 static int hf_mmse_ffheader = -1;
130 * Initialize the subtree pointers
132 static gint ett_mmse = -1;
135 * Valuestrings for header contents
137 static const value_string vals_message_type[] = {
138 { 0x80, "m-send-req" },
139 { 0x81, "m-send-conf" },
140 { 0x82, "m-notification-ind" },
141 { 0x83, "m-notifyresp-ind" },
142 { 0x84, "m-retrieve-conf" },
143 { 0x85, "m-acknowledge-ind" },
144 { 0x86, "m-delivery-ind" },
148 static const value_string vals_yes_no[] = {
154 static const value_string vals_message_class[] = {
155 { 0x80, "Personal" },
156 { 0x81, "Advertisement" },
157 { 0x82, "Informational" },
162 static const value_string vals_priority[] = {
169 static const value_string vals_response_status[] = {
171 { 0x81, "Unspecified" },
172 { 0x82, "Service denied" },
173 { 0x83, "Message format corrupt" },
174 { 0x84, "sending address unresolved" },
175 { 0x85, "message not found" },
176 { 0x86, "Network problem" },
177 { 0x87, "Content not accepted" },
178 { 0x88, "Unsupported message" },
182 static const value_string vals_sender_visibility[] = {
188 static const value_string vals_status[] = {
190 { 0x81, "Retrieved" },
191 { 0x82, "Rejected" },
192 { 0x82, "Deferred" },
193 { 0x82, "Unrecognized" },
198 * Decodes a Text-string from the protocol data
199 * Text-string = [Quote] *TEXT End-of-string
200 * Quote = <Octet 127>
201 * End-of-string = <Octet 0>
203 * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
205 * \param tvb The buffer with PDU-data
206 * \param offset Offset within that buffer
207 * \param strval String buffer to receive the text, reserve memory!
209 * \return The length in bytes of the entire field
212 get_text_string(tvbuff_t *tvb, guint offset, char *strval)
216 len = tvb_strsize(tvb, offset);
217 if (tvb_get_guint8(tvb, offset) == MM_QUOTE)
218 tvb_memcpy(tvb, strval, offset + 1, len - 1);
220 tvb_memcpy(tvb, strval, offset, len);
225 * Decodes a Value-length from the protocol data.
226 * Value-length = Short-length | (Length-quote Length)
227 * Short-length = <Any octet 0-30>
228 * Length-quote = <Octet 31>
229 * Length = Uintvar-integer
231 * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
233 * \param tvb The buffer with PDU-data
234 * \param offset Offset within that buffer
235 * \param byte_count Returns the length in bytes of
236 * the "Value-length" field.
238 * \return The actual value of "Value-length"
241 get_value_length(tvbuff_t *tvb, guint offset, guint *byte_count)
245 field = tvb_get_guint8(tvb, offset++);
248 else { /* Must be 31 so, Uintvar follows */
249 field = tvb_get_guintvar(tvb, offset, byte_count);
256 * Decodes an Encoded-string-value from the protocol data
257 * Encoded-string-value = Text-string | Value-length Char-set Text-string
259 * \param tvb The buffer with PDU-data
260 * \param offset Offset within that buffer
261 * \param strval String buffer to receive the text, reserve memory!
263 * \return The length in bytes of the entire field
266 get_encoded_strval(tvbuff_t *tvb, guint offset, char *strval)
272 field = tvb_get_guint8(tvb, offset);
275 length = get_value_length(tvb, offset, &count);
276 /* \todo Something with "Char-set", skip for now */
277 tvb_memcpy(tvb, strval, offset + count + 1, length - 1);
278 strval[length - 1] = '\0'; /* Just to make sure */
279 return offset + count + length;
281 return get_text_string(tvb, offset, strval);
285 * Decodes a Long-integer from the protocol data
286 * Long-integer = Short-length Multi-octet-integer
287 * Short-length = <Any octet 0-30>
288 * Multi-octet-integer = 1*30OCTET
290 * \todo Shouldn't we be sharing this with WSP (packet-wap.c)?
292 * \param tvb The buffer with PDU-data
293 * \param offset Offset within that buffer
294 * \param byte_count Returns the length in bytes of the field
296 * \return The value of the Long-integer
298 * \note A maximum of 4-byte integers will be handled.
301 get_long_integer(tvbuff_t *tvb, guint offset, guint *byte_count)
305 *byte_count = tvb_get_guint8(tvb, offset++);
306 switch (*byte_count) {
308 val = tvb_get_guint8(tvb, offset);
311 val = tvb_get_ntohs(tvb, offset);
314 val = tvb_get_ntoh24(tvb, offset);
317 val = tvb_get_ntohl(tvb, offset);
327 /* Code to actually dissect the packets */
329 dissect_mmse_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
334 * Check if data makes sense for it to be dissected as MMSE: Message-type
335 * field must make sense and followed by Transaction-Id header
337 if (tvb_get_guint8(tvb, 0) != MM_MTYPE_HDR)
339 pdut = tvb_get_guint8(tvb, 1);
340 if (match_strval(pdut, vals_message_type) == NULL)
342 if (tvb_get_guint8(tvb, 2) != MM_TID_HDR)
344 dissect_mmse(tvb, pinfo, tree);
349 dissect_mmse(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
358 /* Set up structures needed to add the protocol subtree and manage it */
360 proto_tree *mmse_tree;
362 pdut = tvb_get_guint8(tvb, 1);
363 /* Make entries in Protocol column and Info column on summary display */
364 if (check_col(pinfo->cinfo, COL_PROTOCOL))
365 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MMSE");
367 if (check_col(pinfo->cinfo, COL_INFO)) {
368 col_clear(pinfo->cinfo, COL_INFO);
369 col_add_fstr(pinfo->cinfo, COL_INFO, "MMS %s",
370 match_strval(pdut, vals_message_type));
373 /* In the interest of speed, if "tree" is NULL, don't do any work not
374 * necessary to generate protocol tree items.
377 offset = 2; /* Skip Message-Type */
379 /* create display subtree for the protocol */
380 ti = proto_tree_add_item(tree, proto_mmse, tvb, 0,
381 tvb_length(tvb), FALSE);
382 mmse_tree = proto_item_add_subtree(ti, ett_mmse);
384 /* Report PDU-type */
385 proto_tree_add_uint(mmse_tree, hf_mmse_message_type, tvb, 0, 2, pdut);
387 * Cycle through MMS-headers
389 while ((offset < tvb_length(tvb)) &&
390 (field = tvb_get_guint8(tvb, offset++)) != MM_CTYPE_HDR)
394 case MM_TID_HDR: /* Text-string */
395 length = get_text_string(tvb, offset, strval);
396 proto_tree_add_string(mmse_tree, hf_mmse_transaction_id,
397 tvb, offset - 1, length + 1,strval);
400 case MM_VERSION_HDR: /* nibble-Major/nibble-minor*/
401 field = tvb_get_guint8(tvb, offset++);
405 major = (field & 0x70) >> 4;
406 minor = field & 0x0F;
408 sprintf(strval, "%d", major);
410 sprintf(strval, "%d.%d", major, minor);
412 proto_tree_add_string(mmse_tree, hf_mmse_mms_version, tvb,
413 offset - 2, 2, strval);
415 case MM_BCC_HDR: /* Encoded-string-value */
416 length = get_encoded_strval(tvb, offset, strval);
417 proto_tree_add_string(mmse_tree, hf_mmse_bcc, tvb,
418 offset - 1, length + 1, strval);
421 case MM_CC_HDR: /* Encoded-string-value */
422 length = get_encoded_strval(tvb, offset, strval);
423 proto_tree_add_string(mmse_tree, hf_mmse_cc, tvb,
424 offset - 1, length + 1, strval);
427 case MM_CLOCATION_HDR: /* Uri-value */
428 length = get_text_string(tvb, offset, strval);
429 proto_tree_add_string(mmse_tree, hf_mmse_content_location,
430 tvb, offset - 1, length + 1,strval);
433 case MM_DATE_HDR: /* Long-integer */
438 tval = get_long_integer(tvb, offset, &count);
441 proto_tree_add_time(mmse_tree, hf_mmse_date, tvb,
442 offset - 1, count + 1, &tmptime);
446 case MM_DREPORT_HDR: /* Yes|No */
447 field = tvb_get_guint8(tvb, offset++);
448 proto_tree_add_uint(mmse_tree, hf_mmse_delivery_report, tvb,
449 offset - 2, 2, field);
453 * Value-length(Absolute-token Date-value|
454 * Relative-token Delta-seconds-value)
456 length = get_value_length(tvb, offset, &count);
457 field = tvb_get_guint8(tvb, offset + count);
463 tval = get_long_integer(tvb, offset + count, &cnt);
467 proto_tree_add_time(mmse_tree,
468 hf_mmse_delivery_time_abs,
470 length + count + 1, &tmptime);
472 proto_tree_add_time(mmse_tree,
473 hf_mmse_delivery_time_rel,
475 length + count + 1, &tmptime);
477 offset += length + count;
481 * Value-length(Absolute-token Date-value|
482 * Relative-token Delta-seconds-value)
484 length = get_value_length(tvb, offset, &count);
485 field = tvb_get_guint8(tvb, offset + count);
491 tval = get_long_integer(tvb, offset + count + 1, &cnt);
495 proto_tree_add_time(mmse_tree, hf_mmse_expiry_abs,
497 length + count + 1, &tmptime);
499 proto_tree_add_time(mmse_tree, hf_mmse_expiry_rel,
501 length + count + 1, &tmptime);
503 offset += length + count;
507 * Value-length(Address-present-token Encoded-string-value
508 * |Insert-address-token)
510 length = get_value_length(tvb, offset, &count);
511 field = tvb_get_guint8(tvb, offset + count);
513 strcpy(strval, "<insert address>");
515 (void) get_encoded_strval(tvb, offset + count + 1,
518 proto_tree_add_string(mmse_tree, hf_mmse_from, tvb,
519 offset-1, length + 2, strval);
520 offset += length + 1;
524 * Class-identifier|Text-string
526 field = tvb_get_guint8(tvb, offset);
529 proto_tree_add_uint(mmse_tree,
530 hf_mmse_message_class_id,
531 tvb, offset - 2, 2, field);
533 length = get_text_string(tvb, offset, strval);
534 proto_tree_add_string(mmse_tree,
535 hf_mmse_message_class_str,
536 tvb, offset - 1, length + 1,
541 case MM_MID_HDR: /* Text-string */
542 length = get_text_string(tvb, offset, strval);
543 proto_tree_add_string(mmse_tree, hf_mmse_message_id, tvb,
544 offset - 1, length + 1, strval);
547 case MM_MSIZE_HDR: /* Long-integer */
548 length = get_long_integer(tvb, offset, &count);
549 proto_tree_add_uint(mmse_tree, hf_mmse_message_size, tvb,
550 offset - 1, count + 1, length);
553 case MM_PRIORITY_HDR: /* Low|Normal|High */
554 field = tvb_get_guint8(tvb, offset++);
555 proto_tree_add_uint(mmse_tree, hf_mmse_priority, tvb,
556 offset - 2, 2, field);
558 case MM_RREPLY_HDR: /* Yes|No */
559 field = tvb_get_guint8(tvb, offset++);
560 proto_tree_add_uint(mmse_tree, hf_mmse_read_reply, tvb,
561 offset - 2, 2, field);
563 case MM_RALLOWED_HDR: /* Yes|No */
564 field = tvb_get_guint8(tvb, offset++);
565 proto_tree_add_uint(mmse_tree, hf_mmse_report_allowed, tvb,
566 offset - 2, 2, field);
569 field = tvb_get_guint8(tvb, offset++);
570 proto_tree_add_uint(mmse_tree, hf_mmse_response_status, tvb,
571 offset - 2, 2, field);
573 case MM_RTEXT_HDR: /* Encoded-string-value */
574 length = get_encoded_strval(tvb, offset, strval);
575 proto_tree_add_string(mmse_tree, hf_mmse_response_text, tvb,
576 offset - 1, length + 1, strval);
579 case MM_SVISIBILITY_HDR: /* Hide|Show */
580 field = tvb_get_guint8(tvb, offset++);
581 proto_tree_add_uint(mmse_tree,hf_mmse_sender_visibility,
582 tvb, offset - 2, 2, field);
585 field = tvb_get_guint8(tvb, offset++);
586 proto_tree_add_uint(mmse_tree, hf_mmse_status, tvb,
587 offset - 2, 2, field);
589 case MM_SUBJECT_HDR: /* Encoded-string-value */
590 length = get_encoded_strval(tvb, offset, strval);
591 proto_tree_add_string(mmse_tree, hf_mmse_subject, tvb,
592 offset - 1, length + 1, strval);
595 case MM_TO_HDR: /* Encoded-string-value */
596 length = get_encoded_strval(tvb, offset, strval);
597 proto_tree_add_string(mmse_tree, hf_mmse_to, tvb,
598 offset - 1, length + 1, strval);
604 "MMSE - Unknown field encountered (0x%02x)\n",
608 char strval2[BUFSIZ];
611 length = get_text_string(tvb, offset, strval);
612 length2= get_text_string(tvb, offset+length, strval2);
614 proto_tree_add_string_format(mmse_tree,
617 length + length2, NULL,
618 "%s : %s",strval,strval2);
619 offset += length + length2;
624 if (field == MM_CTYPE_HDR) {
626 * Eeehh, we're now actually back to good old WSP content-type
627 * encoding for multipart/related and multipart/mixed MIME-types.
628 * Let's steal that from the WSP-dissector.
632 const char *type_str;
634 offset = add_content_type(mmse_tree, tvb, offset, &type, &type_str);
635 tmp_tvb = tvb_new_subset(tvb, offset,
636 tvb_length_remaining(tvb, offset),
637 tvb_length_remaining(tvb, offset));
638 add_multipart_data(mmse_tree, tmp_tvb);
642 /* If this protocol has a sub-dissector call it here, see section 1.8 */
646 /* Register the protocol with Ethereal */
648 /* this format is required because a script is used to build the C function
649 * that calls all the protocol registration.
652 proto_register_mmse(void)
654 /* Setup list of header fields See Section 1.6.1 for details */
655 static hf_register_info hf[] = {
656 { &hf_mmse_message_type,
657 { "Message-Type", "mmse.message_type",
658 FT_UINT8, BASE_HEX, VALS(vals_message_type), 0x00,
659 "Specifies the transaction type. Effectively defines PDU.",
663 { &hf_mmse_transaction_id,
664 { "Transaction-ID", "mmse.transaction_id",
665 FT_STRING, BASE_NONE, NULL, 0x00,
666 "A unique identifier for this transaction. "
667 "Identifies request and corresponding response only.",
671 { &hf_mmse_mms_version,
672 { "MMS-Version", "mmse.mms_version",
673 FT_STRING, BASE_NONE, NULL, 0x00,
674 "Version of the protocol used.",
680 FT_STRING, BASE_NONE, NULL, 0x00,
681 "Blind carbon copy.",
687 FT_STRING, BASE_NONE, NULL, 0x00,
692 { &hf_mmse_content_location,
693 { "Content-Location", "mmse.content_location",
694 FT_STRING, BASE_NONE, NULL, 0x00,
695 "Defines the location of the message.",
700 { "Date", "mmse.date",
701 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
702 "Arrival timestamp of the message or sending timestamp.",
706 { &hf_mmse_delivery_report,
707 { "Delivery-Report", "mmse.delivery_report",
708 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
709 "Whether a report of message delivery is wanted or not.",
713 { &hf_mmse_delivery_time_abs,
714 { "Delivery-Time", "mmse.delivery_time.abs",
715 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
716 "The time at which message delivery is desired.",
720 { &hf_mmse_delivery_time_rel,
721 { "Delivery-Time", "mmse.delivery_time.rel",
722 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
723 "The desired message delivery delay.",
727 { &hf_mmse_expiry_abs,
728 { "Expiry", "mmse.expiry.abs",
729 FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
730 "Time when message expires and need not be delivered anymore.",
734 { &hf_mmse_expiry_rel,
735 { "Expiry", "mmse.expiry.rel",
736 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x00,
737 "Delay before message expires and need not be delivered anymore.",
742 { "From", "mmse.from",
743 FT_STRING, BASE_NONE, NULL, 0x00,
744 "Address of the message sender.",
748 { &hf_mmse_message_class_id,
749 { "Message-Class", "mmse.message_class.id",
750 FT_UINT8, BASE_HEX, VALS(vals_message_class), 0x00,
751 "Of what category is the message.",
755 { &hf_mmse_message_class_str,
756 { "Message-Class", "mmse.message_class.str",
757 FT_STRING, BASE_NONE, NULL, 0x00,
758 "Of what category is the message.",
762 { &hf_mmse_message_id,
763 { "Message-Id", "mmse.message_id",
764 FT_STRING, BASE_NONE, NULL, 0x00,
765 "Unique identification of the message.",
769 { &hf_mmse_message_size,
770 { "Message-Size", "mmse.message_size",
771 FT_UINT32, BASE_DEC, NULL, 0x00,
772 "The size of the message in octets.",
777 { "Priority", "mmse.priority",
778 FT_UINT8, BASE_HEX, VALS(vals_priority), 0x00,
779 "Priority of the message.",
783 { &hf_mmse_read_reply,
784 { "Read-Reply", "mmse.read_reply",
785 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
786 "Whether a read report from every recipient is wanted.",
790 { &hf_mmse_report_allowed,
791 { "Report-Allowed", "mmse.report_allowed",
792 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
793 "Sending of delivery report allowed or not.",
797 { &hf_mmse_response_status,
798 { "Response-Status", "mmse.response_status",
799 FT_UINT8, BASE_HEX, VALS(vals_response_status), 0x00,
800 "MMS-specific result of a message submission or retrieval.",
804 { &hf_mmse_response_text,
805 { "Response-Text", "mmse.response_text",
806 FT_STRING, BASE_NONE, NULL, 0x00,
807 "Additional information on MMS-specific result.",
811 { &hf_mmse_sender_visibility,
812 { "Sender-Visibility", "mmse.sender_visibility",
813 FT_UINT8, BASE_HEX, VALS(vals_yes_no), 0x00,
814 "Disclose sender identity to receiver or not.",
819 { "Status", "mmse.status",
820 FT_UINT8, BASE_HEX, VALS(vals_status), 0x00,
821 "Current status of the message.",
826 { "Subject", "mmse.subject",
827 FT_STRING, BASE_NONE, NULL, 0x00,
828 "Subject of the message.",
834 FT_STRING, BASE_NONE, NULL, 0x00,
835 "Recipient(s) of the message.",
839 { &hf_mmse_content_type,
840 { "Data", "mmse.content_type",
841 FT_NONE, BASE_NONE, NULL, 0x00,
842 "Media content of the message.",
847 { "Free format (not encoded) header", "mmse.ffheader",
848 FT_STRING, BASE_NONE, NULL, 0x00,
849 "Application header without corresponding encoding.",
854 /* Setup protocol subtree array */
855 static gint *ett[] = {
859 /* Register the protocol name and description */
860 proto_mmse = proto_register_protocol("MMS Message Encapsulation",
863 /* Required function calls to register header fields and subtrees used */
864 proto_register_field_array(proto_mmse, hf, array_length(hf));
865 proto_register_subtree_array(ett, array_length(ett));
868 /* If this dissector uses sub-dissector registration add registration routine.
869 * This format is required because a script is used to find these routines and
870 * create the code that calls these routines.
873 proto_reg_handoff_mmse(void)
875 dissector_handle_t mmse_handle;
877 heur_dissector_add("wsp", dissect_mmse_heur, proto_mmse);
878 mmse_handle = create_dissector_handle(dissect_mmse, proto_mmse);
879 dissector_add("wsp.content_type.type", MMS_CONTENT_TYPE,
883 * The bearer could also be http (through the content-type field).
884 * The wsp-dissector should then ofcourse be modified to cater for
885 * such subdissectors...