summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2004-06-25 06:31:47 +0000
committerRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2004-06-25 06:31:47 +0000
commite790073f3afed22dc5084a37424e35ab14412400 (patch)
tree36855bb500d4767eafc7fe1005940384af79f4f5
parent79d7a7cba6f8c81803ed818df68791b9ad643280 (diff)
downloadwireshark-e790073f3afed22dc5084a37424e35ab14412400.tar.gz
Updates from Richard v d Hoff
IAX2 updates and a CRC16 routine svn path=/trunk/; revision=11233
-rw-r--r--AUTHORS4
-rw-r--r--crc16.c152
-rw-r--r--crc16.h39
-rw-r--r--epan/packet_info.h5
-rw-r--r--iax2_codec_type.h77
-rw-r--r--packet-h263.c7
-rw-r--r--packet-iax2.c1638
-rw-r--r--packet-iax2.h22
8 files changed, 1676 insertions, 268 deletions
diff --git a/AUTHORS b/AUTHORS
index 3feff9f26e..ec35afd112 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2144,6 +2144,10 @@ Dominic Béchaz <bdo [AT] zhwin.ch> {
IEEE 1588 / PTP support
}
+Richard van der Hoff <richardv [AT] mxtelecom.com> {
+ IAX2 updates
+ CRC16 routines
+}
And assorted fixes and enhancements by the people listed above and by:
diff --git a/crc16.c b/crc16.c
new file mode 100644
index 0000000000..7cf8553265
--- /dev/null
+++ b/crc16.c
@@ -0,0 +1,152 @@
+/* crc16.c
+ * CRC-16 routine
+ *
+ * 2004 Richard van der Hoff <richardv@mxtelecom.com>
+ *
+ * $Id: crc16.c,v 1.1 2004/06/25 06:31:46 sahlberg Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxxxxxx>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from README.developer
+ *
+ * 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.
+ *
+ * References:
+ * "A Painless Guide to CRC Error Detection Algorithms", Ross Williams
+ * http://www.repairfaq.org/filipg/LINK/F_crc_v3.html
+ *
+ * ITU-T Recommendation V.42 (2002), "Error-Correcting Procedures for
+ * DCEs using asynchronous-to-synchronous conversion", Para. 8.1.1.6.1
+ */
+
+#include <glib.h>
+#include <epan/tvbuff.h>
+#include "crc16.h"
+
+
+/*****************************************************************/
+
+/*
+ * Table for the CCITT/ITU/CRC-16 16-bit CRC
+ *
+ * Polynomial is
+ *
+ * x^16 + x^12 + x^5 + 1
+ */
+
+/* */
+/* CRC LOOKUP TABLE */
+/* ================ */
+/* The following CRC lookup table was generated automagically */
+/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
+/* Program V1.0 using the following model parameters: */
+/* */
+/* Width : 2 bytes. */
+/* Poly : 0x1021 */
+/* Reverse : TRUE. */
+/* */
+/* For more information on the Rocksoft^tm Model CRC Algorithm, */
+/* see the document titled "A Painless Guide to CRC Error */
+/* Detection Algorithms" by Ross Williams */
+/* (ross@xxxxxxxxxxxxxxxxxxxxxx). This document is likely to be */
+/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
+/* */
+/*****************************************************************/
+
+guint crc16_ccitt_table[256] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
+ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
+ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
+ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
+ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
+ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
+ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
+ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
+ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
+ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
+ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
+ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
+ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
+ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
+ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
+ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
+ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
+ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
+ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
+ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
+ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
+ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
+ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
+ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
+ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
+ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
+ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
+ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
+ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
+ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
+ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
+ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
+};
+
+static const guint16 crc16_ccitt_start = 0xFFFF;
+static const guint16 crc16_ccitt_xorout = 0xFFFF;
+
+/* two types of crcs are possible: unreflected (bits shift left) and
+ * reflected (bits shift right).
+ */
+#if 0
+static guint16 crc16_unreflected(const unsigned char *buf, guint len,
+ guint16 crc_in, const guint table[])
+{
+ /* we use guints, rather than guint16s, as they are likely to be
+ faster. We just ignore the top 16 bits and let them do what they want. */
+ guint crc16 = (guint)crc_in;;
+
+ while( len-- > 0 )
+ crc16 = table[(crc16 ^ *buf++) & 0xff] ^ (crc16 << 8);
+
+ return (guint16)crc16;
+}
+#endif
+
+static guint16 crc16_reflected(const unsigned char *buf, guint len,
+ guint16 crc_in, const guint table[])
+{
+ /* we use guints, rather than guint16s, as they are likely to be
+ faster. We just ignore the top 16 bits and let them do what they want. */
+ guint crc16 = (guint)crc_in;;
+
+ while( len-- > 0 )
+ crc16 = table[(crc16 ^ *buf++) & 0xff] ^ (crc16 >> 8);
+
+ return (guint16)crc16;
+}
+
+
+guint16 crc16_ccitt(const unsigned char *buf, guint len)
+{
+ return crc16_reflected(buf,len,crc16_ccitt_start,crc16_ccitt_table)
+ ^ crc16_ccitt_xorout;
+}
+
+guint16 crc16_ccitt_tvb(tvbuff_t *tvb, unsigned int len)
+{
+ const unsigned char* buf = tvb_get_ptr(tvb, 0, len);
+
+ return crc16_ccitt(buf, len);
+}
diff --git a/crc16.h b/crc16.h
new file mode 100644
index 0000000000..237974e18b
--- /dev/null
+++ b/crc16.h
@@ -0,0 +1,39 @@
+/* crc16.h
+ * Declaration of CRC-16 routines and table
+ *
+ * 2004 Richard van der Hoff <richardv@mxtelecom.com>
+ *
+ * $Id: crc16.h,v 1.1 2004/06/25 06:31:46 sahlberg Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxxxxxx>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from README.developer
+ *
+ * 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.
+*/
+
+/* Calculate the CCITT/ITU/CRC-16 16-bit CRC
+
+ (parameters for this CRC are:
+ Polynomial: x^16 + x^12 + x^5 + 1 (0x1021);
+ Start value 0xFFFF;
+ XOR result with 0xFFFF;
+ First bit is LSB)
+*/
+extern guint16 crc16_ccitt(const unsigned char *buf, guint len);
+extern guint16 crc16_ccitt_tvb(tvbuff_t *tvb, unsigned int len);
+
diff --git a/epan/packet_info.h b/epan/packet_info.h
index 41eb393675..d0f4321342 100644
--- a/epan/packet_info.h
+++ b/epan/packet_info.h
@@ -1,7 +1,7 @@
/* packet_info.h
* Definitions for packet info structures and routines
*
- * $Id: packet_info.h,v 1.40 2004/03/23 01:02:40 guy Exp $
+ * $Id: packet_info.h,v 1.41 2004/06/25 06:31:47 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -121,7 +121,8 @@ typedef enum {
CT_DLCI, /* Frame Relay DLCI */
CT_ISDN, /* ISDN channel number */
CT_X25, /* X.25 logical channel number */
- CT_ISUP /* ISDN User Part CIC */
+ CT_ISUP, /* ISDN User Part CIC */
+ CT_IAX2 /* IAX2 call id */
/* Could also have ATM VPI/VCI pairs */
} circuit_type;
diff --git a/iax2_codec_type.h b/iax2_codec_type.h
new file mode 100644
index 0000000000..460b6e5bc1
--- /dev/null
+++ b/iax2_codec_type.h
@@ -0,0 +1,77 @@
+/* iax2_codec_type.h
+ * Defines IAX2 codec types
+ *
+ * $Id: iax2_codec_type.h,v 1.1 2004/06/25 06:31:46 sahlberg Exp $
+ *
+ * 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.
+ */
+
+#ifndef __IAX2_CODEC_TYPE_H__
+#define __IAX2_CODEC_TYPE_H__
+
+
+/* Ref: frame.h from Asterisk source */
+
+/* Data formats for capabilities and frames alike */
+/* suitable for use in iax2.codec dissector table */
+/*! G.723.1 compression */
+#define AST_FORMAT_G723_1 (1 << 0)
+/*! GSM compression */
+#define AST_FORMAT_GSM (1 << 1)
+/*! Raw mu-law data (G.711) */
+#define AST_FORMAT_ULAW (1 << 2)
+/*! Raw A-law data (G.711) */
+#define AST_FORMAT_ALAW (1 << 3)
+/*! ADPCM (G.726, 32kbps) */
+#define AST_FORMAT_G726 (1 << 4)
+/*! ADPCM (IMA) */
+#define AST_FORMAT_ADPCM (1 << 5)
+/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+#define AST_FORMAT_SLINEAR (1 << 6)
+/*! LPC10, 180 samples/frame */
+#define AST_FORMAT_LPC10 (1 << 7)
+/*! G.729A audio */
+#define AST_FORMAT_G729A (1 << 8)
+/*! SpeeX Free Compression */
+#define AST_FORMAT_SPEEX (1 << 9)
+/*! iLBC Free Compression */
+#define AST_FORMAT_ILBC (1 << 10)
+/*! Maximum audio format */
+#define AST_FORMAT_MAX_AUDIO (1 << 15)
+/*! JPEG Images */
+#define AST_FORMAT_JPEG (1 << 16)
+/*! PNG Images */
+#define AST_FORMAT_PNG (1 << 17)
+/*! H.261 Video */
+#define AST_FORMAT_H261 (1 << 18)
+/*! H.263 Video */
+#define AST_FORMAT_H263 (1 << 19)
+/*! Max one */
+#define AST_FORMAT_MAX_VIDEO (1 << 24)
+
+
+/* data format for IAX_IE_DATAFORMAT ie */
+/* suitable for use in iax2.dataformat dissector table */
+typedef enum {
+ AST_DATAFORMAT_NULL, /* N/A: analogue call etc */
+ AST_DATAFORMAT_V110, /* ITU-T V.110 rate adaption */
+ AST_DATAFORMAT_H223_H245 /* ITU-T H.223/H.245 */
+} iax_dataformat_t;
+
+#endif
diff --git a/packet-h263.c b/packet-h263.c
index 621f7133e3..820bcdbbc9 100644
--- a/packet-h263.c
+++ b/packet-h263.c
@@ -5,7 +5,7 @@
* Copyright 2003 Niklas Ögren <niklas.ogren@7l.se>
* Seven Levels Consultants AB
*
- * $Id: packet-h263.c,v 1.4 2003/08/25 21:48:44 guy Exp $
+ * $Id: packet-h263.c,v 1.5 2004/06/25 06:31:46 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -45,6 +45,7 @@
#include <string.h>
#include "rtp_pt.h"
+#include "iax2_codec_type.h"
/* H.263 header fields */
static int proto_h263 = -1;
@@ -526,6 +527,7 @@ proto_register_h263(void)
"H.263", "h263");
proto_register_field_array(proto_h263, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+ register_dissector("h263", dissect_h263, proto_h263);
}
void
@@ -533,6 +535,7 @@ proto_reg_handoff_h263(void)
{
dissector_handle_t h263_handle;
- h263_handle = create_dissector_handle(dissect_h263, proto_h263);
+ h263_handle = find_dissector("h263");
dissector_add("rtp.pt", PT_H263, h263_handle);
+ dissector_add("iax2.codec", AST_FORMAT_H263, h263_handle);
}
diff --git a/packet-iax2.c b/packet-iax2.c
index 189df6b675..7db74f8776 100644
--- a/packet-iax2.c
+++ b/packet-iax2.c
@@ -8,7 +8,7 @@
* IAX2 is a VoIP protocol for the open source PBX Asterisk. Please see
* http://www.asterisk.org for more information.
*
- * $Id: packet-iax2.c,v 1.6 2004/05/15 21:26:09 guy Exp $
+ * $Id: packet-iax2.c,v 1.7 2004/06/25 06:31:46 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -34,21 +34,34 @@
#include <stdio.h>
#include <string.h>
#include <glib.h>
+
+#include <epan/circuit.h>
#include <epan/packet.h>
+#include <epan/to_str.h>
#include "packet-iax2.h"
+#include "iax2_codec_type.h"
#define IAX2_PORT 4569
#define PROTO_TAG_IAX2 "IAX2"
+/* #define DEBUG_HASHING */
+
+/* Ethereal ID of the IAX2 protocol */
static int proto_iax2 = -1;
+/* The following hf_* variables are used to hold the ethereal IDs of
+ * our header fields; they are filled out when we call
+ * proto_register_field_array() in proto_register_iax2()
+ */
+static int hf_iax2_packet_type = -1;
static int hf_iax2_retransmission = -1;
static int hf_iax2_scallno = -1;
static int hf_iax2_dcallno = -1;
static int hf_iax2_ts = -1;
static int hf_iax2_minits = -1;
-static int hf_iax2_voicedata = -1;
+static int hf_iax2_minividts = -1;
+static int hf_iax2_minividmarker = -1;
static int hf_iax2_oseqno = -1;
static int hf_iax2_iseqno = -1;
static int hf_iax2_type = -1;
@@ -56,7 +69,26 @@ static int hf_iax2_csub = -1;
static int hf_iax2_cmd_csub = -1;
static int hf_iax2_iax_csub = -1;
static int hf_iax2_voice_csub = -1;
-static int hf_iax2_ies = -1;
+static int hf_iax2_voice_codec = -1;
+static int hf_iax2_video_csub = -1;
+static int hf_iax2_video_codec = -1;
+static int hf_iax2_marker = -1;
+
+static int hf_iax2_cap_g723_1 = -1;
+static int hf_iax2_cap_gsm = -1;
+static int hf_iax2_cap_ulaw = -1;
+static int hf_iax2_cap_alaw = -1;
+static int hf_iax2_cap_g726 = -1;
+static int hf_iax2_cap_adpcm = -1;
+static int hf_iax2_cap_slinear = -1;
+static int hf_iax2_cap_lpc10 = -1;
+static int hf_iax2_cap_g729a = -1;
+static int hf_iax2_cap_speex = -1;
+static int hf_iax2_cap_ilbc = -1;
+static int hf_iax2_cap_jpeg = -1;
+static int hf_iax2_cap_png = -1;
+static int hf_iax2_cap_h261 = -1;
+static int hf_iax2_cap_h263 = -1;
static int hf_IAX_IE_APPARENTADDR_SINFAMILY = -1;
static int hf_IAX_IE_APPARENTADDR_SINPORT = -1;
@@ -89,14 +121,28 @@ static int hf_IAX_IE_AUTOANSWER = -1;
static int hf_IAX_IE_MUSICONHOLD = -1;
static int hf_IAX_IE_TRANSFERID = -1;
static int hf_IAX_IE_RDNIS = -1;
+static int hf_IAX_IE_DATAFORMAT = -1;
+static int hf_IAX_IE_UNKNOWN_BYTE = -1;
+static int hf_IAX_IE_UNKNOWN_I16 = -1;
+static int hf_IAX_IE_UNKNOWN_I32 = -1;
+static int hf_IAX_IE_UNKNOWN_BYTES = -1;
+/* These are the ids of the subtrees that we may be creating */
+static gint ett_iax2 = -1;
+static gint ett_iax2_full_mini_subtree = -1;
+static gint ett_iax2_type = -1; /* Frame-type specific subtree */
+static gint ett_iax2_ie = -1; /* single IE */
+static gint ett_iax2_codecs = -1; /* capabilities IE */
+static gint ett_iax2_ies_apparent_addr = -1; /* apparent address IE */
+static dissector_handle_t data_handle;
-static gint ett_iax2 = -1;
-static gint ett_iax2_ies = -1;
-static gint ett_iax2_codecs = -1;
-static gint ett_iax2_ies_apparent_addr = -1;
+/* data-call subdissectors, AST_DATAFORMAT_* */
+static dissector_table_t iax2_dataformat_dissector_table;
+/* voice/video call subdissectors, AST_FORMAT_* */
+static dissector_table_t iax2_codec_dissector_table;
+/* IAX2 Full-frame types */
static const value_string iax_frame_types[] = {
{0, "(0?)"},
{1, "DTMF"},
@@ -106,8 +152,11 @@ static const value_string iax_frame_types[] = {
{5, "NULL"},
{6, "IAX"},
{7, "Text"},
- {8, "Image"}
+ {8, "Image"},
+ {0,NULL}
};
+
+/* Subclasses for IAX packets */
static const value_string iax_iax_subclasses[] = {
{0, "(0?)"},
{1, "NEW"},
@@ -143,8 +192,11 @@ static const value_string iax_iax_subclasses[] = {
{31, "PAGE"},
{32, "MWI"},
{33, "UNSUPPORTED"},
- {34, "TRANSFER"}
+ {34, "TRANSFER"},
+ {0,NULL}
};
+
+/* Subclassess for Control packets */
static const value_string iax_cmd_subclasses[] = {
{0, "(0?)"},
{1, "HANGUP"},
@@ -153,9 +205,12 @@ static const value_string iax_cmd_subclasses[] = {
{4, "ANSWER"},
{5, "BUSY"},
{6, "TKOFFHK"},
- {7, "OFFHOOK"}
+ {7, "OFFHOOK"},
+ {0xFF, "stop sounds"}, /* sent by app_dial, and not much else */
+ {0,NULL}
};
+/* Information elements */
static const value_string iax_ies_type[] = {
{IAX_IE_CALLED_NUMBER, "Number/extension being called"},
{IAX_IE_CALLING_NUMBER, "Calling number"},
@@ -184,7 +239,12 @@ static const value_string iax_ies_type[] = {
{IAX_IE_AUTOANSWER, "Request auto-answering"},
{IAX_IE_MUSICONHOLD, "Request musiconhold with QUELCH"},
{IAX_IE_TRANSFERID, "Transfer Request Identifier"},
- {IAX_IE_RDNIS, "Referring DNIS"}
+ {IAX_IE_RDNIS, "Referring DNIS"},
+ {IAX_IE_PROVISIONING, "Provisioning info"},
+ {IAX_IE_AESPROVISIONING, "AES Provisioning info"},
+ {IAX_IE_DATETIME,"Date/Time"},
+ {IAX_IE_DATAFORMAT, "Data call format"},
+ {0,NULL}
};
static const value_string codec_types[] = {
@@ -202,21 +262,547 @@ static const value_string codec_types[] = {
{AST_FORMAT_JPEG, "JPEG Images"},
{AST_FORMAT_PNG, "PNG Images"},
{AST_FORMAT_H261, "H.261 Video"},
- {AST_FORMAT_H263, "H.263 Video"}
+ {AST_FORMAT_H263, "H.263 Video"},
+ {0,NULL}
+};
+
+static const value_string iax_dataformats[] = {
+ {AST_DATAFORMAT_NULL, "N/A (analogue call?)"},
+ {AST_DATAFORMAT_V110, "ITU-T V.110 rate adaption"},
+ {AST_DATAFORMAT_H223_H245,"ITU-T H.223/H.245"},
+ {0,NULL}
+};
+
+typedef enum {
+ IAX2_MINI_VOICE_PACKET,
+ IAX2_FULL_PACKET,
+ IAX2_MINI_VIDEO_PACKET,
+ IAX2_META_PACKET
+} packet_type;
+
+static const value_string iax_packet_types[] = {
+ {IAX2_FULL_PACKET, "Full packet"},
+ {IAX2_MINI_VOICE_PACKET, "Mini voice packet"},
+ {IAX2_MINI_VIDEO_PACKET, "Mini video packet"},
+ {IAX2_META_PACKET, "Meta packet"},
+ {0,NULL}
};
+
+
+/* ************************************************************************* */
+
+/* In order to track IAX calls, we have a hash table which maps
+ * {addr,port type,port,call} to a unique circuit id.
+ *
+ * Each call has two such circuits associated with it (a forward and a
+ * reverse circuit, where 'forward' is defined as the direction the NEW
+ * packet went in), and we maintain an iax_call_data structure for each
+ * call, attached to both circuits with circuit_add_proto_data.
+ *
+ * Because {addr,port type,port,call} quadruplets can be reused
+ * (Asterisk reuses call numbers), circuit ids aren't unique to
+ * individual calls and we treat NEW packets somewhat specially. When we
+ * get such a packet, we see if there are any calls with a matching
+ * circuit id, and make sure that its circuits are marked as ended
+ * before that packet.
+ *
+ * A second complication is that we only know one quadruplet at the time
+ * the NEW packet is processed: there is therefore cunningness in
+ * iax_lookup_circuit_details() to look for replies to NEW packets and
+ * create the reverse circuit.
+ */
+
+
+/* start with a hash of {addr,port type,port,call}->{id} */
+
+typedef struct {
+ address addr;
+ port_type ptype;
+ guint32 port;
+ guint32 callno;
+} iax_circuit_key;
+
+/* tables */
+static GHashTable *iax_circuit_hashtab = NULL;
+static GMemChunk *iax_circuit_keys = NULL;
+static GMemChunk *iax_circuit_vals = NULL;
+static guint circuitcount = 0;
+
+/* the number of keys and values to reserve space for in each memory chunk.
+ We assume we won't be tracking many calls at once so this is quite low.
+*/
+#define IAX_INIT_PACKET_COUNT 10
+
+#ifdef DEBUG_HASHING
+static gchar *key_to_str( const iax_circuit_key *key )
+{
+ static int i=0;
+ static gchar *strp, str[3][80];
+
+ i++;
+ if(i>=3){
+ i=0;
+ }
+ strp=str[i];
+
+ /* why doesn't address_to_str take a const pointer?
+ cast the warnings into oblivion. */
+
+ sprintf(strp,"{%s:%i,%i}",
+ address_to_str((address *)&key->addr),
+ key->port,
+ key->callno);
+ return strp;
+}
+#endif
+
+/* Hash Functions */
+static gint iax_circuit_equal(gconstpointer v, gconstpointer w)
+{
+ const iax_circuit_key *v1 = (const iax_circuit_key *)v;
+ const iax_circuit_key *v2 = (const iax_circuit_key *)w;
+ gint result;
+
+ result = ( ADDRESSES_EQUAL(&(v1->addr), &(v2->addr)) &&
+ v1->ptype == v2->ptype &&
+ v1->port == v2->port &&
+ v1->callno== v2->callno);
+#ifdef DEBUG_HASHING
+ g_message( "+++ Comparing for equality: %s, %s: %u",key_to_str(v1), key_to_str(v2), result);
+#endif
+
+ return result;;
+}
+
+static guint iax_circuit_hash (gconstpointer v)
+{
+ const iax_circuit_key *key = (const iax_circuit_key *)v;
+ guint hash_val;
+ int i;
+
+ hash_val = 0;
+ for (i = 0; i < key->addr.len; i++)
+ hash_val += (guint)(key->addr.data[i]);
+
+ hash_val += (guint)(key->ptype);
+ hash_val += (guint)(key->port);
+ hash_val += (guint)(key->callno);
+
+#ifdef DEBUG_HASHING
+ g_message( "+++ Hashing key: %s, result %#x", key_to_str(key), hash_val );
+#endif
+
+ return (guint) hash_val;
+}
+
+static guint iax_circuit_lookup(const address *address,
+ port_type ptype,
+ guint32 port,
+ guint32 callno)
+{
+ iax_circuit_key key;
+ guint32 *circuit_id_p;
+
+ key.addr = *address;
+ key.ptype = ptype;
+ key.port = port;
+ key.callno = callno;
+
+#ifdef DEBUG_HASHING
+ g_message( "+++ looking up key: %s", key_to_str(&key));
+#endif
+
+ circuit_id_p = g_hash_table_lookup( iax_circuit_hashtab, &key);
+ if( ! circuit_id_p ) {
+ iax_circuit_key *new_key;
+
+ new_key = g_mem_chunk_alloc(iax_circuit_keys);
+ COPY_ADDRESS(&new_key->addr, address);
+ new_key->ptype = ptype;
+ new_key->port = port;
+ new_key->callno = callno;
+
+ circuit_id_p = g_mem_chunk_alloc(iax_circuit_vals);
+ *circuit_id_p = ++circuitcount;
+
+ g_hash_table_insert(iax_circuit_hashtab, new_key, circuit_id_p);
+ }
+
+#ifdef DEBUG_HASHING
+ g_message( "+++ Id: %u", *circuit_id_p );
+#endif
+
+ return *circuit_id_p;
+}
+
+
+/* ************************************************************************* */
+
+
+/* This is our per-call data structure, which is attached to both the
+ * forward and reverse circuits.
+ */
+typedef struct iax_call_data {
+ /* For this data, src and dst are relative to the original direction under
+ which this call is stored. Obviously if the reversed flag is set true by
+ iax_find_call, src and dst are reversed relative to the direction the
+ actual source and destination of the data.
+
+ if the codec changes mid-call, we update it here; because we store a codec
+ number with each packet too, we handle going back to earlier packets
+ without problem.
+ */
+
+ iax_dataformat_t dataformat;
+ guint32 src_codec, dst_codec;
+ guint32 src_vformat, dst_vformat;
+
+ guint forward_circuit_id;
+ guint reverse_circuit_id;
+
+ guint callno;
+} iax_call_data;
+
+static guint callcount = 0;
+
+static GMemChunk *iax_call_datas = NULL;
+
+static void iax_init_hash( void )
+{
+ if (iax_circuit_hashtab)
+ g_hash_table_destroy(iax_circuit_hashtab);
+
+ if (iax_circuit_keys)
+ g_mem_chunk_destroy(iax_circuit_keys);
+ if (iax_circuit_vals)
+ g_mem_chunk_destroy(iax_circuit_vals);
+ if (iax_call_datas)
+ g_mem_chunk_destroy(iax_call_datas);
+
+ iax_circuit_hashtab = g_hash_table_new(iax_circuit_hash, iax_circuit_equal);
+
+ iax_circuit_keys = g_mem_chunk_create(iax_circuit_key,
+ 2*IAX_INIT_PACKET_COUNT,
+ G_ALLOC_ONLY);
+ iax_circuit_vals = g_mem_chunk_create(iax_circuit_key,
+ 2*IAX_INIT_PACKET_COUNT,
+ G_ALLOC_ONLY);
+
+ iax_call_datas = g_mem_chunk_create(iax_call_data,
+ IAX_INIT_PACKET_COUNT,
+ G_ALLOC_ONLY);
+ circuitcount = 0;
+ callcount = 0;
+}
+
+
+static iax_call_data *iax_lookup_circuit_details_from_dest( guint src_circuit_id,
+ guint dst_circuit_id,
+ guint framenum,
+ gboolean *reversed_p,
+ circuit_t **circuit_p)
+{
+ circuit_t *dst_circuit;
+ iax_call_data * iax_call;
+ gboolean reversed = FALSE;
+
+ dst_circuit = find_circuit( CT_IAX2,
+ dst_circuit_id,
+ framenum );
+
+ if( !dst_circuit ) {
+#ifdef DEBUG_HASHING
+ g_message( "++ destination circuit not found, must have missed NEW packet" );
+#endif
+ return NULL;
+ }
+
+#ifdef DEBUG_HASHING
+ g_message( "++ found destination circuit" );
+#endif
+
+ iax_call = (iax_call_data *)circuit_get_proto_data(dst_circuit,proto_iax2);
+
+ /* there's no way we can create a CT_IAX2 circuit without adding
+ iax call data to it; assert this */
+ g_assert(iax_call);
+
+ if( dst_circuit_id == iax_call -> forward_circuit_id ) {
+#ifdef DEBUG_HASHING
+ g_message( "++ destination circuit matches forward_circuit_id of call, "
+ "therefore packet is reversed" );
+#endif
+
+ reversed = TRUE;
+
+ if( iax_call -> reverse_circuit_id == 0 ) {
+ circuit_t *rev_circuit;
+
+ /* we are going in the reverse direction, and this call
+ doesn't have a reverse circuit associated with it.
+ create one now. */
+#ifdef DEBUG_HASHING
+ g_message( "++ reverse_circuit_id of call is zero, need to create a "
+ "new reverse circuit for this call" );
+#endif
+
+ iax_call -> reverse_circuit_id = src_circuit_id;
+ rev_circuit = circuit_new(CT_IAX2,
+ src_circuit_id,
+ framenum );
+ circuit_add_proto_data(rev_circuit, proto_iax2, iax_call);
+
+ /* we should have already set up a subdissector for the forward
+ * circuit. we'll need to copy it to the reverse circuit. */
+ circuit_set_dissector(rev_circuit, circuit_get_dissector(dst_circuit));
+#ifdef DEBUG_HASHING
+ g_message( "++ done" );
+#endif
+ } else if( iax_call -> reverse_circuit_id != src_circuit_id ) {
+ g_warning( "IAX Packet %u from circuit ids %u->%u"
+ "conflicts with earlier call with circuit ids %u->%u",
+ framenum,
+ src_circuit_id,dst_circuit_id,
+ iax_call->forward_circuit_id,
+ iax_call->reverse_circuit_id);
+ return NULL;
+ }
+ } else if ( dst_circuit_id == iax_call -> reverse_circuit_id ) {
+#ifdef DEBUG_HASHING
+ g_message( "++ destination circuit matches reverse_circuit_id of call, "
+ "therefore packet is forward" );
+#endif
+
+ reversed = FALSE;
+ if( iax_call -> forward_circuit_id != src_circuit_id ) {
+ g_warning( "IAX Packet %u from circuit ids %u->%u"
+ "conflicts with earlier call with circuit ids %u->%u",
+ framenum,
+ src_circuit_id,dst_circuit_id,
+ iax_call->forward_circuit_id,
+ iax_call->reverse_circuit_id);
+ return NULL;
+ }
+ } else {
+ g_assert_not_reached();
+ }
+
+
+ if( circuit_p ) {
+ /* by now we've created a new circuit if one was necessary, or
+ bailed out if it looks like a conflict, and we should be able
+ to look up the source circuit without issue */
+ *circuit_p = find_circuit( CT_IAX2,
+ src_circuit_id,
+ framenum );
+ g_assert(*circuit_p);
+ }
+
+ if( reversed_p )
+ *reversed_p = reversed;
+
+ return iax_call;
+}
+
+
+ /* looks up a circuit_t and an iax_call for this packet */
+static iax_call_data *iax_lookup_circuit_details( packet_info *pinfo,
+ guint32 scallno,
+ guint32 dcallno,
+ gboolean *reversed_p,
+ circuit_t **circuit_p)
+{
+ gboolean reversed = FALSE;
+ iax_call_data *iax_call = NULL;
+ guint src_circuit_id;
+ circuit_t *src_circuit = NULL;
+
+#ifdef DEBUG_HASHING
+ g_message( "++ iax_lookup_circuit_details: Looking up circuit for frame %u, "
+ "from {%s:%u:%u} to {%s:%u:%u}", pinfo->fd->num,
+ address_to_str(&pinfo->src),pinfo->srcport,scallno,
+ address_to_str(&pinfo->dst),pinfo->destport,dcallno);
+#endif
+
+
+ src_circuit_id = iax_circuit_lookup(&pinfo->src,pinfo->ptype,
+ pinfo->srcport,scallno);
+
+
+ /* the most reliable indicator of call is the destination callno, if
+ we have one */
+ if( dcallno != 0 ) {
+ guint dst_circuit_id;
+#ifdef DEBUG_HASHING
+ g_message( "++ dcallno non-zero, looking up destination circuit" );
+#endif
+
+ dst_circuit_id = iax_circuit_lookup(&pinfo->dst,pinfo->ptype,
+ pinfo->destport,dcallno);
+
+ iax_call = iax_lookup_circuit_details_from_dest(src_circuit_id, dst_circuit_id, pinfo->fd->num, &reversed, &src_circuit);
+ } else {
+
+ /* in all other circumstances, the source circuit should already
+ * exist: its absense indicates that we missed the all-important NEW
+ * packet.
+ */
+
+ src_circuit = find_circuit( CT_IAX2,
+ src_circuit_id,
+ pinfo->fd->num );
+
+ if( src_circuit ) {
+ iax_call = (iax_call_data *)circuit_get_proto_data(src_circuit,proto_iax2);
+
+ /* there's no way we can create a CT_IAX2 circuit without adding
+ iax call data to it; assert this */
+ g_assert(iax_call);
+
+ if( src_circuit_id == iax_call -> forward_circuit_id )
+ reversed = FALSE;
+ else if ( src_circuit_id == iax_call -> reverse_circuit_id )
+ reversed = TRUE;
+ else {
+ /* there's also no way we can attach an iax_call_data to a circuit
+ without the circuit being either the forward or reverse circuit
+ for that call; assert this too.
+ */
+ g_assert_not_reached();
+ }
+ }
+ }
+
+ if(src_circuit && iax_call) {
+ /* info for subdissectors. We always pass on the forward circuit,
+ * and steal the p2p_dir flag to indicate the direction */
+ pinfo -> ctype = CT_IAX2;
+ pinfo -> circuit_id = (guint32)iax_call->forward_circuit_id;
+ pinfo -> p2p_dir = reversed?P2P_DIR_RECV:P2P_DIR_SENT;
+ }
+
+ if(reversed_p)
+ *reversed_p = reversed;
+
+ if(circuit_p)
+ *circuit_p = src_circuit;
+
+#ifdef DEBUG_HASHING
+ if( iax_call ) {
+ g_message( "++ Found call for packet: id %u, reversed=%c", iax_call->callno, reversed?'1':'0' );
+ } else {
+ g_message( "++ Call not found. Must have missed the NEW packet?" );
+ }
+#endif
+
+ return iax_call;
+}
+
+
+/* handles a NEW packet by creating a new iax call and forward circuit.
+ the reverse circuit is not created until the ACK is received and
+ is created by iax_lookup_circuit_details. */
+static iax_call_data *iax_new_circuit_details( packet_info *pinfo,
+ guint32 scallno,
+ circuit_t **circuit_p)
+{
+ circuit_t *circuit;
+ iax_call_data *call;
+ guint circuit_id;
+
+#ifdef DEBUG_HASHING
+ g_message( "+ new_circuit: Handling NEW packet, frame %u", pinfo->fd->num );
+#endif
+
+ circuit_id = iax_circuit_lookup(&pinfo->src,pinfo->ptype,
+ pinfo->srcport,scallno);
+
+ circuit = circuit_new(CT_IAX2,
+ circuit_id,
+ pinfo->fd->num );
+
+
+
+ call = g_mem_chunk_alloc(iax_call_datas);
+ call -> dataformat = 0;
+ call -> src_codec = 0;
+ call -> dst_codec = 0;
+ call -> forward_circuit_id = circuit_id;
+ call -> reverse_circuit_id = 0;
+ call -> callno = ++callcount;
+
+#ifdef DEBUG_HASHING
+ g_message( "+ new_circuit: Added new circuit for new call %u", call -> callno );
+#endif
+
+ circuit_add_proto_data( circuit, proto_iax2, call );
+
+ if( circuit_p )
+ *circuit_p = circuit;
+
+ return call;
+}
+
+
+/* ************************************************************************* */
+
+/* per-packet data */
+typedef struct iax_packet_data {
+ iax_call_data *call_data;
+ guint32 codec;
+} iax_packet_data;
+
+static GMemChunk *iax_packets = NULL;
+
+static iax_packet_data *iax_new_packet_data(iax_call_data *call)
+{
+ iax_packet_data *p = g_mem_chunk_alloc(iax_packets);
+ p->call_data=call;
+ p->codec=0;
+ return p;
+}
+
+
+/* ************************************************************************* */
+
+static guint32 dissect_fullpacket (tvbuff_t * tvb, guint32 offset,
+ guint16 scallno,
+ packet_info * pinfo,
+ proto_tree * iax2_tree,
+ proto_tree * main_tree);
+
+
+static guint32 dissect_minipacket (tvbuff_t * tvb, guint32 offset,
+ guint16 scallno,
+ packet_info * pinfo,
+ proto_tree * iax2_tree,
+ proto_tree * main_tree);
+
+static guint32 dissect_minivideopacket (tvbuff_t * tvb, guint32 offset,
+ guint16 scallno,
+ packet_info * pinfo,
+ proto_tree * iax2_tree,
+ proto_tree * main_tree);
+
+static void dissect_payload(tvbuff_t *tvb, guint32 offset,
+ packet_info *pinfo, proto_tree *tree,
+ guint32 ts, gboolean video,
+ iax_packet_data *iax_packet);
+
+
static void
dissect_iax2 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
{
- proto_tree *iax2_tree = NULL, *ies_tree = NULL, *codec_tree = NULL, *sockaddr_tree = NULL;
- proto_item *ti = 0, *ies_base = 0, *codec_base = 0, *sockaddr_item = 0;
- guint32 offset = 0, codecs = 0, i = 0, mask = 0, retransmission = 0;
- guint16 scallno;
- guint16 dcallno;
- guint32 ts;
- guint8 type;
- guint8 csub;
+ proto_item *iax2_item = NULL;
+ proto_tree *iax2_tree = NULL;
+ proto_tree *full_mini_subtree = NULL;
+ guint32 offset = 0, len;
+ guint16 scallno = 0;
+ guint16 stmp;
+ packet_type type;
+ /* set up the protocol and info fields in the summary pane */
if (check_col (pinfo->cinfo, COL_PROTOCOL))
{
col_set_str (pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_IAX2);
@@ -226,133 +812,109 @@ dissect_iax2 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
col_clear (pinfo->cinfo, COL_INFO);
}
+ /* add the 'iax2' tree to the main tree */
if (tree)
{
- ti = proto_tree_add_item (tree, proto_iax2, tvb, offset, -1, FALSE);
- iax2_tree = proto_item_add_subtree (ti, ett_iax2);
+ iax2_item = proto_tree_add_item (tree, proto_iax2, tvb, offset, -1, FALSE);
+ iax2_tree = proto_item_add_subtree (iax2_item, ett_iax2);
}
- scallno = tvb_get_ntohs(tvb, offset);
- if (scallno & 0x8000)
- {
- /*
- * remove the top bit for header type detection
- */
- scallno = scallno & 0x7FFF;
- proto_tree_add_uint (iax2_tree, hf_iax2_scallno, tvb, offset, 2,
- scallno);
+ stmp = tvb_get_ntohs(tvb, offset);
+ if( stmp == 0 ) {
+ /* starting with 0x0000 indicates either a mini video packet or a 'meta'
+ * packet, whatever that means */
+ offset+=2;
+ stmp = tvb_get_ntohs(tvb, offset);
+ if( stmp & 0x8000 ) {
+ /* mini video packet */
+ type = IAX2_MINI_VIDEO_PACKET;
+ scallno = stmp & 0x7FFF;
+ offset += 2;
+ }
+ else {
+ type = IAX2_META_PACKET;
+ }
+ } else {
+ /* The source call/fullpacket flag is common to both mini and full packets */
+ scallno = tvb_get_ntohs(tvb, offset);
+ offset += 2;
+ if( scallno & 0x8000 )
+ type = IAX2_FULL_PACKET;
+ else {
+ type = IAX2_MINI_VOICE_PACKET;
+ }
+ scallno &= 0x7FFF;
+ }
- /*
- * remove the top bit for retransmission detection
- */
- dcallno = tvb_get_ntohs(tvb, offset + 2);
- retransmission = dcallno & 0x8000;
- dcallno = dcallno & 0x7FFF;
- proto_tree_add_uint (iax2_tree, hf_iax2_dcallno, tvb, offset + 2, 2,
- dcallno);
- proto_tree_add_boolean (iax2_tree, hf_iax2_retransmission, tvb,
- offset + 2, 2, retransmission);
-
- ts = tvb_get_ntohl(tvb, offset + 4);
- proto_tree_add_uint (iax2_tree, hf_iax2_ts, tvb, offset + 4, 4, ts);
- proto_tree_add_item (iax2_tree, hf_iax2_oseqno, tvb, offset + 8, 1,
- FALSE);
- proto_tree_add_item (iax2_tree, hf_iax2_iseqno, tvb, offset + 9, 1,
- FALSE);
- type = tvb_get_guint8(tvb, offset + 10);
- proto_tree_add_uint (iax2_tree, hf_iax2_type, tvb, offset + 10, 1,
- type);
-
- csub = tvb_get_guint8(tvb, offset + 11);
- if (type == AST_FRAME_IAX)
- {
- proto_tree_add_uint (iax2_tree, hf_iax2_iax_csub, tvb,
- offset + 11, 1, csub);
- if (check_col (pinfo->cinfo, COL_INFO))
- {
- col_add_fstr (pinfo->cinfo, COL_INFO,
- "%s %s, source call# %d, timestamp %ums",
- val_to_str (type, iax_frame_types,
- "Unknown (0x%02x)"),
- val_to_str (csub, iax_iax_subclasses,
- "unknown (0x%02x)"), scallno,
- ts);
- }
+ if( tree ) {
+ proto_item *full_mini_base;
- }
- else if (type == AST_FRAME_DTMF)
- {
- proto_tree_add_text (iax2_tree, tvb, offset + 11, 1, "DTMF digit: %c", csub);
- if (check_col (pinfo->cinfo, COL_INFO))
- {
- col_add_fstr (pinfo->cinfo, COL_INFO,
- "%s digit %c, source call# %d, timestamp %ums",
- val_to_str (type, iax_frame_types,
- "Unknown (0x%02x)"), csub,
- scallno, ts);
- }
+ full_mini_base = proto_tree_add_uint(iax2_tree, hf_iax2_packet_type, tvb, 0, offset, type);
+ full_mini_subtree = proto_item_add_subtree(full_mini_base, ett_iax2_full_mini_subtree);
- }
- else if (type == AST_FRAME_CONTROL)
- {
- proto_tree_add_uint (iax2_tree, hf_iax2_cmd_csub, tvb,
- offset + 11, 1, csub);
- if (check_col (pinfo->cinfo, COL_INFO))
- {
- col_add_fstr (pinfo->cinfo, COL_INFO,
- "%s %s, source call# %d, timestamp %ums",
- val_to_str (type, iax_frame_types,
- "Unknown (0x%02x)"),
- val_to_str (csub, iax_cmd_subclasses,
- "unknown (0x%02x)"), scallno,
- ts);
- }
+ if( scallno != 0 )
+ proto_tree_add_item (full_mini_subtree, hf_iax2_scallno, tvb, offset-2, 2, FALSE);
+ }
- }
- else if (type == AST_FRAME_VOICE)
- {
- proto_tree_add_uint (iax2_tree, hf_iax2_voice_csub, tvb,
- offset + 11, 1, csub);
- if (check_col (pinfo->cinfo, COL_INFO))
- {
- col_add_fstr (pinfo->cinfo, COL_INFO,
- "%s codec %s, source call# %d, timestamp %ums",
- val_to_str (type, iax_frame_types,
- "Unknown (0x%02x)"),
- val_to_str (csub, codec_types,
- "unknown (0x%02x)"), scallno,
- ts);
- }
- }
- else
- {
- proto_tree_add_uint (iax2_tree, hf_iax2_csub, tvb, offset + 11,
- 1, csub);
- if (check_col (pinfo->cinfo, COL_INFO))
- {
- col_add_fstr (pinfo->cinfo, COL_INFO,
- "%s subclass %d, source call# %d, timestamp %ums",
- val_to_str (type, iax_frame_types,
- "Unknown (0x%02x)"), csub,
- scallno, ts);
- }
- }
- offset += 12;
-
- if (type == AST_FRAME_IAX && (offset < tvb_reported_length (tvb)))
- {
- ies_base =
- proto_tree_add_item (iax2_tree, hf_iax2_ies, tvb, offset,
- -1, FALSE);
- ies_tree = proto_item_add_subtree (ies_base, ett_iax2_ies);
- }
+ switch( type ) {
+ case IAX2_FULL_PACKET:
+ len = dissect_fullpacket( tvb, offset, scallno, pinfo, full_mini_subtree, tree );
+ break;
+ case IAX2_MINI_VOICE_PACKET:
+ len = dissect_minipacket( tvb, offset, scallno, pinfo, full_mini_subtree, tree );
+ break;
+ case IAX2_MINI_VIDEO_PACKET:
+ len = dissect_minivideopacket( tvb, offset, scallno, pinfo, full_mini_subtree, tree );
+ break;
+ case IAX2_META_PACKET:
+ /* not implemented yet */
+ len = 0;
+ break;
+ default:
+ len = 0;
+ }
- while (type == AST_FRAME_IAX && offset < tvb_reported_length (tvb))
- {
- int ies_type = tvb_get_guint8(tvb, offset);
- int ies_len = tvb_get_guint8(tvb, offset + 1);
- switch (ies_type)
- {
+ /* update the 'length' of the main IAX2 header field so that it covers just the headers,
+ not the audio data. */
+ proto_item_set_len(iax2_item, len);
+}
+
+
+/* dissect the information elements in an IAX frame. Returns the updated offset */
+static guint32 dissect_ies (tvbuff_t * tvb, guint32 offset,
+ proto_tree * iax_tree,
+ iax_call_data *iax_call_data )
+{
+ proto_tree *sockaddr_tree = NULL;
+ proto_item *sockaddr_item = 0;
+
+
+ while (offset < tvb_reported_length (tvb)) {
+
+ int ies_type = tvb_get_guint8(tvb, offset);
+ int ies_len = tvb_get_guint8(tvb, offset + 1);
+
+ if( iax_tree ) {
+ proto_item *ti;
+ proto_tree *ies_tree;
+
+ ti = proto_tree_add_text(iax_tree, tvb, offset, ies_len+2,
+ "Information Element: %s (0x%02X)",
+ val_to_str(ies_type, iax_ies_type,
+ "Unknown information element"),
+ ies_type);
+
+
+ ies_tree = proto_item_add_subtree(ti, ett_iax2_ie);
+
+ proto_tree_add_text(ies_tree, tvb, offset, 1, "IE id: %s (0x%02X)",
+ val_to_str(ies_type, iax_ies_type, "Unknown"),
+ ies_type);
+
+ proto_tree_add_text(ies_tree, tvb, offset+1, 1, "Length: %u",ies_len);
+
+
+ switch (ies_type) {
case IAX_IE_CALLED_NUMBER:
proto_tree_add_item (ies_tree, hf_IAX_IE_CALLED_NUMBER, tvb,
offset + 2, ies_len, FALSE);
@@ -406,33 +968,33 @@ dissect_iax2 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
offset + 2, ies_len, FALSE);
break;
case IAX_IE_CAPABILITY:
+ {
+ proto_tree *codec_tree;
+ proto_item *codec_base;
+
codec_base =
proto_tree_add_item (ies_tree, hf_IAX_IE_CAPABILITY,
tvb, offset + 2, ies_len, FALSE);
codec_tree =
proto_item_add_subtree (codec_base, ett_iax2_codecs);
-
- codecs = tvb_get_ntohl (tvb, offset + 2);
- for (i = 0; i < 8; i++)
- {
- mask = (1 << i);
- if (codecs & mask)
- proto_tree_add_text (codec_tree, tvb, offset + 2, 4,
- "Supported: %s",
- val_to_str (mask, codec_types,
- "unknown"));
- }
- for (i = 0; i < 8; i++)
- {
- mask = (1 << i);
- if (!(codecs & mask))
- proto_tree_add_text (codec_tree, tvb, offset + 2, 4,
- "Unsupported: %s",
- val_to_str (mask, codec_types,
- "unknown"));
- }
-
+
+ proto_tree_add_item(codec_tree, hf_iax2_cap_g723_1, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_gsm, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_ulaw, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_alaw, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_g726, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_adpcm, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_slinear, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_lpc10, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_g729a, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_speex, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_ilbc, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_jpeg, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_png, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_h261, tvb, offset + 2, ies_len, FALSE );
+ proto_tree_add_item(codec_tree, hf_iax2_cap_h263, tvb, offset + 2, ies_len, FALSE );
break;
+ }
case IAX_IE_FORMAT:
proto_tree_add_item (ies_tree, hf_IAX_IE_FORMAT, tvb,
offset + 2, ies_len, FALSE);
@@ -491,221 +1053,803 @@ dissect_iax2 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
proto_tree_add_item (ies_tree, hf_IAX_IE_TRANSFERID, tvb,
offset + 2, ies_len, FALSE);
break;
- }
- offset += ies_len + 2;
- }
+
+ case IAX_IE_DATAFORMAT:
+ proto_tree_add_item (ies_tree, hf_IAX_IE_DATAFORMAT, tvb,
+ offset + 2, ies_len, FALSE);
+
+ if( iax_call_data )
+ iax_call_data -> dataformat = tvb_get_ntohl(tvb, offset+2);
+
+ break;
+
+ default:
+ {
+ switch(ies_len) {
+ case 1:
+ proto_tree_add_item( ies_tree, hf_IAX_IE_UNKNOWN_BYTE, tvb, offset+2, ies_len, FALSE );
+ break;
+
+ case 2:
+ proto_tree_add_item( ies_tree, hf_IAX_IE_UNKNOWN_I16, tvb, offset+2, ies_len, FALSE );
+ break;
+
+ case 4:
+ proto_tree_add_item( ies_tree, hf_IAX_IE_UNKNOWN_I32, tvb, offset+2, ies_len, FALSE );
+ break;
+ default:
+ proto_tree_add_item( ies_tree, hf_IAX_IE_UNKNOWN_BYTES, tvb, offset+2, ies_len, FALSE );
+ }
+ }
+ }
}
+ offset += ies_len + 2;
+ }
+ return offset;
+}
+
+static guint32 uncompress_subclass(guint8 csub)
+{
+ /* If the SC_LOG flag is set, return 2^csub otherwise csub */
+ if (csub & 0x80) {
+ /* special case for 'compressed' -1 */
+ if (csub == 0xff)
+ return (guint32)-1;
+ else
+ return 1 << (csub & 0x1F);
+ }
else
- {
- proto_tree_add_uint (iax2_tree, hf_iax2_scallno, tvb, offset, 2,
- scallno);
- ts = tvb_get_ntohs(tvb, offset + 2);
- proto_tree_add_uint (iax2_tree, hf_iax2_minits, tvb, offset + 2, 2,
- ts);
- if (check_col (pinfo->cinfo, COL_INFO))
- {
- col_add_fstr (pinfo->cinfo, COL_INFO,
- "Voice frame (mini header), source call# %d, timestamp %ums",
- scallno, ts);
- }
- proto_tree_add_item (iax2_tree, hf_iax2_voicedata, tvb, offset + 4,
- -1, FALSE);
+ return (guint32)csub;
+}
+
+
+static guint32
+dissect_fullpacket (tvbuff_t * tvb, guint32 offset,
+ guint16 scallno,
+ packet_info * pinfo, proto_tree * iax2_tree,
+ proto_tree * main_tree)
+{
+ guint32 retransmission = 0;
+ guint16 dcallno;
+ guint32 ts;
+ guint8 type;
+ guint8 csub;
+ guint32 codec;
+
+ proto_tree *packet_type_tree = NULL;
+ iax_call_data *iax_call;
+ iax_packet_data *iax_packet;
+ gboolean reversed;
+ gboolean rtp_marker;
+
+ circuit_t *circuit;
+
+ /*
+ * remove the top bit for retransmission detection
+ */
+ dcallno = tvb_get_ntohs(tvb, offset);
+ retransmission = dcallno & 0x8000;
+ dcallno = dcallno & 0x7FFF;
+ ts = tvb_get_ntohl(tvb, offset+2);
+ type = tvb_get_guint8(tvb, offset + 8);
+ csub = tvb_get_guint8(tvb, offset + 9);
+
+ /* see if we've seen this packet before */
+ iax_packet = (iax_packet_data *)p_get_proto_data(pinfo->fd,proto_iax2);
+ if( !iax_packet ) {
+ /* if not, find or create an iax_call info structure for this IAX session. */
+
+ if( type == AST_FRAME_IAX && csub == IAX_COMMAND_NEW ) {
+ /* NEW packets start a new call */
+ iax_call = iax_new_circuit_details(pinfo,scallno,&circuit);
+ reversed = FALSE;
+ } else {
+ iax_call = iax_lookup_circuit_details(pinfo, scallno, dcallno,
+ &reversed, &circuit);
+ }
+
+ iax_packet = iax_new_packet_data(iax_call);
+ p_add_proto_data(pinfo->fd,proto_iax2,iax_packet);
+ } else {
+ iax_call = iax_packet->call_data;
+ }
+
+ if( iax2_tree ) {
+ proto_item *packet_type_base;
+
+ proto_tree_add_item (iax2_tree, hf_iax2_dcallno, tvb, offset, 2, FALSE );
+ proto_tree_add_boolean(iax2_tree, hf_iax2_retransmission, tvb, offset, 2, FALSE );
+
+ proto_tree_add_uint (iax2_tree, hf_iax2_ts, tvb, offset+2, 4, ts);
+
+ proto_tree_add_item (iax2_tree, hf_iax2_oseqno, tvb, offset+6, 1,
+ FALSE);
+
+ proto_tree_add_item (iax2_tree, hf_iax2_iseqno, tvb, offset+7, 1,
+ FALSE);
+ packet_type_base = proto_tree_add_uint (iax2_tree, hf_iax2_type, tvb,
+ offset+8, 1, type);
+
+ /* add the type-specific subtree */
+ packet_type_tree = proto_item_add_subtree (packet_type_base, ett_iax2_type);
+ }
+
+ /* add frame type to info line */
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ col_add_fstr (pinfo->cinfo, COL_INFO, "%s, source call# %d, timestamp %ums",
+ val_to_str (type, iax_frame_types, "Unknown (0x%02x)"),
+ scallno, ts);
+ }
+
+ switch( type ) {
+ case AST_FRAME_IAX:
+ /* add the subclass */
+ proto_tree_add_uint (packet_type_tree, hf_iax2_iax_csub, tvb,
+ offset+9, 1, csub);
+ offset += 10;
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
+ val_to_str (csub, iax_iax_subclasses, "unknown (0x%02x)"));
+
+ if (offset < tvb_reported_length (tvb)) {
+ offset += dissect_ies(tvb, offset, packet_type_tree, iax_call);
+ }
+
+ if( csub == IAX_COMMAND_NEW && circuit && iax_call ) {
+ /* if this is a data call, set up a subdissector for the circuit */
+ dissector_handle_t s;
+ s = dissector_get_port_handle(iax2_dataformat_dissector_table, iax_call -> dataformat );
+ circuit_set_dissector( circuit, s );
+ }
+ break;
+
+ case AST_FRAME_DTMF:
+ proto_tree_add_text (packet_type_tree, tvb, offset+9, 1, "DTMF digit: %c", csub);
+ offset += 10;
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " digit %c", csub );
+ break;
+
+ case AST_FRAME_CONTROL:
+ /* add the subclass */
+ proto_tree_add_uint (packet_type_tree, hf_iax2_cmd_csub, tvb,
+ offset+9, 1, csub);
+ offset += 10;
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
+ val_to_str (csub, iax_cmd_subclasses, "unknown (0x%02x)"));
+ break;
+
+ case AST_FRAME_VOICE:
+ /* add the codec */
+ iax_packet -> codec = codec = uncompress_subclass(csub);
+
+ if( packet_type_tree ) {
+ proto_tree_add_item (packet_type_tree, hf_iax2_voice_csub, tvb, offset+9, 1, FALSE);
+ proto_tree_add_uint (packet_type_tree, hf_iax2_voice_codec, tvb, offset+9, 1, codec);
+ }
+
+ offset += 10;
+
+ if( iax_call ) {
+ if( reversed ) {
+ iax_call->dst_codec = codec;
+ } else {
+ iax_call->src_codec = codec;
+ }
+ }
+
+ dissect_payload(tvb, offset, pinfo, main_tree, ts, FALSE,iax_packet);
+ break;
+
+ case AST_FRAME_VIDEO:
+ /* bit 6 of the csub is used to represent the rtp 'marker' bit */
+ rtp_marker = csub & 0x40 ? TRUE:FALSE;
+ iax_packet -> codec = codec = uncompress_subclass(csub & ~40);
+
+ if( packet_type_tree ) {
+ proto_tree_add_item (packet_type_tree, hf_iax2_video_csub, tvb, offset+9, 1, FALSE);
+ proto_tree_add_item (packet_type_tree, hf_iax2_marker, tvb, offset+9, 1, FALSE);
+ proto_tree_add_uint (packet_type_tree, hf_iax2_video_codec, tvb, offset+9, 1, codec);
+ }
+
+ offset += 10;
+
+ if( iax_call ) {
+ if( reversed ) {
+ iax_call->dst_vformat = codec;
+ } else {
+ iax_call->src_vformat = codec;
+ }
+ }
+
+ if( rtp_marker && check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, ", Mark" );
+
+
+ dissect_payload(tvb, offset, pinfo, main_tree, ts, TRUE, iax_packet);
+ break;
+
+
+ default:
+ proto_tree_add_uint (packet_type_tree, hf_iax2_csub, tvb, offset+9,
+ 1, csub);
+ offset += 10;
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " subclass %d", csub );
+ break;
+ }
+
+ return offset;
+}
+
+static iax_packet_data *iax2_get_packet_data_for_minipacket(packet_info * pinfo,
+ guint16 scallno,
+ gboolean video)
+{
+ /* see if we've seen this packet before */
+ iax_packet_data *p = (iax_packet_data *)p_get_proto_data(pinfo->fd,proto_iax2);
+
+ if( !p ) {
+ /* if not, find or create an iax_call info structure for this IAX session. */
+ gboolean reversed;
+ circuit_t *circuit;
+ iax_call_data *iax_call;
+
+ iax_call = iax_lookup_circuit_details(pinfo, scallno, 0, &reversed, &circuit);
+
+ p = iax_new_packet_data(iax_call);
+ p_add_proto_data(pinfo->fd,proto_iax2,p);
+
+ /* set the codec for this frame to be whatever the last full frame used */
+ if( video )
+ p->codec = reversed ? iax_call -> dst_vformat : iax_call -> src_vformat;
+ else
+ p->codec = reversed ? iax_call -> dst_codec : iax_call -> src_codec;
+ }
+ return p;
+}
+
+
+static guint32 dissect_minivideopacket (tvbuff_t * tvb, guint32 offset,
+ guint16 scallno, packet_info * pinfo,
+ proto_tree * iax2_tree, proto_tree *main_tree)
+{
+ guint32 ts;
+ iax_packet_data *iax_packet;
+ gboolean rtp_marker;
+
+ ts = tvb_get_ntohs(tvb, offset);
+
+ /* bit 15 of the ts is used to represent the rtp 'marker' bit */
+ rtp_marker = ts & 0x8000 ? TRUE:FALSE;
+ ts &= ~0x8000;
+
+
+ if( iax2_tree ) {
+ proto_tree_add_item (iax2_tree, hf_iax2_minividts, tvb, offset, 2, FALSE);
+ proto_tree_add_item (iax2_tree, hf_iax2_minividmarker, tvb, offset, 2, FALSE);
+ }
+
+ offset += 2;
+
+ iax_packet = iax2_get_packet_data_for_minipacket(pinfo, scallno, TRUE);
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_add_fstr (pinfo->cinfo, COL_INFO,
+ "Mini video packet, source call# %d, timestamp %ums%s",
+ scallno, ts, rtp_marker?", Mark":"");
+
+
+ dissect_payload(tvb, offset, pinfo, main_tree, ts, TRUE, iax_packet);
+
+ return offset;
+}
+
+static guint32
+dissect_minipacket (tvbuff_t * tvb, guint32 offset, guint16 scallno, packet_info * pinfo, proto_tree * iax2_tree,
+ proto_tree *main_tree)
+{
+ guint32 ts;
+ iax_packet_data *iax_packet;
+
+ ts = tvb_get_ntohs(tvb, offset);
+
+ iax_packet = iax2_get_packet_data_for_minipacket(pinfo, scallno, FALSE);
+
+ proto_tree_add_uint (iax2_tree, hf_iax2_minits, tvb, offset, 2,
+ ts);
+ offset += 2;
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_add_fstr (pinfo->cinfo, COL_INFO,
+ "Mini packet, source call# %d, timestamp %ums",
+ scallno, ts);
+
+
+ /* XXX fix the timestamp logic */
+ dissect_payload(tvb, offset, pinfo, main_tree, ts, FALSE, iax_packet);
+
+
+ return offset;
+}
+
+static void dissect_payload(tvbuff_t *tvb, guint32 offset,
+ packet_info *pinfo, proto_tree *tree,
+ guint32 ts, gboolean video,
+ iax_packet_data *iax_packet)
+{
+ gboolean out_of_order = FALSE;
+ tvbuff_t *sub_tvb;
+ guint32 codec = iax_packet -> codec;
+ iax_call_data *iax_call = iax_packet -> call_data;
+
+ /* keep compiler quiet */
+ ts = ts;
+
+ if( offset >= tvb_reported_length (tvb)) {
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, ", empty frame" );
+ return;
+ }
+
+ sub_tvb = tvb_new_subset(tvb, offset, -1, -1 );
+
+ /* XXX shouldn't pass through out-of-order packets. */
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ if( !video && iax_call && iax_call -> dataformat != 0 ) {
+ col_append_fstr (pinfo->cinfo, COL_INFO, ", data, format %s",
+ val_to_str (iax_call -> dataformat,
+ iax_dataformats, "unknown (0x%02x)"));
+
+ if( out_of_order )
+ col_append_fstr (pinfo->cinfo, COL_INFO, " (out-of-order packet)");
+ } else {
+ col_append_fstr (pinfo->cinfo, COL_INFO, ", %s",
+ val_to_str (codec, codec_types, "unknown (0x%02x)"));
}
+ }
+
+ /* pass the rest of the block to a subdissector */
+ if( !video && try_circuit_dissector(pinfo->ctype, pinfo->circuit_id, pinfo->fd->num,
+ sub_tvb, pinfo, tree))
+ return;
+
+ if( codec != 0 && dissector_try_port(iax2_codec_dissector_table, codec, sub_tvb, pinfo, tree ))
+ return;
+
+ /* we don't know how to dissect our data: dissect it as data */
+ call_dissector(data_handle,sub_tvb, pinfo, tree);
+}
+
+/*
+ * Init routines
+ */
+
+/* called at the start of a capture. We should clear out our static, per-capture
+ * data.
+ */
+
+static void
+iax_init_protocol(void)
+{
+ iax_init_hash();
+
+ if (iax_packets)
+ g_mem_chunk_destroy(iax_packets);
+ iax_packets = g_mem_chunk_create(iax_packet_data,128,G_ALLOC_ONLY);
+}
-} /* dissect_iax2 */
void
proto_register_iax2 (void)
{
+ /* we use this for displaying which codecs are supported */
+ static const true_false_string supported_strings = {
+ "Supported",
+ "Not supported"
+ };
+
+ /* A header field is something you can search/filter on.
+ *
+ * We create a structure to register our fields. It consists of an
+ * array of hf_register_info structures, each of which are of the format
+ * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
+ */
+
static hf_register_info hf[] = {
+
+ {&hf_iax2_packet_type,
+ {"Packet type", "iax2.type", FT_UINT8, BASE_DEC, VALS(iax_packet_types), 0,
+ "Full/minivoice/minivideo/meta packet",
+ HFILL}},
+
+
{&hf_iax2_scallno,
- {"Source call", "iax2.src_call", FT_UINT16, BASE_DEC, NULL, 0x0,
- "",
+ {"Source call", "iax2.src_call", FT_UINT16, BASE_DEC, NULL, 0x7FFF,
+ "src_call holds the number of this call at the packet source pbx",
HFILL}},
+
+ /* FIXME could this be turned into a FRAMENUM field? */
{&hf_iax2_dcallno,
- {"Destination call", "iax2.dst_call", FT_UINT16, BASE_DEC, NULL,
- 0x0, "",
+ {"Destination call", "iax2.dst_call", FT_UINT16, BASE_DEC, NULL, 0x7FFF,
+ "dst_call holds the number of this call at the packet destination",
HFILL}},
+
{&hf_iax2_retransmission,
- {"Retransmission", "iax2.retransmission", FT_BOOLEAN, BASE_NONE,
- NULL,
- 0x0, "", HFILL}},
+ {"Retransmission", "iax2.retransmission", FT_BOOLEAN, 16,
+ NULL, 0x8000,
+ "retransmission is set if this packet is a retransmission of an earlier "
+ "failed packet", HFILL}},
+
{&hf_iax2_ts,
{"Timestamp", "iax2.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
- "",
+ "timestamp is the time, in ms after the start of this call, at which "
+ "this packet was transmitted",
HFILL}},
+
{&hf_iax2_minits,
{"Timestamp", "iax2.timestamp", FT_UINT16, BASE_DEC, NULL, 0x0,
- "",
+ "timestamp is the time, in ms after the start of this call, at which "
+ "this packet was transmitted",
+ HFILL}},
+
+ {&hf_iax2_minividts,
+ {"Timestamp", "iax2.timestamp", FT_UINT16, BASE_DEC, NULL, 0x7FFF,
+ "timestamp is the time, in ms after the start of this call, at which "
+ "this packet was transmitted",
HFILL}},
- {&hf_iax2_voicedata,
- {"Voice data", "iax2.voicedata", FT_BYTES, BASE_NONE, NULL, 0x0,
- "",
+
+ {&hf_iax2_minividmarker,
+ {"Marker", "iax2.video.marker", FT_UINT16, BASE_DEC, NULL, 0x8000,
+ "RTP end-of-frame marker",
HFILL}},
+
{&hf_iax2_oseqno,
{"Outbound seq.no.", "iax2.oseqno", FT_UINT16, BASE_DEC, NULL,
- 0x0, "",
+ 0x0,
+ "oseqno is the sequence no of this packet. The first packet has "
+ "oseqno==0, and subsequent packets increment the oseqno by 1",
HFILL}},
+
{&hf_iax2_iseqno,
{"Inbound seq.no.", "iax2.iseqno", FT_UINT16, BASE_DEC, NULL, 0x0,
- "",
+ "iseqno is the sequence no of the last successfully recieved packet",
HFILL}},
+
{&hf_iax2_type,
{"Type", "iax2.type", FT_UINT8, BASE_DEC, VALS (iax_frame_types),
- 0x0, "",
+ 0x0,
+ "For full IAX2 frames, type is the type of frame",
HFILL}},
+
{&hf_iax2_csub,
- {"Sub-class", "iax2.subclass", FT_UINT8, BASE_DEC, NULL, 0x0, "",
+ {"Sub-class", "iax2.subclass", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "subclass",
HFILL}},
+
{&hf_iax2_cmd_csub,
- {"Control type", "iax2.control", FT_UINT8, BASE_DEC,
- VALS (iax_cmd_subclasses), 0x0, "", HFILL}},
- {&hf_iax2_voice_csub,
- {"CODEC", "iax2.voice", FT_UINT8, BASE_DEC, VALS (codec_types),
- 0x0, "", HFILL}},
+ {"Control subclass", "iax2.control.subclass", FT_UINT8, BASE_DEC,
+ VALS (iax_cmd_subclasses), 0x0,
+ "This gives the command number for a Control packet.", HFILL}},
+
{&hf_iax2_iax_csub,
- {"IAX type", "iax2.iax", FT_UINT8, BASE_DEC,
+ {"IAX type", "iax2.iax.subclass", FT_UINT8, BASE_DEC,
VALS (iax_iax_subclasses),
- 0x0, "", HFILL}},
- {&hf_iax2_ies,
- {"Information elements", "iax2.ies", FT_BYTES, BASE_NONE, NULL,
- 0x0, "", HFILL}},
- {&hf_IAX_IE_APPARENTADDR_SINFAMILY,
- {"Family", "iax2.ies.app_addr.sinfamily", FT_UINT16, BASE_DEC, NULL, 0, "Family", HFILL }},
- {&hf_IAX_IE_APPARENTADDR_SINPORT,
- {"Port", "iax2.ies.app_addr.sinport", FT_UINT16, BASE_DEC, NULL, 0, "Port", HFILL }},
- {&hf_IAX_IE_APPARENTADDR_SINADDR,
- {"Address", "iax2.ies.app_addr.sinaddr", FT_IPv4, BASE_HEX, NULL, 0, "Address", HFILL }},
- {&hf_IAX_IE_APPARENTADDR_SINZERO,
- {"Zero", "iax2.ies.app_addr.sinzero", FT_BYTES, BASE_HEX, NULL, 0, "Zero", HFILL }},
+ 0x0,
+ "IAX type gives the command number for IAX signalling packets", HFILL}},
+
+ {&hf_iax2_voice_csub,
+ {"Sub-class", "iax2.voice.subclass", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "subclass",
+ HFILL}},
+
+ {&hf_iax2_voice_codec,
+ {"CODEC", "iax2.voice.codec", FT_UINT32, BASE_HEX, VALS (codec_types),
+ 0x0,
+ "CODEC gives the codec used to encode audio data", HFILL}},
+
+ {&hf_iax2_video_csub,
+ {"Subclass (compressed codec no)", "iax2.video.subclass", FT_UINT8, BASE_DEC, NULL, 0xBF,
+ "Subclass (compressed codec no)",
+ HFILL}},
+
+ {&hf_iax2_marker,
+ {"Marker", "iax2.video.marker", FT_BOOLEAN, 8, NULL, 0x40,
+ "RTP end-of-frame marker",
+ HFILL}},
+
+ {&hf_iax2_video_codec,
+ {"CODEC", "iax2.video.codec", FT_UINT32, BASE_HEX, VALS (codec_types), 0,
+ "The codec used to encode video data", HFILL}},
+
+ /*
+ * Decoding for the ies
+ */
+
+ {&hf_IAX_IE_APPARENTADDR_SINFAMILY,
+ {"Family", "iax2.iax.app_addr.sinfamily", FT_UINT16, BASE_DEC, NULL, 0, "Family", HFILL }},
+ {&hf_IAX_IE_APPARENTADDR_SINPORT,
+ {"Port", "iax2.iax.app_addr.sinport", FT_UINT16, BASE_DEC, NULL, 0, "Port", HFILL }},
+ {&hf_IAX_IE_APPARENTADDR_SINADDR,
+ {"Address", "iax2.iax.app_addr.sinaddr", FT_IPv4, BASE_HEX, NULL, 0, "Address", HFILL }},
+ {&hf_IAX_IE_APPARENTADDR_SINZERO,
+ {"Zero", "iax2.iax.app_addr.sinzero", FT_BYTES, BASE_HEX, NULL, 0, "Zero", HFILL }},
+
{&hf_IAX_IE_CALLED_NUMBER,
- {"Number/extension being called", "iax2.ies.called_number",
+ {"Number/extension being called", "iax2.iax.called_number",
FT_STRING,
BASE_NONE, NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_CALLING_NUMBER,
- {"Calling number", "iax2.ies.calling_number", FT_STRING,
+ {"Calling number", "iax2.iax.calling_number", FT_STRING,
BASE_NONE, NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_CALLING_ANI,
- {"Calling number ANI for billing", "iax2.ies.calling_ani",
+ {"Calling number ANI for billing", "iax2.iax.calling_ani",
FT_STRING,
BASE_NONE, NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_CALLING_NAME,
- {"Name of caller", "iax2.ies.calling_name", FT_STRING, BASE_NONE,
+ {"Name of caller", "iax2.iax.calling_name", FT_STRING, BASE_NONE,
NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_CALLED_CONTEXT,
- {"Context for number", "iax2.ies.called_context", FT_STRING,
+ {"Context for number", "iax2.iax.called_context", FT_STRING,
BASE_NONE,
NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_USERNAME,
{"Username (peer or user) for authentication",
- "iax2.ies.username",
+ "iax2.iax.username",
FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_PASSWORD,
- {"Password for authentication", "iax2.ies.password", FT_STRING,
+ {"Password for authentication", "iax2.iax.password", FT_STRING,
BASE_NONE, NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_CAPABILITY,
- {"Actual codec capability", "iax2.ies.capability", FT_UINT32,
+ {"Actual codec capability", "iax2.iax.capability", FT_UINT32,
BASE_HEX,
NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_FORMAT,
- {"Desired codec format", "iax2.ies.format", FT_UINT32, BASE_HEX,
+ {"Desired codec format", "iax2.iax.format", FT_UINT32, BASE_HEX,
VALS (codec_types), 0x0, "", HFILL}},
+
{&hf_IAX_IE_LANGUAGE,
- {"Desired language", "iax2.ies.language", FT_STRING, BASE_NONE,
+ {"Desired language", "iax2.iax.language", FT_STRING, BASE_NONE,
NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_VERSION,
- {"Protocol version", "iax2.ies.version", FT_INT16, BASE_HEX, NULL,
+ {"Protocol version", "iax2.iax.version", FT_UINT16, BASE_HEX, NULL,
0x0,
"", HFILL}},
+
{&hf_IAX_IE_ADSICPE,
- {"CPE ADSI capability", "iax2.ies.cpe_adsi", FT_INT16, BASE_HEX,
+ {"CPE ADSI capability", "iax2.iax.cpe_adsi", FT_UINT16, BASE_HEX,
NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_DNID,
- {"Originally dialed DNID", "iax2.ies.dnid", FT_STRING, BASE_NONE,
+ {"Originally dialed DNID", "iax2.iax.dnid", FT_STRING, BASE_NONE,
NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_AUTHMETHODS,
- {"Authentication method(s)", "iax2.ies.auth.methods", FT_INT16,
+ {"Authentication method(s)", "iax2.iax.auth.methods", FT_UINT16,
BASE_HEX,
NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_CHALLENGE,
- {"Challenge data for MD5/RSA", "iax2.ies.auth.challenge",
+ {"Challenge data for MD5/RSA", "iax2.iax.auth.challenge",
FT_STRING,
BASE_NONE, NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_MD5_RESULT,
- {"MD5 challenge result", "iax2.ies.auth.md5", FT_STRING,
+ {"MD5 challenge result", "iax2.iax.auth.md5", FT_STRING,
BASE_NONE, NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_RSA_RESULT,
- {"RSA challenge result", "iax2.ies.auth.rsa", FT_STRING,
+ {"RSA challenge result", "iax2.iax.auth.rsa", FT_STRING,
BASE_NONE, NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_REFRESH,
- {"When to refresh registration", "iax2.ies.refresh", FT_INT16,
+ {"When to refresh registration", "iax2.iax.refresh", FT_INT16,
BASE_DEC,
NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_DPSTATUS,
- {"Dialplan status", "iax2.ies.dialplan_status", FT_INT16,
+ {"Dialplan status", "iax2.iax.dialplan_status", FT_UINT16,
BASE_HEX, NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_CALLNO,
- {"Call number of peer", "iax2.ies.call_no", FT_INT16, BASE_DEC,
+ {"Call number of peer", "iax2.iax.call_no", FT_INT16, BASE_DEC,
NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_CAUSE,
- {"Cause", "iax2.ies.cause", FT_STRING, BASE_NONE, NULL, 0x0, "",
+ {"Cause", "iax2.iax.cause", FT_STRING, BASE_NONE, NULL, 0x0, "",
HFILL}},
+
{&hf_IAX_IE_IAX_UNKNOWN,
- {"Unknown IAX command", "iax2.ies.iax_unknown", FT_BYTES,
+ {"Unknown IAX command", "iax2.iax.iax_unknown", FT_BYTES,
BASE_HEX, NULL,
0x0, "", HFILL}},
+
{&hf_IAX_IE_MSGCOUNT,
- {"How many messages waiting", "iax2.ies.msg_count", FT_INT16,
+ {"How many messages waiting", "iax2.iax.msg_count", FT_INT16,
BASE_DEC,
NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_AUTOANSWER,
- {"Request auto-answering", "iax2.ies.autoanswer", FT_NONE,
+ {"Request auto-answering", "iax2.iax.autoanswer", FT_NONE,
BASE_NONE,
NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_MUSICONHOLD,
- {"Request musiconhold with QUELCH", "iax2.ies.moh", FT_NONE,
+ {"Request musiconhold with QUELCH", "iax2.iax.moh", FT_NONE,
BASE_NONE,
NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_TRANSFERID,
- {"Transfer Request Identifier", "iax2.ies.transferid", FT_INT32,
+ {"Transfer Request Identifier", "iax2.iax.transferid", FT_UINT32,
BASE_HEX, NULL, 0x0, "", HFILL}},
+
{&hf_IAX_IE_RDNIS,
- {"Referring DNIS", "iax2.ies.rdnis", FT_STRING, BASE_NONE, NULL,
+ {"Referring DNIS", "iax2.iax.rdnis", FT_STRING, BASE_NONE, NULL,
0x0, "",
- HFILL}}
+ HFILL}},
+
+ {&hf_IAX_IE_DATAFORMAT,
+ {"Data call format", "iax2.iax.dataformat", FT_UINT32, BASE_HEX,
+ VALS(iax_dataformats), 0x0, "", HFILL}},
+
+ {&hf_IAX_IE_UNKNOWN_BYTE,
+ {"data", "iax2.iax.unknowndata", FT_UINT8, BASE_HEX, NULL,
+ 0x0, "Raw data for unknown IEs",
+ HFILL}},
+ {&hf_IAX_IE_UNKNOWN_I16,
+ {"data", "iax2.iax.unknowndata", FT_UINT16, BASE_HEX, NULL,
+ 0x0, "Raw data for unknown IEs",
+ HFILL}},
+ {&hf_IAX_IE_UNKNOWN_I32,
+ {"data", "iax2.iax.unknowndata", FT_UINT32, BASE_HEX, NULL,
+ 0x0, "Raw data for unknown IEs",
+ HFILL}},
+ {&hf_IAX_IE_UNKNOWN_BYTES,
+ {"data", "iax2.iax.unknowndata", FT_BYTES, BASE_NONE, NULL,
+ 0x0, "Raw data for unknown IEs",
+ HFILL}},
+
+ /* capablilites */
+ {&hf_iax2_cap_g723_1,
+ {"G.723.1 compression", "iax2.cap.g723_1", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_G723_1,
+ "G.723.1 compression", HFILL }},
+
+ {&hf_iax2_cap_gsm,
+ {"GSM compression", "iax2.cap.gsm", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_GSM,
+ "GSM compression", HFILL }},
+
+ {&hf_iax2_cap_ulaw,
+ {"Raw mu-law data (G.711)", "iax2.cap.ulaw",FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_ULAW,
+ "Raw mu-law data (G.711)", HFILL }},
+
+ {&hf_iax2_cap_alaw,
+ {"Raw A-law data (G.711)", "iax2.cap.alaw",FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_ALAW,
+ "Raw A-law data (G.711)", HFILL }},
+
+ {&hf_iax2_cap_g726,
+ {"G.726 compression", "iax2.cap.g726",FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_G726,
+ "G.726 compression", HFILL }},
+
+ {&hf_iax2_cap_adpcm,
+ {"ADPCM", "iax2.cap.adpcm", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_ADPCM,
+ "ADPCM", HFILL }},
+
+ {&hf_iax2_cap_slinear,
+ {"Raw 16-bit Signed Linear (8000 Hz) PCM", "iax2.cap.slinear",
+ FT_BOOLEAN, 32, TFS(&supported_strings), AST_FORMAT_SLINEAR,
+ "Raw 16-bit Signed Linear (8000 Hz) PCM", HFILL }},
+
+ {&hf_iax2_cap_lpc10,
+ {"LPC10, 180 samples/frame", "iax2.cap.lpc10", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_LPC10,
+ "LPC10, 180 samples/frame", HFILL }},
+
+ {&hf_iax2_cap_g729a,
+ {"G.729a Audio", "iax2.cap.g729a", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_G729A,
+ "G.729a Audio", HFILL }},
+
+ {&hf_iax2_cap_speex,
+ {"SPEEX Audio", "iax2.cap.speex", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_SPEEX,
+ "SPEEX Audio", HFILL }},
+
+ {&hf_iax2_cap_ilbc,
+ {"iLBC Free compressed Audio", "iax2.cap.ilbc", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_ILBC,
+ "iLBC Free compressed Audio", HFILL }},
+
+ {&hf_iax2_cap_jpeg,
+ {"JPEG images", "iax2.cap.jpeg", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_JPEG,
+ "JPEG images", HFILL }},
+
+ {&hf_iax2_cap_png,
+ {"PNG images", "iax2.cap.png", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_PNG,
+ "PNG images", HFILL }},
+
+ {&hf_iax2_cap_h261,
+ {"H.261 video", "iax2.cap.h261", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_H261,
+ "H.261 video", HFILL }},
+
+ {&hf_iax2_cap_h263,
+ {"H.263 video", "iax2.cap.h263", FT_BOOLEAN, 32,
+ TFS(&supported_strings), AST_FORMAT_H263,
+ "H.263 video", HFILL }}
};
static gint *ett[] = {
&ett_iax2,
- &ett_iax2_ies,
+ &ett_iax2_full_mini_subtree,
+ &ett_iax2_type,
+ &ett_iax2_ie,
&ett_iax2_codecs,
- &ett_iax2_ies_apparent_addr
+ &ett_iax2_ies_apparent_addr
};
proto_iax2 =
- proto_register_protocol ("IAX2", "Inter-Asterisk eXchange v2", "iax2");
+ proto_register_protocol ("Inter-Asterisk eXchange v2", "IAX2", "iax2");
proto_register_field_array (proto_iax2, hf, array_length (hf));
proto_register_subtree_array (ett, array_length (ett));
+ register_dissector("iax2", dissect_iax2, proto_iax2);
+
+ iax2_codec_dissector_table = register_dissector_table(
+ "iax2.codec","IAX codec number", FT_UINT32, BASE_HEX);
+ iax2_dataformat_dissector_table = register_dissector_table(
+ "iax2.dataformat","IAX dataformat number", FT_UINT32, BASE_HEX);
+
+ /* register our init routine to be called at the start of a capture,
+ to clear out our hash tables etc */
+ register_init_routine(&iax_init_protocol);
}
void
proto_reg_handoff_iax2 (void)
{
+ dissector_add("udp.port", IAX2_PORT, find_dissector("iax2"));
+ dissector_add("iax2.dataformat", AST_DATAFORMAT_V110, find_dissector("v110"));
+ data_handle = find_dissector("data");
+}
- dissector_handle_t iax2_handle = NULL;
-
- iax2_handle = create_dissector_handle (dissect_iax2, proto_iax2);
- dissector_add ("udp.port", IAX2_PORT, iax2_handle);
-}
+/*
+ * This sets up the indentation style for this file in emacs.
+ *
+ * Local Variables:
+ * c-basic-offset: 2
+ * End:
+ */
diff --git a/packet-iax2.h b/packet-iax2.h
index be2dd878e8..320698252e 100644
--- a/packet-iax2.h
+++ b/packet-iax2.h
@@ -7,7 +7,7 @@
*
* Mark Spencer <markster@linux-support.net>
*
- * $Id: packet-iax2.h,v 1.2 2004/05/15 21:26:09 guy Exp $
+ * $Id: packet-iax2.h,v 1.3 2004/06/25 06:31:46 sahlberg Exp $
*
* This program is free software, distributed under the terms of
* the GNU General Public License
@@ -112,6 +112,10 @@
#define IAX_IE_MUSICONHOLD 26 /* Request musiconhold with QUELCH -- none or string */
#define IAX_IE_TRANSFERID 27 /* Transfer Request Identifier -- int */
#define IAX_IE_RDNIS 28 /* Referring DNIS -- string */
+#define IAX_IE_PROVISIONING 29 /* Provisioning info */
+#define IAX_IE_AESPROVISIONING 30 /* AES Provisioning info */
+#define IAX_IE_DATETIME 31 /* Date/Time */
+#define IAX_IE_DATAFORMAT 255 /* Data call format -- iax_dataformat_t */
#define IAX_AUTH_PLAINTEXT (1 << 0)
#define IAX_AUTH_MD5 (1 << 1)
@@ -126,20 +130,4 @@
#define IAX_DPSTATUS_IGNOREPAT (1 << 14)
#define IAX_DPSTATUS_MATCHMORE (1 << 15)
-#define AST_FORMAT_G723_1 (1 << 0) /* G.723.1 compression */
-#define AST_FORMAT_GSM (1 << 1) /* GSM compression */
-#define AST_FORMAT_ULAW (1 << 2) /* Raw mu-law data (G.711) */
-#define AST_FORMAT_ALAW (1 << 3) /* Raw A-law data (G.711) */
-#define AST_FORMAT_G726 (1 << 4) /* ADPCM (G.726, 32kbps) */
-#define AST_FORMAT_ADPCM (1 << 5) /* ADPCM (IMA) */
-#define AST_FORMAT_SLINEAR (1 << 6) /* Raw 16-bit Signed Linear (8000 Hz) PCM */
-#define AST_FORMAT_LPC10 (1 << 7) /* LPC10, 180 samples/frame */
-#define AST_FORMAT_G729A (1 << 8) /* G.729a Audio */
-#define AST_FORMAT_SPEEX (1 << 9) /* SpeeX Free Compression */
-#define AST_FORMAT_ILBC (1 << 10) /* iLBC Free Compression */
-#define AST_FORMAT_JPEG (1 << 16) /* JPEG Images */
-#define AST_FORMAT_PNG (1 << 17) /* PNG Images */
-#define AST_FORMAT_H261 (1 << 18) /* H.261 Video */
-#define AST_FORMAT_H263 (1 << 19) /* H.263 Video */
-
#endif