aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ansi_637.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-ansi_637.c')
-rw-r--r--epan/dissectors/packet-ansi_637.c1937
1 files changed, 1937 insertions, 0 deletions
diff --git a/epan/dissectors/packet-ansi_637.c b/epan/dissectors/packet-ansi_637.c
new file mode 100644
index 0000000000..8285ed698f
--- /dev/null
+++ b/epan/dissectors/packet-ansi_637.c
@@ -0,0 +1,1937 @@
+/* packet-ansi_637.c
+ * Routines for ANSI IS-637-A (SMS) dissection
+ *
+ * Copyright 2003, Michael Lum <mlum [AT] telostech.com>
+ * In association with Telos Technology Inc.
+ *
+ * Title 3GPP2 Other
+ *
+ * Short Message Service
+ * 3GPP2 C.S0015-0 TIA/EIA-637-A
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gmodule.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#include <string.h>
+
+#include "epan/packet.h"
+
+
+static char *ansi_proto_name_tele = "ANSI IS-637-A (SMS) Teleservice Layer";
+static char *ansi_proto_name_trans = "ANSI IS-637-A (SMS) Transport Layer";
+static char *ansi_proto_name_short = "IS-637-A";
+
+static const value_string ansi_srvc_cat_strings[] = {
+ { 0x0000, "Unknown or unspecified" },
+ { 0x0001, "Emergency Broadcasts" },
+ { 0x0002, "Administrative" },
+ { 0x0003, "Maintenance" },
+ { 0x0004, "General News - Local" },
+ { 0x0005, "General News - Regional" },
+ { 0x0006, "General News - National" },
+ { 0x0007, "General News - International" },
+ { 0x0008, "Business/Financial News - Local" },
+ { 0x0009, "Business/Financial News - Regional" },
+ { 0x000A, "Business/Financial News - National" },
+ { 0x000B, "Business/Financial News - International" },
+ { 0x000C, "Sports News - Local" },
+ { 0x000D, "Sports News - Regional" },
+ { 0x000E, "Sports News - National" },
+ { 0x000F, "Sports News - International" },
+ { 0x0010, "Entertainment News - Local" },
+ { 0x0011, "Entertainment News - Regional" },
+ { 0x0012, "Entertainment News - National" },
+ { 0x0013, "Entertainment News - International" },
+ { 0x0014, "Local Weather" },
+ { 0x0015, "Area Traffic Reports" },
+ { 0x0016, "Local Airport Flight Schedules" },
+ { 0x0017, "Restaurants" },
+ { 0x0018, "Lodgings" },
+ { 0x0019, "Retail Directory" },
+ { 0x001A, "Advertisements" },
+ { 0x001B, "Stock Quotes" },
+ { 0x001C, "Employment Opportunities" },
+ { 0x001D, "Medical/Health/Hospitals" },
+ { 0x001E, "Technology News" },
+ { 0x001F, "Multi-category" },
+ { 0, NULL },
+};
+
+static const value_string ansi_tele_msg_type_strings[] = {
+ { 1, "Deliver (mobile-terminated only)" },
+ { 2, "Submit (mobile-originated only)" },
+ { 3, "Cancellation (mobile-originated only)" },
+ { 4, "Delivery Acknowledgement (mobile-terminated only)" },
+ { 5, "User Acknowledgement (either direction)" },
+ { 0, NULL },
+};
+
+static const value_string ansi_tele_id_strings[] = {
+ { 1, "Reserved for maintenance" },
+ { 4096, "AMPS Extended Protocol Enhanced Services" },
+ { 4097, "CDMA Cellular Paging Teleservice" },
+ { 4098, "CDMA Cellular Messaging Teleservice" },
+ { 4099, "CDMA Voice Mail Notification" },
+ { 32513, "TDMA Cellular Messaging Teleservice" },
+ { 32520, "TDMA System Assisted Mobile Positioning through Satellite (SAMPS)" },
+ { 32584, "TDMA Segmented System Assisted Mobile Positioning Service" },
+ { 0, NULL },
+};
+
+static const value_string ansi_tele_param_strings[] = {
+ { 0x00, "Message Identifier" },
+ { 0x01, "User Data" },
+ { 0x02, "User Response Code" },
+ { 0x03, "Message Center Time Stamp" },
+ { 0x04, "Validity Period - Absolute" },
+ { 0x05, "Validity Period - Relative" },
+ { 0x06, "Deferred Delivery Time - Absolute" },
+ { 0x07, "Deferred Delivery Time - Relative" },
+ { 0x08, "Priority Indicator" },
+ { 0x09, "Privacy Indicator" },
+ { 0x0a, "Reply Option" },
+ { 0x0b, "Number of Messages" },
+ { 0x0c, "Alert on Message Delivery" },
+ { 0x0d, "Language Indicator" },
+ { 0x0e, "Call-Back Number" },
+ { 0x0f, "Message Display Mode" },
+ { 0x10, "Multiple Encoding User Data" },
+ { 0, NULL },
+};
+
+static const value_string ansi_trans_msg_type_strings[] = {
+ { 0, "Point-to-Point" },
+ { 1, "Broadcast" },
+ { 2, "Acknowledge" },
+ { 0, NULL },
+};
+
+static const value_string ansi_trans_param_strings[] = {
+ { 0x00, "Teleservice Identifier" },
+ { 0x01, "Service Category" },
+ { 0x02, "Originating Address" },
+ { 0x03, "Originating Subaddress" },
+ { 0x04, "Destination Address" },
+ { 0x05, "Destination Subaddress" },
+ { 0x06, "Bearer Reply Option" },
+ { 0x07, "Cause Codes" },
+ { 0x08, "Bearer Data" },
+ { 0, NULL },
+};
+
+/*
+ * from Table 2.7.1.3.2.4-4. Representation of DTMF Digits
+ * 3GPP2 C.S0005-C (IS-2000 aka cdma2000)
+ */
+static unsigned char air_digits[] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e */
+ '?','1','2','3','4','5','6','7','8','9','0','*','#','?','?'
+};
+
+/* Initialize the protocol and registered fields */
+static int proto_ansi_637_tele = -1;
+static int proto_ansi_637_trans = -1;
+static int hf_ansi_637_none = -1;
+static int hf_ansi_637_length = -1;
+static int hf_ansi_637_bin_addr = -1;
+static int hf_ansi_637_tele_msg_type = -1;
+static int hf_ansi_637_tele_msg_id = -1;
+static int hf_ansi_637_tele_msg_rsvd = -1;
+static int hf_ansi_637_tele_subparam_id = -1;
+static int hf_ansi_637_trans_msg_type = -1;
+static int hf_ansi_637_trans_param_id = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_ansi_637_tele = -1;
+static gint ett_ansi_637_trans = -1;
+static gint ett_params = -1;
+
+static guint32 ansi_637_trans_tele_id;
+static char ansi_637_bigbuf[1024];
+static gchar ansi_637_add_string[1024];
+static dissector_handle_t data_handle;
+static dissector_table_t tele_dissector_table;
+static packet_info *g_pinfo;
+static proto_tree *g_tree;
+
+/* FUNCTIONS */
+
+static void
+decode_7_bits(tvbuff_t *tvb, guint32 *offset, guint8 num_fields, guint8 *last_oct, guint8 *last_bit, gchar *buf)
+{
+ guint8 oct, oct2, bit;
+ guint32 saved_offset;
+ guint32 i;
+
+
+ if (num_fields == 0)
+ {
+ return;
+ }
+
+ saved_offset = *offset;
+ oct = oct2 = *last_oct;
+ bit = *last_bit;
+
+ if (bit == 1)
+ {
+ oct2 = tvb_get_guint8(tvb, *offset);
+ (*offset)++;
+ }
+
+ for (i=0; i < num_fields; i++)
+ {
+ if (bit != 1)
+ {
+ oct = oct2;
+
+ /*
+ * cannot grab an octet if we are getting
+ * the last field and bit is 7 or 8
+ * because there may not be another octet
+ */
+ if (((i + 1) != num_fields) ||
+ ((bit != 7) && (bit != 8)))
+ {
+ oct2 = tvb_get_guint8(tvb, *offset);
+ (*offset)++;
+ }
+ }
+
+ switch (bit)
+ {
+ case 1:
+ buf[i] = ((oct & 0x01) << 6) | ((oct2 & 0xfc) >> 2);
+ break;
+
+ case 2:
+ buf[i] = ((oct & 0x03) << 5) | ((oct2 & 0xf8) >> 3);
+ break;
+
+ case 3:
+ buf[i] = ((oct & 0x07) << 4) | ((oct2 & 0xf0) >> 4);
+ break;
+
+ case 4:
+ buf[i] = ((oct & 0x0f) << 3) | ((oct2 & 0xe0) >> 5);
+ break;
+
+ case 5:
+ buf[i] = ((oct & 0x1f) << 2) | ((oct2 & 0xc0) >> 6);
+ break;
+
+ case 6:
+ buf[i] = ((oct & 0x3f) << 1) | ((oct2 & 0x80) >> 7);
+ break;
+
+ case 7:
+ buf[i] = oct & 0x7f;
+ break;
+
+ case 8:
+ buf[i] = (oct & 0xfe) >> 1;
+ break;
+ }
+
+ bit = (bit % 8) + 1;
+ }
+
+ buf[i] = '\0';
+ *last_bit = bit;
+ *last_oct = (bit == 1) ? oct : oct2;
+}
+
+static gchar *
+my_match_strval(guint32 val, const value_string *vs, gint *idx)
+{
+ gint i = 0;
+
+ while (vs[i].strptr)
+ {
+ if (vs[i].value == val)
+ {
+ *idx = i;
+ return(vs[i].strptr);
+ }
+
+ i++;
+ }
+
+ *idx = -1;
+ return(NULL);
+}
+
+
+/* PARAM FUNCTIONS */
+
+#define EXTRANEOUS_DATA_CHECK(edc_len, edc_max_len) \
+ if ((edc_len) > (edc_max_len)) \
+ { \
+ proto_tree_add_text(tree, tvb, offset, \
+ (edc_len) - (edc_max_len), "Extraneous Data"); \
+ }
+
+#define SHORT_DATA_CHECK(sdc_len, sdc_min_len) \
+ if ((sdc_len) < (sdc_min_len)) \
+ { \
+ proto_tree_add_text(tree, tvb, offset, \
+ (sdc_len), "Short Data (?)"); \
+ return; \
+ }
+
+#define EXACT_DATA_CHECK(edc_len, edc_eq_len) \
+ if ((edc_len) != (edc_eq_len)) \
+ { \
+ proto_tree_add_text(tree, tvb, offset, \
+ (edc_len), "Unexpected Data Length"); \
+ return; \
+ }
+
+static void
+tele_param_user_data(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct, oct2;
+ guint8 encoding;
+ guint8 msg_type;
+ guint8 num_fields;
+ guint8 used;
+ guint8 bit;
+ guint32 required_octs;
+ guint32 saved_offset;
+ guint32 i;
+ gchar *str = NULL;
+
+ SHORT_DATA_CHECK(len, 2);
+
+ /*
+ * message encoding
+ */
+ oct = tvb_get_guint8(tvb, offset);
+ oct2 = 0;
+ msg_type = 0;
+ used = 0;
+
+ encoding = ((oct & 0xf8) >> 3);
+ switch (encoding)
+ {
+ case 0x00: str = "Octet, unspecified"; break;
+ case 0x01: str = "Extended Protocol Message";
+ oct2 = tvb_get_guint8(tvb, offset+1);
+ msg_type = ((oct & 0x07) << 5) | ((oct2 & 0xf8) >> 3);
+ break;
+ case 0x02: str = "7-bit ASCII"; break;
+ case 0x03: str = "IA5"; break;
+ case 0x04: str = "UNICODE"; break;
+ case 0x05: str = "Shift-JIS"; break;
+ case 0x06: str = "Korean"; break;
+ case 0x07: str = "Latin/Hebrew"; break;
+ case 0x08: str = "Latin"; break;
+ case 0x09: str = "GSM 7-bit default alphabet"; break;
+ default: str = "Reserved"; break;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xf8, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Encoding: %s",
+ ansi_637_bigbuf,
+ str);
+
+ if (encoding == 0x01)
+ {
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Message type: see TIA/EIA/IS-91 (%d)",
+ ansi_637_bigbuf,
+ msg_type);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0xf8, 8);
+ proto_tree_add_text(tree, tvb, offset+1, 1,
+ "%s : Message type",
+ ansi_637_bigbuf);
+
+ oct = oct2;
+ offset++;
+ used++;
+ }
+
+ offset++;
+ used++;
+
+ /*
+ * number of fields
+ */
+ oct2 = tvb_get_guint8(tvb, offset);
+ num_fields = ((oct & 0x07) << 5) | ((oct2 & 0xf8) >> 3);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree, tvb, offset-1, 1,
+ "%s : Number of fields (MSB): %d",
+ ansi_637_bigbuf,
+ num_fields);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0xf8, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number of fields (LSB)",
+ ansi_637_bigbuf);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0x07, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Most significant bits of first field",
+ ansi_637_bigbuf);
+
+ offset++;
+ used++;
+ oct = oct2;
+
+ /* NOTE: there are now 3 bits remaining in 'oct' */
+
+ if (len - used <= 0) return;
+
+ /*
+ * decode rest if 7-bit ASCII
+ */
+ if (encoding == 0x02)
+ {
+ /*
+ * magic numbers:
+ * 3 bits remaining from last octet
+ * 7 bit encoding
+ * 8 bits per octet
+ */
+ i = (num_fields * 7) - 3;
+ required_octs = (i / 8) + ((i % 8) ? 1 : 0);
+
+ if (required_octs + used > len)
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Missing %d octet(s) for number of fields",
+ (required_octs + used) - len);
+
+ return;
+ }
+
+ bit = 3;
+ saved_offset = offset;
+
+ decode_7_bits(tvb, &offset, num_fields, &oct, &bit, ansi_637_bigbuf);
+
+ proto_tree_add_text(tree, tvb, saved_offset, offset - saved_offset,
+ "Encoded user data: %s",
+ ansi_637_bigbuf);
+
+ switch (bit)
+ {
+ case 1: oct2 = 0x01; break;
+ case 2: oct2 = 0x03; break;
+ case 3: oct2 = 0x07; break;
+ case 4: oct2 = 0x0f; break;
+ case 5: oct2 = 0x1f; break;
+ case 6: oct2 = 0x3f; break;
+ case 7: oct2 = 0x7f; break;
+ }
+
+ if (bit != 8)
+ {
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, oct2, 8);
+ proto_tree_add_text(tree, tvb, offset - 1, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+ }
+ }
+ else
+ {
+ proto_tree_add_text(tree, tvb, offset, len - used,
+ "Encoded user data");
+ }
+}
+
+static void
+tele_param_rsp_code(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ /*
+ * response code
+ */
+ oct = tvb_get_guint8(tvb, offset);
+
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Response code: %d",
+ oct);
+}
+
+static void
+tele_param_timestamp(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct, oct2, oct3;
+
+ EXACT_DATA_CHECK(len, 6);
+
+ oct = tvb_get_guint8(tvb, offset);
+ oct2 = tvb_get_guint8(tvb, offset+1);
+ oct3 = tvb_get_guint8(tvb, offset+2);
+
+ proto_tree_add_text(tree, tvb, offset, 3,
+ "Year %d%d, Month %d%d, Day %d%d",
+ (oct & 0xf0) >> 4,
+ oct & 0x0f,
+ (oct2 & 0xf0) >> 4,
+ oct2 & 0x0f,
+ (oct3 & 0xf0) >> 4,
+ oct3 & 0x0f);
+
+ offset += 3;
+
+ oct = tvb_get_guint8(tvb, offset);
+ oct2 = tvb_get_guint8(tvb, offset+1);
+ oct3 = tvb_get_guint8(tvb, offset+2);
+
+ proto_tree_add_text(tree, tvb, offset, 3,
+ "Hour %d%d, Minutes %d%d, Seconds %d%d",
+ (oct & 0xf0) >> 4,
+ oct & 0x0f,
+ (oct2 & 0xf0) >> 4,
+ oct2 & 0x0f,
+ (oct3 & 0xf0) >> 4,
+ oct3 & 0x0f);
+}
+
+static void
+tele_param_rel_timestamp(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+ guint32 value = 0;
+ gchar *str = NULL;
+ gchar *str2 = NULL;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch (oct)
+ {
+ case 245: str = "Indefinite"; break;
+ case 246: str = "Immediate"; break;
+ case 247: str = "Valid until mobile becomes inactive/Deliver when mobile next becomes active"; break;
+ case 248: str = "Valid until registration area changes, discard if not registered" ; break;
+ default:
+ if (oct <= 143) { value = (oct + 1) * 5; str2 = "Minutes"; break; }
+ else if ((oct >= 144) && (oct <= 167)) { value = (oct - 143) * 30; str2 = "Minutes + 12 Hours"; break; }
+ else if ((oct >= 168) && (oct <= 196)) { value = oct - 166; str2 = "Days"; break; }
+ else if ((oct >= 197) && (oct <= 244)) { value = oct - 192; str2 = "Weeks"; break; }
+ else { str = "Reserved"; break; }
+ }
+
+ if (str == NULL)
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ str2);
+ }
+ else
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%d %s",
+ value, str2);
+ }
+}
+
+static void
+tele_param_pri_ind(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+ gchar *str = NULL;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch ((oct & 0xc0) >> 6)
+ {
+ case 0: str = "Normal"; break;
+ case 1: str = "Interactive"; break;
+ case 2: str = "Urgent"; break;
+ case 3: str = "Emergency"; break;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xc0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : %s",
+ ansi_637_bigbuf,
+ str);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+}
+
+static void
+tele_param_priv_ind(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+ gchar *str = NULL;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch ((oct & 0xc0) >> 6)
+ {
+ case 0: str = "Not restricted (privacy level 0)"; break;
+ case 1: str = "Restricted (privacy level 1)"; break;
+ case 2: str = "Confidential (privacy level 2)"; break;
+ case 3: str = "Secret (privacy level 3)"; break;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xc0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : %s",
+ ansi_637_bigbuf,
+ str);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+}
+
+static void
+tele_param_reply_opt(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : %s (manual) acknowledgment is requested",
+ ansi_637_bigbuf,
+ (oct & 0x80) ? "User" : "No user");
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x40, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : %s acknowledgment requested",
+ ansi_637_bigbuf,
+ (oct & 0x40) ? "Delivery" : "No delivery");
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+}
+
+static void
+tele_param_num_messages(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Number of voice mail messages: %d%d",
+ (oct & 0xf0) >> 4,
+ oct & 0x0f);
+}
+
+static void
+tele_param_alert(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+ gchar *str = NULL;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch ((oct & 0xc0) >> 6)
+ {
+ case 0: str = "Use Mobile default alert"; break;
+ case 1: str = "Use Low-priority alert"; break;
+ case 2: str = "Use Medium-priority alert"; break;
+ case 3: str = "Use High-priority alert"; break;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xc0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : %s",
+ ansi_637_bigbuf,
+ str);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+}
+
+static void
+tele_param_lang_ind(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+ gchar *str = NULL;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch (oct)
+ {
+ case 0x00: str = "Unknown or unspecified"; break;
+ case 0x01: str = "English"; break;
+ case 0x02: str = "French"; break;
+ case 0x03: str = "Spanish"; break;
+ case 0x04: str = "Japanese"; break;
+ case 0x05: str = "Korean"; break;
+ case 0x06: str = "Chinese"; break;
+ case 0x07: str = "Hebrew"; break;
+ default: str = "Reserved"; break;
+ }
+
+ proto_tree_add_text(tree, tvb, offset, 1,
+ str);
+}
+
+static void
+tele_param_cb_num(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct, oct2, num_fields, odd;
+ guint32 saved_offset;
+ guint32 required_octs;
+ guint32 i;
+
+ SHORT_DATA_CHECK(len, 2);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Digit mode: %s",
+ ansi_637_bigbuf,
+ (oct & 0x80) ? "8-bit ASCII" : "4-bit DTMF");
+
+ if (oct & 0x80)
+ {
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x70, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Type of number: (%d)",
+ ansi_637_bigbuf,
+ (oct & 0x70) >> 4);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Numbering plan: (%d)",
+ ansi_637_bigbuf,
+ oct & 0x0f);
+
+ offset++;
+ num_fields = tvb_get_guint8(tvb, offset);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xff, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number of fields: (%d)",
+ ansi_637_bigbuf,
+ num_fields);
+
+ if (num_fields == 0) return;
+
+ if (num_fields > (len - 2))
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Missing %d octet(s) for number of fields",
+ (num_fields + 2) - len);
+
+ return;
+ }
+
+ offset++;
+
+ i = 0;
+ while (i < num_fields)
+ {
+ ansi_637_bigbuf[i] = tvb_get_guint8(tvb, offset+i) & 0x7f;
+ i++;
+ }
+ ansi_637_bigbuf[i] = '\0';
+
+ proto_tree_add_text(tree, tvb, offset, num_fields,
+ "Number: %s",
+ ansi_637_bigbuf);
+ }
+ else
+ {
+ offset++;
+ num_fields = (oct & 0x7f) << 1;
+ oct2 = tvb_get_guint8(tvb, offset);
+ num_fields |= ((oct2 & 0x80) >> 7);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree, tvb, offset-1, 1,
+ "%s : Number of fields (MBS): (%d)",
+ ansi_637_bigbuf,
+ num_fields);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0x80, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number of fields (LSB)",
+ ansi_637_bigbuf);
+
+ oct = oct2;
+ odd = FALSE;
+
+ if (num_fields > 0)
+ {
+ i = (num_fields - 1) * 4;
+ required_octs = (i / 8) + ((i % 8) ? 1 : 0);
+
+ if (required_octs + 2 > len)
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Missing %d octet(s) for number of fields",
+ (required_octs + 2) - len);
+
+ return;
+ }
+
+ odd = num_fields & 0x01;
+ memset((void *) ansi_637_bigbuf, 0, sizeof(ansi_637_bigbuf));
+ saved_offset = offset;
+ offset++;
+
+ i = 0;
+ while (i < num_fields)
+ {
+ ansi_637_bigbuf[i] =
+ air_digits[(oct & 0x78) >> 3];
+
+ i++;
+ if (i >= num_fields) break;
+
+ oct2 = tvb_get_guint8(tvb, offset);
+ offset++;
+
+ ansi_637_bigbuf[i] =
+ air_digits[((oct & 0x07) << 1) | ((oct2 & 0x80) >> 7)];
+
+ oct = oct2;
+
+ i++;
+ }
+
+ proto_tree_add_text(tree, tvb, saved_offset, offset - saved_offset,
+ "Number: %s",
+ ansi_637_bigbuf);
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, odd ? 0x07: 0x7f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+ }
+}
+
+static void
+tele_param_disp_mode(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
+{
+ guint8 oct;
+ gchar *str = NULL;
+
+ EXACT_DATA_CHECK(len, 1);
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch ((oct & 0xc0) >> 6)
+ {
+ case 0: str = "Immediate Display: The mobile station is to display the received message as soon as possible."; break;
+ case 1: str = "Mobile default setting: The mobile station is to display the received message based on a pre-defined mode in the mobile station."; break;
+ case 2: str = "User Invoke: The mobile station is to display the received message based on the mode selected by the user."; break;
+ case 3: str = "Reserved"; break;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xc0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : %s",
+ ansi_637_bigbuf,
+ str);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+}
+
+#define NUM_TELE_PARAM (sizeof(ansi_tele_param_strings)/sizeof(value_string))
+static gint ett_ansi_637_tele_param[NUM_TELE_PARAM];
+static void (*ansi_637_tele_param_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = {
+ NULL, /* Message Identifier */
+ tele_param_user_data, /* User Data */
+ tele_param_rsp_code, /* User Response Code */
+ tele_param_timestamp, /* Message Center Time Stamp */
+ tele_param_timestamp, /* Validity Period Absolute */
+ tele_param_rel_timestamp, /* Validity Period Relative */
+ tele_param_timestamp, /* Deferred Delivery Time - Absolute */
+ tele_param_rel_timestamp, /* Deferred Delivery Time - Relative */
+ tele_param_pri_ind, /* Priority Indicator */
+ tele_param_priv_ind, /* Privacy Indicator */
+ tele_param_reply_opt, /* Reply Option */
+ tele_param_num_messages, /* Number of Messages */
+ tele_param_alert, /* Alert on Message Delivery */
+ tele_param_lang_ind, /* Language Indicator */
+ tele_param_cb_num, /* Call-Back Number */
+ tele_param_disp_mode, /* Message Display Mode */
+ NULL, /* Multiple Encoding User Data */
+ NULL, /* NONE */
+};
+
+static void
+trans_param_tele_id(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string)
+{
+ guint32 value;
+ gchar *str = NULL;
+
+ EXACT_DATA_CHECK(len, 2);
+
+ value = tvb_get_ntohs(tvb, offset);
+
+ ansi_637_trans_tele_id = value;
+
+ str = match_strval(value, ansi_tele_id_strings);
+
+ if (NULL == str) str = "Unrecognized Teleservice ID";
+
+ proto_tree_add_text(tree, tvb, offset, 2,
+ "%s (%d)",
+ str,
+ value);
+
+ sprintf(add_string, " - %s (%d)", str, value);
+}
+
+static void
+trans_param_srvc_cat(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string)
+{
+ guint32 value;
+ gchar *str = NULL;
+
+ EXACT_DATA_CHECK(len, 2);
+
+ value = tvb_get_ntohs(tvb, offset);
+
+ str = match_strval(value, ansi_srvc_cat_strings);
+
+ if (NULL == str) str = "Reserved";
+
+ proto_tree_add_text(tree, tvb, offset, 2,
+ str);
+
+ sprintf(add_string, " - %s (%d)", str, value);
+}
+
+static void
+trans_param_address(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string)
+{
+ guint8 oct, oct2, num_fields, odd;
+ gboolean email_addr;
+ guint32 saved_offset;
+ guint32 required_octs;
+ guint32 i;
+ gchar *str;
+
+ SHORT_DATA_CHECK(len, 2);
+
+ add_string = add_string;
+ email_addr = FALSE;
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Digit mode: %s",
+ ansi_637_bigbuf,
+ (oct & 0x80) ? "8-bit ASCII" : "4-bit DTMF");
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x40, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number mode: %s",
+ ansi_637_bigbuf,
+ (oct & 0x40) ? "Data Network Address" : "ANSI T1.607");
+
+ if (oct & 0x80)
+ {
+ if (oct & 0x40)
+ {
+ switch ((oct & 0x38) >> 3)
+ {
+ case 0: str = "Unknown"; break;
+ case 1: str = "Internet Protocol (RFC 791)"; break;
+ case 2: str = "Internet Email Address (RFC 822)"; email_addr = TRUE; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x38, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Type of number: %s (%d)",
+ ansi_637_bigbuf,
+ str,
+ (oct & 0x38) >> 3);
+
+ offset++;
+ num_fields = (oct & 0x07) << 5;
+ oct2 = tvb_get_guint8(tvb, offset);
+ num_fields |= ((oct2 & 0xf8) >> 3);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree, tvb, offset-1, 1,
+ "%s : Number of fields (MSB): (%d)",
+ ansi_637_bigbuf,
+ num_fields);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0xf8, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number of fields (LSB)",
+ ansi_637_bigbuf);
+
+ if (num_fields == 0) return;
+
+ if (num_fields > (len - 2))
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Missing %d octet(s) for number of fields",
+ (num_fields + 2) - len);
+
+ return;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0x07, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Most significant bits of first field",
+ ansi_637_bigbuf);
+
+ offset++;
+ oct = oct2;
+
+ i = 0;
+ while (i < num_fields)
+ {
+ ansi_637_bigbuf[i] = (oct & 0x07) << 5;
+ ansi_637_bigbuf[i] |= ((oct = tvb_get_guint8(tvb, offset+i)) & 0xf8) >> 3;
+ i++;
+ }
+ ansi_637_bigbuf[i] = '\0';
+
+ if (email_addr)
+ {
+ proto_tree_add_text(tree, tvb, offset, num_fields - 1,
+ "Number: %s",
+ ansi_637_bigbuf);
+ }
+ else
+ {
+ proto_tree_add_bytes(tree, hf_ansi_637_bin_addr, tvb, offset, num_fields - 1,
+ ansi_637_bigbuf);
+ }
+
+ offset += (num_fields - 1);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xf8, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Least significant bits of last field",
+ ansi_637_bigbuf);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+ }
+ else
+ {
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x38, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Type of number: (%d)",
+ ansi_637_bigbuf,
+ (oct & 0x38) >> 3);
+
+ oct2 = tvb_get_guint8(tvb, offset + 1);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x07, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Numbering plan (MSB): (%d)",
+ ansi_637_bigbuf,
+ ((oct & 0x07) << 1) | ((oct2 & 0x80) >> 7));
+
+ offset++;
+ oct = oct2;
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Numbering plan (LSB)",
+ ansi_637_bigbuf);
+
+ offset++;
+ num_fields = (oct & 0x7f) << 1;
+ oct2 = tvb_get_guint8(tvb, offset);
+ num_fields |= ((oct2 & 0x80) >> 7);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree, tvb, offset-1, 1,
+ "%s : Number of fields (MSB): (%d)",
+ ansi_637_bigbuf,
+ num_fields);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0x80, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number of fields (LSB)",
+ ansi_637_bigbuf);
+
+ if (num_fields == 0) return;
+
+ if (num_fields > (len - 3))
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Missing %d octet(s) for number of fields",
+ (num_fields + 3) - len);
+
+ return;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0x7f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Most significant bits of first field",
+ ansi_637_bigbuf);
+
+ offset++;
+ oct = oct2;
+
+ i = 0;
+ while (i < num_fields)
+ {
+ ansi_637_bigbuf[i] = (oct & 0x7f) << 1;
+ ansi_637_bigbuf[i] |= ((oct = tvb_get_guint8(tvb, offset+i)) & 0x80) >> 7;
+ i++;
+ }
+ ansi_637_bigbuf[i] = '\0';
+
+ proto_tree_add_text(tree, tvb, offset, num_fields - 1,
+ "Number: %s",
+ ansi_637_bigbuf);
+
+ offset += (num_fields - 1);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x80, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Least significant bit of last field",
+ ansi_637_bigbuf);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x7f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+ }
+ }
+ else
+ {
+ offset++;
+ num_fields = (oct & 0x3f) << 2;
+ oct2 = tvb_get_guint8(tvb, offset);
+ num_fields |= ((oct2 & 0xc0) >> 6);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x3f, 8);
+ proto_tree_add_text(tree, tvb, offset-1, 1,
+ "%s : Number of fields (MSB): (%d)",
+ ansi_637_bigbuf,
+ num_fields);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0xc0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number of fields (LSB)",
+ ansi_637_bigbuf);
+
+ oct = oct2;
+ odd = FALSE;
+
+ if (num_fields > 0)
+ {
+ i = (num_fields - 1) * 4;
+ required_octs = (i / 8) + ((i % 8) ? 1 : 0);
+
+ if (required_octs + 2 > len)
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Missing %d octet(s) for number of fields",
+ (required_octs + 2) - len);
+
+ return;
+ }
+
+ odd = num_fields & 0x01;
+ memset((void *) ansi_637_bigbuf, 0, sizeof(ansi_637_bigbuf));
+ saved_offset = offset;
+ offset++;
+
+ i = 0;
+ while (i < num_fields)
+ {
+ ansi_637_bigbuf[i] =
+ air_digits[(oct & 0x3c) >> 2];
+
+ i++;
+ if (i >= num_fields) break;
+
+ oct2 = tvb_get_guint8(tvb, offset);
+ offset++;
+
+ ansi_637_bigbuf[i] =
+ air_digits[((oct & 0x03) << 2) | ((oct2 & 0xc0) >> 6)];
+
+ oct = oct2;
+
+ i++;
+ }
+
+ proto_tree_add_text(tree, tvb, saved_offset, offset - saved_offset,
+ "Number: %s",
+ ansi_637_bigbuf);
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, odd ? 0x03: 0x3f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+ }
+}
+
+static void
+trans_param_subaddress(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string)
+{
+ guint8 oct, oct2, num_fields;
+ guint32 i;
+ gchar *str;
+
+ SHORT_DATA_CHECK(len, 2);
+
+ add_string = add_string;
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch ((oct & 0xe0) >> 5)
+ {
+ case 0: str = "NSAP (CCITT Recommendation X.213 or ISO 8348 AD2)"; break;
+ case 1: str = "User-specified"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xe0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Type: %s",
+ ansi_637_bigbuf,
+ str);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x10, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Odd",
+ ansi_637_bigbuf);
+
+ offset++;
+ num_fields = (oct & 0x0f) << 4;
+ oct2 = tvb_get_guint8(tvb, offset);
+ num_fields |= ((oct2 & 0xf0) >> 4);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree, tvb, offset-1, 1,
+ "%s : Number of fields (MSB): (%d)",
+ ansi_637_bigbuf,
+ num_fields);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0xf0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Number of fields (LSB)",
+ ansi_637_bigbuf);
+
+ if (num_fields == 0) return;
+
+ if (num_fields > (len - 2))
+ {
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "Missing %d octet(s) for number of fields",
+ (num_fields + 2) - len);
+
+ return;
+ }
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct2, 0x0f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Most significant bits of first field",
+ ansi_637_bigbuf);
+
+ offset++;
+ oct = oct2;
+
+ i = 0;
+ while (i < num_fields)
+ {
+ ansi_637_bigbuf[i] = (oct & 0x0f) << 4;
+ ansi_637_bigbuf[i] |= ((oct = tvb_get_guint8(tvb, offset+i)) & 0xf0) >> 4;
+ i++;
+ }
+ ansi_637_bigbuf[i] = '\0';
+
+ proto_tree_add_bytes(tree, hf_ansi_637_bin_addr, tvb, offset, num_fields - 1,
+ ansi_637_bigbuf);
+
+ offset += (num_fields - 1);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xf0, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Least significant bits of last field",
+ ansi_637_bigbuf);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x0f, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+}
+
+static void
+trans_param_bearer_reply_opt(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string)
+{
+ guint8 oct;
+
+ len = len;
+ oct = tvb_get_guint8(tvb, offset);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xfc, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reply Sequence Number: %d",
+ ansi_637_bigbuf,
+ (oct & 0xfc) >> 2);
+
+ sprintf(add_string, " - Reply Sequence Number (%d)", (oct & 0xfc) >> 2);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x03, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reserved",
+ ansi_637_bigbuf);
+}
+
+static void
+trans_param_cause_codes(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string)
+{
+ guint8 oct;
+ gchar *str = NULL;
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0xfc, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Reply Sequence Number: %d",
+ ansi_637_bigbuf,
+ (oct & 0xfc) >> 2);
+
+ switch (oct & 0x03)
+ {
+ case 0x00: str = "No error"; break;
+ case 0x02: str = "Temporary Condition"; break;
+ case 0x03: str = "Permanent Condition"; break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ sprintf(add_string, " - Reply Sequence Number (%d)", (oct & 0xfc) >> 2);
+
+ other_decode_bitfield_value(ansi_637_bigbuf, oct, 0x03, 8);
+ proto_tree_add_text(tree, tvb, offset, 1,
+ "%s : Error Class: %s",
+ ansi_637_bigbuf,
+ str);
+
+ offset++;
+
+ if (!(oct & 0x03)) return;
+
+ if (len == 1) return;
+
+ oct = tvb_get_guint8(tvb, offset);
+
+ switch (oct)
+ {
+ case 0: str = "Address vacant"; break;
+ case 1: str = "Address translation failure"; break;
+ case 2: str = "Network resource shortage"; break;
+ case 3: str = "Network failure"; break;
+ case 4: str = "Invalid Teleservice ID"; break;
+ case 5: str = "Other network problem"; break;
+ case 6: str = "Unsupported network interface"; break;
+ case 32: str = "No page response"; break;
+ case 33: str = "Destination busy"; break;
+ case 34: str = "No acknowledgement"; break;
+ case 35: str = "Destination resource shortage"; break;
+ case 36: str = "SMS delivery postponed"; break;
+ case 37: str = "Destination out of service"; break;
+ case 38: str = "Destination no longer at this address"; break;
+ case 39: str = "Other terminal problem"; break;
+ case 64: str = "Radio interface resource shortage"; break;
+ case 65: str = "Radio interface incompatibility"; break;
+ case 66: str = "Other radio interface problem"; break;
+ case 67: str = "Unsupported Base Station Capability"; break;
+ case 96: str = "Encoding problem"; break;
+ case 97: str = "Service origination denied"; break;
+ case 98: str = "Service termination denied"; break;
+ case 99: str = "Supplementary service not supported"; break;
+ case 100: str = "Service not supported"; break;
+ case 101: str = "Reserved"; break;
+ case 102: str = "Missing expected parameter"; break;
+ case 103: str = "Missing mandatory parameter"; break;
+ case 104: str = "Unrecognized parameter value"; break;
+ case 105: str = "Unexpected parameter value"; break;
+ case 106: str = "User Data size error"; break;
+ case 107: str = "Other general problems"; break;
+ case 108: str = "Session not active"; break;
+ default:
+ if ((oct >= 7) && (oct <= 31)) { str = "Reserved, treat as Other network problem"; }
+ else if ((oct >= 40) && (oct <= 47)) { str = "Reserved, treat as Other terminal problem"; }
+ else if ((oct >= 48) && (oct <= 63)) { str = "Reserved, treat as SMS delivery postponed"; }
+ else if ((oct >= 68) && (oct <= 95)) { str = "Reserved, treat as Other radio interface problem"; }
+ else if ((oct >= 109) && (oct <= 223)) { str = "Reserved, treat as Other general problems"; }
+ else { str = "Reserved for protocol extension, treat as Other general problems"; }
+ break;
+ }
+
+ proto_tree_add_text(tree, tvb, offset, 1,
+ str);
+}
+
+static void
+trans_param_bearer_data(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string)
+{
+ tvbuff_t *tele_tvb;
+
+ add_string = add_string;
+
+ proto_tree_add_text(tree, tvb, offset, len,
+ "Bearer Data");
+
+ /*
+ * dissect the embedded teleservice data
+ */
+ tele_tvb = tvb_new_subset(tvb, offset, len, len);
+
+ dissector_try_port(tele_dissector_table, ansi_637_trans_tele_id,
+ tele_tvb, g_pinfo, g_tree);
+}
+
+#define NUM_TRANS_PARAM (sizeof(ansi_trans_param_strings)/sizeof(value_string))
+static gint ett_ansi_637_trans_param[NUM_TRANS_PARAM];
+static void (*ansi_637_trans_param_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string) = {
+ trans_param_tele_id, /* Teleservice Identifier */
+ trans_param_srvc_cat, /* Service Category */
+ trans_param_address, /* Originating Address */
+ trans_param_subaddress, /* Originating Subaddress */
+ trans_param_address, /* Destination Address */
+ trans_param_subaddress, /* Destination Subaddress */
+ trans_param_bearer_reply_opt, /* Bearer Reply Option */
+ trans_param_cause_codes, /* Cause Codes */
+ trans_param_bearer_data, /* Bearer Data */
+ NULL, /* NONE */
+};
+
+#define NUM_TRANS_MSG_TYPE (sizeof(ansi_trans_msg_type_strings)/sizeof(value_string))
+static gint ett_ansi_637_trans_msg[NUM_TRANS_MSG_TYPE];
+
+/* GENERIC IS-637 DISSECTOR FUNCTIONS */
+
+static gboolean
+dissect_ansi_637_tele_param(tvbuff_t *tvb, proto_tree *tree, guint32 *offset)
+{
+ void (*param_fcn)(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = NULL;
+ guint8 oct;
+ guint8 len;
+ guint32 curr_offset;
+ gint ett_param_idx, idx;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str = NULL;
+
+
+ curr_offset = *offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+ str = my_match_strval((guint32) oct, ansi_tele_param_strings, &idx);
+
+ if (NULL == str)
+ {
+ return(FALSE);
+ }
+
+ ett_param_idx = ett_ansi_637_tele_param[idx];
+ param_fcn = ansi_637_tele_param_fcn[idx];
+
+ item =
+ proto_tree_add_text(tree, tvb, curr_offset, -1, str);
+
+ subtree = proto_item_add_subtree(item, ett_param_idx);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_tele_subparam_id,
+ tvb, curr_offset, 1, oct);
+
+ curr_offset++;
+
+ len = tvb_get_guint8(tvb, curr_offset);
+
+ proto_item_set_len(item, (curr_offset - *offset) + len + 1);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_length,
+ tvb, curr_offset, 1, len);
+
+ curr_offset++;
+
+ if (len > 0)
+ {
+ if (param_fcn == NULL)
+ {
+ proto_tree_add_text(subtree, tvb, curr_offset,
+ len, "Parameter Data");
+ }
+ else
+ {
+ (*param_fcn)(tvb, subtree, len, curr_offset);
+ }
+
+ curr_offset += len;
+ }
+
+ *offset = curr_offset;
+
+ return(TRUE);
+}
+
+static void
+dissect_ansi_637_tele_message(tvbuff_t *tvb, proto_tree *ansi_637_tree)
+{
+ guint8 oct;
+ guint8 len;
+ guint32 octs;
+ guint32 curr_offset;
+ guint32 msg_id;
+ guint32 msg_type;
+ gchar *str = NULL;
+ proto_item *item;
+ proto_tree *subtree;
+
+
+ oct = tvb_get_guint8(tvb, 0);
+ if (oct != 0x00)
+ {
+ return;
+ }
+
+ len = tvb_get_guint8(tvb, 1);
+ if (len != 3)
+ {
+ return;
+ }
+
+ octs = tvb_get_ntoh24(tvb, 2);
+ msg_type = (octs >> 20) & 0x0f;
+ msg_id = (octs >> 4) & 0xffff;
+
+ str = match_strval(msg_type, ansi_tele_msg_type_strings);
+
+ /*
+ * do not append to COL_INFO
+ */
+
+ item =
+ proto_tree_add_none_format(ansi_637_tree, hf_ansi_637_none,
+ tvb, 0, -1, str);
+
+ subtree = proto_item_add_subtree(item, ett_params);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_tele_subparam_id,
+ tvb, 0, 1, oct);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_length,
+ tvb, 1, 1, len);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_tele_msg_type,
+ tvb, 2, 3, octs);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_tele_msg_id,
+ tvb, 2, 3, octs);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_tele_msg_rsvd,
+ tvb, 2, 3, octs);
+
+ proto_item_set_len(item, 2 + len);
+
+ curr_offset = 2 + len;
+ len = tvb_length(tvb);
+
+ while ((len - curr_offset) > 0)
+ {
+ if (!dissect_ansi_637_tele_param(tvb, ansi_637_tree, &curr_offset))
+ {
+ proto_tree_add_text(ansi_637_tree, tvb, curr_offset, len - curr_offset,
+ "Unknown Parameter Data");
+ break;
+ }
+ }
+}
+
+static void
+dissect_ansi_637_tele(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ansi_637_item;
+ proto_tree *ansi_637_tree = NULL;
+ gchar *str = NULL;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ {
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, ansi_proto_name_short);
+ }
+
+ /* In the interest of speed, if "tree" is NULL, don't do any work not
+ * necessary to generate protocol tree items.
+ */
+ if (tree)
+ {
+ /*
+ * create the ansi_637 protocol tree
+ */
+ str = match_strval(pinfo->match_port, ansi_tele_id_strings);
+
+ if (NULL == str) str = "Unrecognized Teleservice ID";
+
+ ansi_637_item =
+ proto_tree_add_protocol_format(tree, proto_ansi_637_tele, tvb, 0, -1,
+ "%s - %s (%d)",
+ ansi_proto_name_tele,
+ str,
+ pinfo->match_port);
+
+ ansi_637_tree =
+ proto_item_add_subtree(ansi_637_item, ett_ansi_637_tele);
+
+ dissect_ansi_637_tele_message(tvb, ansi_637_tree);
+ }
+}
+
+static gboolean
+dissect_ansi_637_trans_param(tvbuff_t *tvb, proto_tree *tree, guint32 *offset)
+{
+ void (*param_fcn)(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset, gchar *add_string) = NULL;
+ guint8 oct;
+ guint8 len;
+ guint32 curr_offset;
+ gint ett_param_idx, idx;
+ proto_tree *subtree;
+ proto_item *item;
+ gchar *str = NULL;
+
+ curr_offset = *offset;
+
+ oct = tvb_get_guint8(tvb, curr_offset);
+ str = my_match_strval((guint32) oct, ansi_trans_param_strings, &idx);
+
+ if (NULL == str)
+ {
+ return(FALSE);
+ }
+
+ ett_param_idx = ett_ansi_637_trans_param[idx];
+ param_fcn = ansi_637_trans_param_fcn[idx];
+
+ item =
+ proto_tree_add_text(tree, tvb, curr_offset, -1, str);
+
+ subtree = proto_item_add_subtree(item, ett_param_idx);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_trans_param_id,
+ tvb, curr_offset, 1, oct);
+
+ curr_offset++;
+
+ len = tvb_get_guint8(tvb, curr_offset);
+
+ proto_item_set_len(item, (curr_offset - *offset) + len + 1);
+
+ proto_tree_add_uint(subtree, hf_ansi_637_length,
+ tvb, curr_offset, 1, len);
+
+ curr_offset++;
+
+ if (len > 0)
+ {
+ if (param_fcn == NULL)
+ {
+ proto_tree_add_text(subtree, tvb, curr_offset,
+ len, "Parameter Data");
+ }
+ else
+ {
+ ansi_637_add_string[0] = '\0';
+ (*param_fcn)(tvb, subtree, len, curr_offset, ansi_637_add_string);
+
+ if (ansi_637_add_string[0] != '\0')
+ {
+ proto_item_append_text(item, ansi_637_add_string);
+ }
+ }
+
+ curr_offset += len;
+ }
+
+ *offset = curr_offset;
+
+ return(TRUE);
+}
+
+static void
+dissect_ansi_637_trans(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ansi_637_item;
+ proto_tree *ansi_637_tree = NULL;
+ guint32 curr_offset;
+ gint idx;
+ gchar *str = NULL;
+ guint8 oct;
+ guint8 len;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ {
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, ansi_proto_name_short);
+ }
+
+ /* In the interest of speed, if "tree" is NULL, don't do any work not
+ * necessary to generate protocol tree items.
+ */
+ if (tree)
+ {
+ g_pinfo = pinfo;
+ g_tree = tree;
+
+ /*
+ * create the ansi_637 protocol tree
+ */
+ oct = tvb_get_guint8(tvb, 0);
+
+ str = my_match_strval(oct, ansi_trans_msg_type_strings, &idx);
+
+ if (NULL == str)
+ {
+ ansi_637_item =
+ proto_tree_add_protocol_format(tree, proto_ansi_637_trans, tvb, 0, -1,
+ "%s - Unrecognized Transport Layer Message Type (%d)",
+ ansi_proto_name_trans,
+ oct);
+
+ ansi_637_tree =
+ proto_item_add_subtree(ansi_637_item, ett_ansi_637_trans);
+ }
+ else
+ {
+ ansi_637_item =
+ proto_tree_add_protocol_format(tree, proto_ansi_637_trans, tvb, 0, -1,
+ "%s - %s",
+ ansi_proto_name_trans,
+ str);
+
+ ansi_637_tree =
+ proto_item_add_subtree(ansi_637_item, ett_ansi_637_trans_msg[idx]);
+ }
+
+ curr_offset = 1;
+
+ len = tvb_length(tvb);
+
+ while ((len - curr_offset) > 0)
+ {
+ if (!dissect_ansi_637_trans_param(tvb, ansi_637_tree, &curr_offset))
+ {
+ proto_tree_add_text(ansi_637_tree, tvb, curr_offset, len - curr_offset,
+ "Unknown Parameter Data");
+ break;
+ }
+ }
+ }
+}
+
+/* Register the protocol with Ethereal */
+void
+proto_register_ansi_637(void)
+{
+ guint i;
+
+ /* Setup list of header fields */
+ static hf_register_info hf[] =
+ {
+ { &hf_ansi_637_trans_msg_type,
+ { "Message Type",
+ "ansi_637.trans_msg_type",
+ FT_UINT24, BASE_DEC, VALS(ansi_trans_msg_type_strings), 0xf00000,
+ "", HFILL }},
+ { &hf_ansi_637_tele_msg_type,
+ { "Message Type",
+ "ansi_637.tele_msg_type",
+ FT_UINT24, BASE_DEC, VALS(ansi_tele_msg_type_strings), 0xf00000,
+ "", HFILL }},
+ { &hf_ansi_637_tele_msg_id,
+ { "Message ID",
+ "ansi_637.tele_msg_id",
+ FT_UINT24, BASE_DEC, NULL, 0x0ffff0,
+ "", HFILL }},
+ { &hf_ansi_637_tele_msg_rsvd,
+ { "Reserved",
+ "ansi_637.tele_msg_rsvd",
+ FT_UINT24, BASE_DEC, NULL, 0x00000f,
+ "", HFILL }},
+ { &hf_ansi_637_length,
+ { "Length", "ansi_637.len",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "", HFILL }
+ },
+ { &hf_ansi_637_none,
+ { "Sub tree", "ansi_637.none",
+ FT_NONE, 0, 0, 0,
+ "", HFILL }
+ },
+ { &hf_ansi_637_tele_subparam_id,
+ { "Teleservice Subparam ID", "ansi_637.tele_subparam_id",
+ FT_UINT8, BASE_DEC, VALS(ansi_tele_param_strings), 0,
+ "", HFILL }
+ },
+ { &hf_ansi_637_trans_param_id,
+ { "Transport Param ID", "ansi_637.trans_param_id",
+ FT_UINT8, BASE_DEC, VALS(ansi_trans_param_strings), 0,
+ "", HFILL }
+ },
+ { &hf_ansi_637_bin_addr,
+ { "Binary Address", "ansi_637.bin_addr",
+ FT_BYTES, BASE_HEX, 0, 0,
+ "", HFILL }
+ },
+ };
+
+ /* Setup protocol subtree array */
+#define NUM_INDIVIDUAL_PARAMS 3
+ static gint *ett[NUM_INDIVIDUAL_PARAMS+NUM_TELE_PARAM+NUM_TRANS_MSG_TYPE+NUM_TRANS_PARAM];
+
+ memset((void *) ett, 0, sizeof(ett));
+
+ ett[0] = &ett_ansi_637_tele;
+ ett[1] = &ett_ansi_637_trans;
+ ett[2] = &ett_params;
+
+ for (i=0; i < NUM_TELE_PARAM; i++)
+ {
+ ett_ansi_637_tele_param[i] = -1;
+ ett[NUM_INDIVIDUAL_PARAMS+i] = &ett_ansi_637_tele_param[i];
+ }
+
+ for (i=0; i < NUM_TRANS_MSG_TYPE; i++)
+ {
+ ett_ansi_637_trans_msg[i] = -1;
+ ett[NUM_INDIVIDUAL_PARAMS+NUM_TELE_PARAM+i] = &ett_ansi_637_trans_msg[i];
+ }
+
+ for (i=0; i < NUM_TRANS_PARAM; i++)
+ {
+ ett_ansi_637_trans_param[i] = -1;
+ ett[NUM_INDIVIDUAL_PARAMS+NUM_TELE_PARAM+NUM_TRANS_MSG_TYPE+i] = &ett_ansi_637_trans_param[i];
+ }
+
+ /* Register the protocol name and description */
+ proto_ansi_637_tele =
+ proto_register_protocol(ansi_proto_name_tele, "ANSI IS-637-A Teleservice", "ansi_637_tele");
+
+ proto_ansi_637_trans =
+ proto_register_protocol(ansi_proto_name_trans, "ANSI IS-637-A Transport", "ansi_637_trans");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_ansi_637_tele, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ tele_dissector_table =
+ register_dissector_table("ansi_637.tele_id",
+ "ANSI IS-637-A Teleservice ID", FT_UINT8, BASE_DEC);
+}
+
+
+void
+proto_reg_handoff_ansi_637(void)
+{
+ dissector_handle_t ansi_637_tele_handle;
+ dissector_handle_t ansi_637_trans_handle;
+ guint i;
+
+ ansi_637_tele_handle = create_dissector_handle(dissect_ansi_637_tele, proto_ansi_637_tele);
+ ansi_637_trans_handle = create_dissector_handle(dissect_ansi_637_trans, proto_ansi_637_trans);
+
+ /*
+ * register for all known teleservices
+ * '-1' is to stop before trailing '0' entry
+ *
+ * to add teleservices, modify 'ansi_tele_id_strings'
+ */
+ for (i=0; i < ((sizeof(ansi_tele_id_strings)/sizeof(value_string))-1); i++)
+ {
+ /*
+ * ANSI MAP dissector will push out teleservice ids
+ */
+ dissector_add("ansi_map.tele_id", ansi_tele_id_strings[i].value, ansi_637_tele_handle);
+
+ /*
+ * we will push out teleservice ids after Transport layer decode
+ */
+ dissector_add("ansi_637.tele_id", ansi_tele_id_strings[i].value, ansi_637_tele_handle);
+ }
+
+ /*
+ * ANSI A-interface will push out transport layer data
+ */
+ dissector_add("ansi_a.sms", 0, ansi_637_trans_handle);
+
+ data_handle = find_dissector("data");
+}