Ethereal-dev: Re: [Ethereal-dev] New dissector: IAX2 (Inter-Asterisk eXchange 2) VoIP protocol

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Alastair Maw <ethereal@xxxxxxxxx>
Date: Tue, 27 Jan 2004 00:06:56 +0000
On 26/01/04 21:15, Guy Harris wrote:

It didn't compile:

    packet-iax2.c: In function `dissect_iax2':
    packet-iax2.c:438: error: dereferencing pointer to incomplete type
    packet-iax2.c:438: error: type of formal parameter 1 is incomplete
    packet-iax2.c:438: error: dereferencing pointer to incomplete type
    packet-iax2.c:155: warning: `iax_ies_type' defined but not used

I suspect "struct sockaddr_in" isn't defined; perhaps, on some OSes, one of the header files that packet-iax2.c transitive-closure-of-includes defines it, but on Mac OS X 10.3.2, I suspect none of those header files does.
[...]
if the item it sends over the wire looks like a 4.4BSD "struct sockaddr", or perhaps the same but with "a 2-byte address family code, in network byte order" instead of the 1-byte address length and 1-byte address family code if it looks like an old-style BSD "struct sockaddr", so that hosts with different "struct sockaddr_in" structures can interoperate. (Maybe it doesn't do IPv6, but perhaps it should....)

Thanks for taking the time to look at this, Guy. :)

I copied the struct out of the Asterisk channel code, which is probably overly linux-specific on this point.

On my box:

struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;         /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */



    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

Asterisk appears to be hardcoded to use the sockaddr_in struct on Linux, with IPv4.

I've therefore modified things so that the dissector assumes two bytes for the address header, two for the port and four for the IPv4 address. Unfortunately, there isn't an IAX RFC/spec to make it clear that this is definitely the right thing to do. One is apparently in the works. If Asterisk is ported to architectures other than Linux and FreeBSD this might need some further attention, but I'm not sure how I can make this any nicer for the time being. It should now at least compile properly on MacOS/X.

Please find attached a new version of the code. I have a great deal left to learn about portability, so critique and comments are more than welcome.

Best regards,

Alastair

--
Alastair Maw
Systems Analyst
Tel: +44 (0) 845 666 7778
http://www.mxtelecom.com
/*
 * packet-iax2.c
 *
 * Routines for IAX2 packet disassembly
 * By Alastair Maw <asterisk@xxxxxxxxx>
 * Copyright 2003 Alastair Maw
 *
 * 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.3 2004/01/02 16:28:18 almaw Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version. This program is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details. You
 * should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <epan/packet.h>

#include "packet-iax2.h"

#define IAX2_PORT		4569
#define PROTO_TAG_IAX2	"IAX2"

static int proto_iax2 = -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_oseqno = -1;
static int hf_iax2_iseqno = -1;
static int hf_iax2_type = -1;
static int hf_iax2_csub = -1;
static int hf_iax2_dtmf_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_IAX_IE_CALLED_NUMBER = -1;
static int hf_IAX_IE_CALLING_NUMBER = -1;
static int hf_IAX_IE_CALLING_ANI = -1;
static int hf_IAX_IE_CALLING_NAME = -1;
static int hf_IAX_IE_CALLED_CONTEXT = -1;
static int hf_IAX_IE_USERNAME = -1;
static int hf_IAX_IE_PASSWORD = -1;
static int hf_IAX_IE_CAPABILITY = -1;
static int hf_IAX_IE_FORMAT = -1;
static int hf_IAX_IE_LANGUAGE = -1;
static int hf_IAX_IE_VERSION = -1;
static int hf_IAX_IE_ADSICPE = -1;
static int hf_IAX_IE_DNID = -1;
static int hf_IAX_IE_AUTHMETHODS = -1;
static int hf_IAX_IE_CHALLENGE = -1;
static int hf_IAX_IE_MD5_RESULT = -1;
static int hf_IAX_IE_RSA_RESULT = -1;
static int hf_IAX_IE_APPARENT_ADDR = -1;
static int hf_IAX_IE_REFRESH = -1;
static int hf_IAX_IE_DPSTATUS = -1;
static int hf_IAX_IE_CALLNO = -1;
static int hf_IAX_IE_CAUSE = -1;
static int hf_IAX_IE_IAX_UNKNOWN = -1;
static int hf_IAX_IE_MSGCOUNT = -1;
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 gint ett_iax2 = -1;
static gint ett_iax2_ies = -1;
static gint ett_iax2_codecs = -1;

static const value_string iax_frame_types[] = {
  {0, "(0?)"},
  {1, "DTMF"},
  {2, "Voice"},
  {3, "Video"},
  {4, "Control"},
  {5, "NULL"},
  {6, "IAX"},
  {7, "Text"},
  {8, "Image"}
};
static const value_string iax_iax_subclasses[] = {
  {0, "(0?)"},
  {1, "NEW"},
  {2, "PING"},
  {3, "PONG"},
  {4, "ACK"},
  {5, "HANGUP"},
  {6, "REJECT"},
  {7, "ACCEPT"},
  {8, "AUTHREQ"},
  {9, "AUTHREP"},
  {10, "INVAL"},
  {11, "LAGRQ"},
  {12, "LAGRP"},
  {13, "REGREQ"},
  {14, "REGAUTH"},
  {15, "REGACK"},
  {16, "REGREJ"},
  {17, "REGREL"},
  {18, "VNAK"},
  {19, "DPREQ"},
  {20, "DPREP"},
  {21, "DIAL"},
  {22, "TXREQ"},
  {23, "TXCNT"},
  {24, "TXACC"},
  {25, "TXREADY"},
  {26, "TXREL"},
  {27, "TXREJ"},
  {28, "QUELCH"},
  {29, "UNQULCH"},
  {30, "POKE"},
  {31, "PAGE"},
  {32, "MWI"},
  {33, "UNSUPPORTED"},
  {34, "TRANSFER"}
};
static const value_string iax_cmd_subclasses[] = {
  {0, "(0?)"},
  {1, "HANGUP"},
  {2, "RING"},
  {3, "RINGING"},
  {4, "ANSWER"},
  {5, "BUSY"},
  {6, "TKOFFHK"},
  {7, "OFFHOOK"}
};

static const value_string iax_ies_type[] = {
  {IAX_IE_CALLED_NUMBER, "Number/extension being called"},
  {IAX_IE_CALLING_NUMBER, "Calling number"},
  {IAX_IE_CALLING_ANI, "Calling number ANI for billing"},
  {IAX_IE_CALLING_NAME, "Name of caller"},
  {IAX_IE_CALLED_CONTEXT, "Context for number"},
  {IAX_IE_USERNAME, "Username (peer or user) for authentication"},
  {IAX_IE_PASSWORD, "Password for authentication"},
  {IAX_IE_CAPABILITY, "Actual codec capability"},
  {IAX_IE_FORMAT, "Desired codec format"},
  {IAX_IE_LANGUAGE, "Desired language"},
  {IAX_IE_VERSION, "Protocol version"},
  {IAX_IE_ADSICPE, "CPE ADSI capability"},
  {IAX_IE_DNID, "Originally dialed DNID"},
  {IAX_IE_AUTHMETHODS, "Authentication method(s)"},
  {IAX_IE_CHALLENGE, "Challenge data for MD5/RSA"},
  {IAX_IE_MD5_RESULT, "MD5 challenge result"},
  {IAX_IE_RSA_RESULT, "RSA challenge result"},
  {IAX_IE_APPARENT_ADDR, "Apparent address of peer"},
  {IAX_IE_REFRESH, "When to refresh registration"},
  {IAX_IE_DPSTATUS, "Dialplan status"},
  {IAX_IE_CALLNO, "Call number of peer"},
  {IAX_IE_CAUSE, "Cause"},
  {IAX_IE_IAX_UNKNOWN, "Unknown IAX command"},
  {IAX_IE_MSGCOUNT, "How many messages waiting"},
  {IAX_IE_AUTOANSWER, "Request auto-answering"},
  {IAX_IE_MUSICONHOLD, "Request musiconhold with QUELCH"},
  {IAX_IE_TRANSFERID, "Transfer Request Identifier"},
  {IAX_IE_RDNIS, "Referring DNIS"}
};

static const value_string codec_types[] = {
  {AST_FORMAT_G723_1, "G.723.1 compression"},
  {AST_FORMAT_GSM, "GSM compression"},
  {AST_FORMAT_ULAW, "Raw mu-law data (G.711)"},
  {AST_FORMAT_ALAW, "Raw A-law data (G.711)"},
  {AST_FORMAT_MP3, "MPEG-2 layer 3"},
  {AST_FORMAT_ADPCM, "ADPCM (whose?)"},
  {AST_FORMAT_SLINEAR, "Raw 16-bit Signed Linear (8000 Hz) PCM"},
  {AST_FORMAT_LPC10, "LPC10, 180 samples/frame"},
  {AST_FORMAT_G729A, "G.729a Audio"}
};

static void
dissect_iax2 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
{
  char buffer[150];
  proto_tree *iax2_tree = NULL, *ies_tree = NULL, *codec_tree = NULL;
  proto_item *ti = 0, *ies_base = 0, *codec_base = 0;
  guint32 offset = 0, codecs = 0, i = 0, mask = 0, retransmission = 0;
  long addr;
  const char *data = tvb_get_ptr (tvb, offset, -1);
  struct ast_iax2_full_hdr *h;
  guint16 scallno;
  guint16 dcallno;

  if (check_col (pinfo->cinfo, COL_PROTOCOL))
    {
      col_set_str (pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_IAX2);
    }

  if (tree)
    {
      ti = proto_tree_add_item (tree, proto_iax2, tvb, offset, -1, FALSE);
      iax2_tree = proto_item_add_subtree (ti, ett_iax2);
    }

  if (g_ntohs (*data) & 0x8000)
    {
      h = (struct ast_iax2_full_hdr *) data;
      retransmission = g_ntohs (h->dcallno) & 0x8000;
      /*
       * remove the top bits for retransmission/header type detection 
       */
      scallno = g_ntohs (h->scallno) & 0x7FFF;
      dcallno = g_ntohs (h->dcallno) & 0x7FFF;

      proto_tree_add_boolean (iax2_tree, hf_iax2_retransmission, tvb,
			      offset + 2, 1, retransmission);

      proto_tree_add_uint (iax2_tree, hf_iax2_scallno, tvb, offset, 2,
			   scallno);
      proto_tree_add_uint (iax2_tree, hf_iax2_dcallno, tvb, offset + 2, 2,
			   dcallno);
      proto_tree_add_item (iax2_tree, hf_iax2_ts, tvb, offset + 4, 4, FALSE);
      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);
      proto_tree_add_item (iax2_tree, hf_iax2_type, tvb, offset + 10, 1,
			   FALSE);

      if (h->type == AST_FRAME_IAX)
	{
	  proto_tree_add_item (iax2_tree, hf_iax2_iax_csub, tvb,
			       offset + 11, 1, FALSE);
	  if (check_col (pinfo->cinfo, COL_INFO))
	    {
	      col_add_fstr (pinfo->cinfo, COL_INFO,
			    "%s %s, source call# %d, timestamp %ums",
			    val_to_str (h->type, iax_frame_types,
					"Unknown (0x%02x)"),
			    val_to_str (h->csub, iax_iax_subclasses,
					"unknown (0x%02x)"), scallno,
			    g_ntohl (h->ts));
	    }

	}
      else if (h->type == AST_FRAME_DTMF)
	{
	  proto_tree_add_item (iax2_tree, hf_iax2_dtmf_csub, tvb,
			       offset + 11, 1, FALSE);
	  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 (h->type, iax_frame_types,
					"Unknown (0x%02x)"), h->csub,
			    scallno, g_ntohl (h->ts));
	    }

	}
      else if (h->type == AST_FRAME_CONTROL)
	{
	  proto_tree_add_item (iax2_tree, hf_iax2_cmd_csub, tvb,
			       offset + 11, 1, FALSE);
	  if (check_col (pinfo->cinfo, COL_INFO))
	    {
	      col_add_fstr (pinfo->cinfo, COL_INFO,
			    "%s %s, source call# %d, timestamp %ums",
			    val_to_str (h->type, iax_frame_types,
					"Unknown (0x%02x)"),
			    val_to_str (h->csub, iax_cmd_subclasses,
					"unknown (0x%02x)"), scallno,
			    g_ntohl (h->ts));
	    }

	}
      else if (h->type == AST_FRAME_VOICE)
	{
	  proto_tree_add_item (iax2_tree, hf_iax2_voice_csub, tvb,
			       offset + 11, 1, FALSE);
	  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 (h->type, iax_frame_types,
					"Unknown (0x%02x)"),
			    val_to_str (h->csub, codec_types,
					"unknown (0x%02x)"), scallno,
			    g_ntohl (h->ts));
	    }
	}
      else
	{
	  proto_tree_add_item (iax2_tree, hf_iax2_csub, tvb, offset + 11,
			       1, FALSE);
	  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 (h->type, iax_frame_types,
					"Unknown (0x%02x)"), h->csub,
			    scallno, g_ntohl (h->ts));
	    }
	}
      offset += 12;

      if (h->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);
	}

      while (h->type == AST_FRAME_IAX && offset < tvb_reported_length (tvb))
	{
	  int ies_type = data[offset];
	  int ies_len = data[offset + 1];
	  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);
	      break;
	    case IAX_IE_CALLING_NUMBER:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_CALLING_NUMBER,
				   tvb, offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_CALLING_ANI:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_CALLING_ANI, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_CALLING_NAME:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_CALLING_NAME, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_CALLED_CONTEXT:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_CALLED_CONTEXT,
				   tvb, offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_USERNAME:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_USERNAME, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_PASSWORD:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_PASSWORD, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_LANGUAGE:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_LANGUAGE, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_DNID:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_DNID, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_CHALLENGE:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_CHALLENGE, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_MD5_RESULT:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_MD5_RESULT, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_RSA_RESULT:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_RSA_RESULT, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_RDNIS:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_RDNIS, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_CAPABILITY:
	      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"));
		}

	      break;
	    case IAX_IE_FORMAT:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_FORMAT, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_VERSION:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_VERSION, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_ADSICPE:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_ADSICPE, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_AUTHMETHODS:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_AUTHMETHODS, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_APPARENT_ADDR:
	      addr = tvb_get_ntohl (tvb, offset + 6);
		  ti = proto_tree_add_ipv4 (ies_tree, hf_IAX_IE_APPARENT_ADDR, tvb, offset + 6, 4, addr);
		  proto_item_append_text( ti, ", Port: %d", tvb_get_ntohs(tvb, offset + 2));
	      break;
	    case IAX_IE_REFRESH:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_REFRESH, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_DPSTATUS:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_DPSTATUS, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_CALLNO:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_CALLNO, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_CAUSE:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_CAUSE, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_IAX_UNKNOWN:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_IAX_UNKNOWN, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_MSGCOUNT:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_MSGCOUNT, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_AUTOANSWER:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_AUTOANSWER, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_MUSICONHOLD:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_MUSICONHOLD, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    case IAX_IE_TRANSFERID:
	      proto_tree_add_item (ies_tree, hf_IAX_IE_TRANSFERID, tvb,
				   offset + 2, ies_len, FALSE);
	      break;
	    }
	  offset += ies_len + 2;
	}

    }
  else
    {
      struct ast_iax2_mini_hdr *h = (struct ast_iax2_mini_hdr *) data;
      if (check_col (pinfo->cinfo, COL_INFO))
	{
	  col_add_fstr (pinfo->cinfo, COL_INFO,
			"Voice frame (mini header), source call# %d, timestamp %ums",
			g_ntohs (h->callno) & 0x7FFF, g_ntohs (h->ts));
	}
      /*
       * remove the top bits for retransmission/header type detection 
       */
      proto_tree_add_uint (iax2_tree, hf_iax2_scallno, tvb, offset, 2,
			   g_ntohs (h->callno));
      proto_tree_add_uint (iax2_tree, hf_iax2_minits, tvb, offset + 2, 2,
			   g_ntohs (h->ts));
      proto_tree_add_item (iax2_tree, hf_iax2_voicedata, tvb, offset + 4,
			   -1, FALSE);
    }

}				/* dissect_iax2 */

void
proto_register_iax2 (void)
{
  static hf_register_info hf[] = {
    {&hf_iax2_retransmission,
     {"Retransmission", "iax2.retransmission", FT_BOOLEAN, BASE_NONE,
      NULL,
      0x0, "", HFILL}},
    {&hf_iax2_scallno,
     {"Source call", "iax2.src_call", FT_UINT16, BASE_DEC, NULL, 0x0,
      "",
      HFILL}},
    {&hf_iax2_dcallno,
     {"Destination call", "iax2.dst_call", FT_UINT16, BASE_DEC, NULL,
      0x0, "",
      HFILL}},
    {&hf_iax2_ts,
     {"Timestamp", "iax2.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
      "",
      HFILL}},
    {&hf_iax2_minits,
     {"Timestamp", "iax2.timestamp", FT_UINT16, BASE_DEC, NULL, 0x0,
      "",
      HFILL}},
    {&hf_iax2_voicedata,
     {"Voice data", "iax2.voicedata", FT_BYTES, BASE_NONE, NULL, 0x0,
      "",
      HFILL}},
    {&hf_iax2_oseqno,
     {"Outbound seq.no.", "iax2.oseqno", FT_UINT16, BASE_DEC, NULL,
      0x0, "",
      HFILL}},
    {&hf_iax2_iseqno,
     {"Inbound seq.no.", "iax2.iseqno", FT_UINT16, BASE_DEC, NULL, 0x0,
      "",
      HFILL}},
    {&hf_iax2_type,
     {"Type", "iax2.type", FT_INT8, BASE_DEC, VALS (iax_frame_types),
      0x0, "",
      HFILL}},
    {&hf_iax2_csub,
     {"Sub-class", "iax2.subclass", FT_UINT8, BASE_DEC, NULL, 0x0, "",
      HFILL}},
    {&hf_iax2_dtmf_csub,
     {"DTMF digit", "iax2.dtmf.digit", FT_UINT8, BASE_DEC, NULL, 0x0,
      "",
      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}},
    {&hf_iax2_iax_csub,
     {"IAX type", "iax2.iax", 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_CALLED_NUMBER,
     {"Number/extension being called", "iax2.ies.called_number",
      FT_STRING,
      BASE_NONE, NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_CALLING_NUMBER,
     {"Calling number", "iax2.ies.calling_number", FT_STRING,
      BASE_NONE, NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_CALLING_ANI,
     {"Calling number ANI for billing", "iax2.ies.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,
      NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_CALLED_CONTEXT,
     {"Context for number", "iax2.ies.called_context", FT_STRING,
      BASE_NONE,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_USERNAME,
     {"Username (peer or user) for authentication",
      "iax2.ies.username",
      FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_PASSWORD,
     {"Password for authentication", "iax2.ies.password", FT_STRING,
      BASE_NONE, NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_CAPABILITY,
     {"Actual codec capability", "iax2.ies.capability", FT_UINT32,
      BASE_HEX,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_FORMAT,
     {"Desired codec format", "iax2.ies.format", FT_UINT32, BASE_HEX,
      VALS (codec_types), 0x0, "", HFILL}},
    {&hf_IAX_IE_LANGUAGE,
     {"Desired language", "iax2.ies.language", FT_STRING, BASE_NONE,
      NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_VERSION,
     {"Protocol version", "iax2.ies.version", FT_INT16, BASE_HEX, NULL,
      0x0,
      "", HFILL}},
    {&hf_IAX_IE_ADSICPE,
     {"CPE ADSI capability", "iax2.ies.cpe_adsi", FT_INT16, BASE_HEX,
      NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_DNID,
     {"Originally dialed DNID", "iax2.ies.dnid", FT_STRING, BASE_NONE,
      NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_AUTHMETHODS,
     {"Authentication method(s)", "iax2.ies.auth.methods", FT_INT16,
      BASE_HEX,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_CHALLENGE,
     {"Challenge data for MD5/RSA", "iax2.ies.auth.challenge",
      FT_STRING,
      BASE_NONE, NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_MD5_RESULT,
     {"MD5 challenge result", "iax2.ies.auth.md5", FT_STRING,
      BASE_NONE, NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_RSA_RESULT,
     {"RSA challenge result", "iax2.ies.auth.rsa", FT_STRING,
      BASE_NONE, NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_APPARENT_ADDR,
     {"Apparent address of peer", "iax2.ies.address", FT_STRING,
      BASE_NONE,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_REFRESH,
     {"When to refresh registration", "iax2.ies.refresh", FT_INT16,
      BASE_DEC,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_DPSTATUS,
     {"Dialplan status", "iax2.ies.dialplan_status", FT_INT16,
      BASE_HEX, NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_CALLNO,
     {"Call number of peer", "iax2.ies.call_no", FT_INT16, BASE_DEC,
      NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_CAUSE,
     {"Cause", "iax2.ies.cause", FT_STRING, BASE_NONE, NULL, 0x0, "",
      HFILL}},
    {&hf_IAX_IE_IAX_UNKNOWN,
     {"Unknown IAX command", "iax2.ies.iax_unknown", FT_BYTES,
      BASE_HEX, NULL,
      0x0, "", HFILL}},
    {&hf_IAX_IE_MSGCOUNT,
     {"How many messages waiting", "iax2.ies.msg_count", FT_INT16,
      BASE_DEC,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_AUTOANSWER,
     {"Request auto-answering", "iax2.ies.autoanswer", FT_NONE,
      BASE_NONE,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_MUSICONHOLD,
     {"Request musiconhold with QUELCH", "iax2.ies.moh", FT_NONE,
      BASE_NONE,
      NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_TRANSFERID,
     {"Transfer Request Identifier", "iax2.ies.transferid", FT_INT32,
      BASE_HEX, NULL, 0x0, "", HFILL}},
    {&hf_IAX_IE_RDNIS,
     {"Referring DNIS", "iax2.ies.rdnis", FT_STRING, BASE_NONE, NULL,
      0x0, "",
      HFILL}}
  };

  static gint *ett[] = {
    &ett_iax2,
    &ett_iax2_ies,
    &ett_iax2_codecs
  };

  proto_iax2 =
    proto_register_protocol ("IAX2", "Inter-Asterisk eXchange v2", "iax2");
  proto_register_field_array (proto_iax2, hf, array_length (hf));
  proto_register_subtree_array (ett, array_length (ett));

}

void
proto_reg_handoff_iax2 (void)
{

  dissector_handle_t iax2_handle = NULL;

  iax2_handle = create_dissector_handle (dissect_iax2, proto_iax2);

  dissector_add ("udp.port", IAX2_PORT, iax2_handle);
}
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * Implementation of Inter-Asterisk eXchange
 * 
 * Copyright (C) 2003, Digium
 *
 * Mark Spencer <markster@xxxxxxxxxxxxxxxxx>
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License
 */
 
#ifndef _PACKET_IAX2_H
#define _PACKET_IAX2_H

/* Max version of IAX protocol we support */
#define IAX_PROTO_VERSION 2

#define IAX_MAX_CALLS 32768

#define IAX_FLAG_FULL		0x8000

#define IAX_FLAG_RETRANS	0x8000

#define IAX_FLAG_SC_LOG		0x80

#define IAX_MAX_SHIFT		0x1F

#define IAX_WINDOW			64

#define AST_FRAME_DTMF      1       /* A DTMF digit, subclass is the digit */
#define AST_FRAME_VOICE     2       /* Voice data, subclass is AST_FORMAT_* */
#define AST_FRAME_VIDEO     3       /* Video frame, maybe?? :) */
#define AST_FRAME_CONTROL   4       /* A control frame, subclass is AST_CONTROL_* */
#define AST_FRAME_NULL      5       /* An empty, useless frame */
#define AST_FRAME_IAX       6       /* Inter Aterisk Exchange private frame type */
#define AST_FRAME_TEXT      7       /* Text messages */
#define AST_FRAME_IMAGE     8       /* Image Frames */
#define AST_FRAME_HTML      9       /* HTML Frames */

/* Subclass for AST_FRAME_IAX */
#define IAX_COMMAND_NEW		1
#define IAX_COMMAND_PING	2
#define IAX_COMMAND_PONG	3
#define IAX_COMMAND_ACK		4
#define IAX_COMMAND_HANGUP	5
#define IAX_COMMAND_REJECT	6
#define IAX_COMMAND_ACCEPT	7
#define IAX_COMMAND_AUTHREQ	8
#define IAX_COMMAND_AUTHREP	9
#define IAX_COMMAND_INVAL	10
#define IAX_COMMAND_LAGRQ	11
#define IAX_COMMAND_LAGRP	12
#define IAX_COMMAND_REGREQ	13	/* Registration request */
#define IAX_COMMAND_REGAUTH	14	/* Registration authentication required */
#define IAX_COMMAND_REGACK	15	/* Registration accepted */
#define IAX_COMMAND_REGREJ	16	/* Registration rejected */
#define IAX_COMMAND_REGREL	17	/* Force release of registration */
#define IAX_COMMAND_VNAK	18	/* If we receive voice before valid first voice frame, send this */
#define IAX_COMMAND_DPREQ	19	/* Request status of a dialplan entry */
#define IAX_COMMAND_DPREP	20	/* Request status of a dialplan entry */
#define IAX_COMMAND_DIAL	21	/* Request a dial on channel brought up TBD */
#define IAX_COMMAND_TXREQ	22	/* Transfer Request */
#define IAX_COMMAND_TXCNT	23	/* Transfer Connect */
#define IAX_COMMAND_TXACC	24	/* Transfer Accepted */
#define IAX_COMMAND_TXREADY	25	/* Transfer ready */
#define IAX_COMMAND_TXREL	26	/* Transfer release */
#define IAX_COMMAND_TXREJ	27	/* Transfer reject */
#define IAX_COMMAND_QUELCH	28	/* Stop audio/video transmission */
#define IAX_COMMAND_UNQUELCH 29	/* Resume audio/video transmission */
#define IAX_COMMAND_POKE    30  /* Like ping, but does not require an open connection */
#define IAX_COMMAND_PAGE	31	/* Paging description */
#define IAX_COMMAND_MWI	32	/* Stand-alone message waiting indicator */
#define IAX_COMMAND_UNSUPPORT	33	/* Unsupported message received */
#define IAX_COMMAND_TRANSFER	34	/* Request remote transfer */

#define IAX_DEFAULT_REG_EXPIRE  60	/* By default require re-registration once per minute */

#define IAX_LINGER_TIMEOUT		10 /* How long to wait before closing bridged call */

#define IAX_DEFAULT_PORTNO		4569

/* IAX Information elements */
#define IAX_IE_CALLED_NUMBER		1		/* Number/extension being called - string */
#define IAX_IE_CALLING_NUMBER		2		/* Calling number - string */
#define IAX_IE_CALLING_ANI			3		/* Calling number ANI for billing  - string */
#define IAX_IE_CALLING_NAME			4		/* Name of caller - string */
#define IAX_IE_CALLED_CONTEXT		5		/* Context for number - string */
#define IAX_IE_USERNAME				6		/* Username (peer or user) for authentication - string */
#define IAX_IE_PASSWORD				7		/* Password for authentication - string */
#define IAX_IE_CAPABILITY			8		/* Actual codec capability - unsigned int */
#define IAX_IE_FORMAT				9		/* Desired codec format - unsigned int */
#define IAX_IE_LANGUAGE				10		/* Desired language - string */
#define IAX_IE_VERSION				11		/* Protocol version - short */
#define IAX_IE_ADSICPE				12		/* CPE ADSI capability - short */
#define IAX_IE_DNID					13		/* Originally dialed DNID - string */
#define IAX_IE_AUTHMETHODS			14		/* Authentication method(s) - short */
#define IAX_IE_CHALLENGE			15		/* Challenge data for MD5/RSA - string */
#define IAX_IE_MD5_RESULT			16		/* MD5 challenge result - string */
#define IAX_IE_RSA_RESULT			17		/* RSA challenge result - string */
#define IAX_IE_APPARENT_ADDR		18		/* Apparent address of peer - struct sockaddr_in */
#define IAX_IE_REFRESH				19		/* When to refresh registration - short */
#define IAX_IE_DPSTATUS				20		/* Dialplan status - short */
#define IAX_IE_CALLNO				21		/* Call number of peer - short */
#define IAX_IE_CAUSE				22		/* Cause - string */
#define IAX_IE_IAX_UNKNOWN			23		/* Unknown IAX command - byte */
#define IAX_IE_MSGCOUNT				24		/* How many messages waiting - short */
#define IAX_IE_AUTOANSWER			25		/* Request auto-answering -- none */
#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_AUTH_PLAINTEXT			(1 << 0)
#define IAX_AUTH_MD5				(1 << 1)
#define IAX_AUTH_RSA				(1 << 2)

#define IAX_META_TRUNK				1		/* Trunk meta-message */
#define IAX_META_VIDEO				2		/* Video frame */

#define IAX_DPSTATUS_EXISTS			(1 << 0)
#define IAX_DPSTATUS_CANEXIST		(1 << 1)
#define IAX_DPSTATUS_NONEXISTANT	(1 << 2)
#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_MP3      (1 << 4)    /* MPEG-2 layer 3 */
#define AST_FORMAT_ADPCM    (1 << 5)    /* ADPCM (whose?) */
#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 */

/* Full frames are always delivered reliably */
struct ast_iax2_full_hdr {
	unsigned short scallno;	/* Source call number -- high bit must be 1 */
	unsigned short dcallno;	/* Destination call number -- high bit is 1 if retransmission */
	unsigned int ts;		/* 32-bit timestamp in milliseconds (from 1st transmission) */
	unsigned char oseqno;	/* Packet number (outgoing) */
	unsigned char iseqno;	/* Packet number (next incoming expected) */
	char type;				/* Frame type */
	unsigned char csub;		/* Compressed subclass */
	unsigned char iedata[0];
} __attribute__ ((__packed__));

/* Mini header is used only for voice frames -- delivered unreliably */
struct ast_iax2_mini_hdr {
	unsigned short callno;	/* Source call number -- high bit must be 0, rest must be non-zero */
	unsigned short ts;		/* 16-bit Timestamp (high 16 bits from last ast_iax2_full_hdr) */
							/* Frametype implicitly VOICE_FRAME */
							/* subclass implicit from last ast_iax2_full_hdr */
	unsigned char data[0];
} __attribute__ ((__packed__));

struct ast_iax2_meta_hdr {
	unsigned short zeros;			/* Zeros field -- must be zero */
	unsigned char metacmd;			/* Meta command */
	unsigned char cmddata;			/* Command Data */
	unsigned char data[0];
} __attribute__ ((__packed__));

struct ast_iax2_meta_trunk_hdr {
	unsigned int ts;				/* 32-bit timestamp for all messages */
	unsigned char data[0];
} __attribute__ ((__packed__));

struct ast_iax2_meta_trunk_entry {
	unsigned short callno;			/* Call number */
	unsigned short len;				/* Length of data for this callno */
} __attribute__ ((__packed__));

#endif
Index: Makefile.am
===================================================================
RCS file: /cvsroot/ethereal/Makefile.am,v
retrieving revision 1.682
diff -u -u -r1.682 Makefile.am
--- Makefile.am	30 Dec 2003 17:14:14 -0000	1.682
+++ Makefile.am	2 Jan 2004 18:26:12 -0000
@@ -256,6 +256,7 @@
 	packet-http.c  \
 	packet-hyperscsi.c \
 	packet-iapp.c  \
+	packet-iax2.c \
 	packet-ib.c  \
 	packet-icap.c  \
 	packet-icmpv6.c\
Index: Makefile.nmake
===================================================================
RCS file: /cvsroot/ethereal/Makefile.nmake,v
retrieving revision 1.382
diff -u -u -r1.382 Makefile.nmake
--- Makefile.nmake	30 Dec 2003 22:18:03 -0000	1.382
+++ Makefile.nmake	2 Jan 2004 18:26:12 -0000
@@ -196,6 +196,7 @@
 	packet-http.c  \
 	packet-hyperscsi.c \
 	packet-iapp.c  \
+	packet-iax2.c  \
 	packet-ib.c  \
 	packet-icap.c  \
 	packet-icmpv6.c\