summaryrefslogtreecommitdiff
path: root/packet-iax2.c
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 /packet-iax2.c
parent79d7a7cba6f8c81803ed818df68791b9ad643280 (diff)
downloadwireshark-e790073f3afed22dc5084a37424e35ab14412400.tar.gz
Updates from Richard v d Hoff
IAX2 updates and a CRC16 routine svn path=/trunk/; revision=11233
Diffstat (limited to 'packet-iax2.c')
-rw-r--r--packet-iax2.c1638
1 files changed, 1391 insertions, 247 deletions
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:
+ */