4 * Routines for IAX2 packet disassembly
5 * By Alastair Maw <asterisk@almaw.com>
6 * Copyright 2003 Alastair Maw
8 * IAX2 is a VoIP protocol for the open source PBX Asterisk. Please see
9 * http://www.asterisk.org for more information; see
11 * http://www.ietf.org/internet-drafts/draft-guy-iax-04.txt
13 * for the current Internet-Draft for IAX2.
17 * Wireshark - Network traffic analyzer
18 * By Gerald Combs <gerald@wireshark.org>
19 * Copyright 1998 Gerald Combs
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version 2
24 * of the License, or (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #include <epan/circuit.h>
45 #include <epan/packet.h>
46 #include <epan/to_str.h>
47 #include <epan/emem.h>
48 #include <epan/reassemble.h>
49 #include <epan/aftypes.h>
51 #include <epan/tap-voip.h>
53 #include "packet-iax2.h"
54 #include <epan/iax2_codec_type.h>
56 #define IAX2_PORT 4569
57 #define PROTO_TAG_IAX2 "IAX2"
59 /* enough to hold any address in an address_t */
60 #define MAX_ADDRESS 16
62 /* the maximum number of transfers (of each end) we can deal with per call,
64 #define IAX_MAX_TRANSFERS 2
66 /* #define DEBUG_HASHING */
67 /* #define DEBUG_DESEGMENT */
69 /* Wireshark ID of the IAX2 protocol */
70 static int proto_iax2 = -1;
73 static int iax2_tap = -1;
75 /* protocol tap info */
76 static iax2_info_t ii_arr[1];
77 static iax2_info_t *iax2_info = ii_arr;
79 /* The following hf_* variables are used to hold the wireshark IDs of
80 * our header fields; they are filled out when we call
81 * proto_register_field_array() in proto_register_iax2()
83 static int hf_iax2_packet_type = -1;
84 static int hf_iax2_retransmission = -1;
85 static int hf_iax2_callno = -1;
86 static int hf_iax2_scallno = -1;
87 static int hf_iax2_dcallno = -1;
88 static int hf_iax2_ts = -1;
89 static int hf_iax2_minits = -1;
90 static int hf_iax2_minividts = -1;
91 static int hf_iax2_absts = -1;
92 static int hf_iax2_lateness = -1;
93 static int hf_iax2_minividmarker = -1;
94 static int hf_iax2_oseqno = -1;
95 static int hf_iax2_iseqno = -1;
96 static int hf_iax2_type = -1;
97 static int hf_iax2_csub = -1;
98 static int hf_iax2_dtmf_csub = -1;
99 static int hf_iax2_cmd_csub = -1;
100 static int hf_iax2_iax_csub = -1;
101 static int hf_iax2_voice_csub = -1;
102 static int hf_iax2_voice_codec = -1;
103 static int hf_iax2_video_csub = -1;
104 static int hf_iax2_video_codec = -1;
105 static int hf_iax2_marker = -1;
106 static int hf_iax2_modem_csub = -1;
108 static int hf_iax2_cap_g723_1 = -1;
109 static int hf_iax2_cap_gsm = -1;
110 static int hf_iax2_cap_ulaw = -1;
111 static int hf_iax2_cap_alaw = -1;
112 static int hf_iax2_cap_g726 = -1;
113 static int hf_iax2_cap_adpcm = -1;
114 static int hf_iax2_cap_slinear = -1;
115 static int hf_iax2_cap_lpc10 = -1;
116 static int hf_iax2_cap_g729a = -1;
117 static int hf_iax2_cap_speex = -1;
118 static int hf_iax2_cap_ilbc = -1;
119 static int hf_iax2_cap_jpeg = -1;
120 static int hf_iax2_cap_png = -1;
121 static int hf_iax2_cap_h261 = -1;
122 static int hf_iax2_cap_h263 = -1;
124 static int hf_iax2_fragments = -1;
125 static int hf_iax2_fragment = -1;
126 static int hf_iax2_fragment_overlap = -1;
127 static int hf_iax2_fragment_overlap_conflict = -1;
128 static int hf_iax2_fragment_multiple_tails = -1;
129 static int hf_iax2_fragment_too_long_fragment = -1;
130 static int hf_iax2_fragment_error = -1;
131 static int hf_iax2_reassembled_in = -1;
134 /* hf_iax2_ies is an array of header fields, one per potential Information
135 * Element. It's done this way (rather than having separate variables for each
136 * IE) to make the dissection of information elements clearer and more
139 * To add the ability to dissect a new information element, just add an
140 * appropriate entry to hf[] in proto_register_iax2(); dissect_ies() will then
141 * pick it up automatically.
143 static int hf_iax2_ies[256];
144 static int hf_iax2_ie_datetime = -1;
145 static int hf_IAX_IE_APPARENTADDR_SINFAMILY = -1;
146 static int hf_IAX_IE_APPARENTADDR_SINPORT = -1;
147 static int hf_IAX_IE_APPARENTADDR_SINADDR = -1;
148 static int hf_IAX_IE_UNKNOWN_BYTE = -1;
149 static int hf_IAX_IE_UNKNOWN_I16 = -1;
150 static int hf_IAX_IE_UNKNOWN_I32 = -1;
151 static int hf_IAX_IE_UNKNOWN_BYTES = -1;
153 /* These are the ids of the subtrees that we may be creating */
154 static gint ett_iax2 = -1;
155 static gint ett_iax2_full_mini_subtree = -1;
156 static gint ett_iax2_type = -1; /* Frame-type specific subtree */
157 static gint ett_iax2_ie = -1; /* single IE */
158 static gint ett_iax2_codecs = -1; /* capabilities IE */
159 static gint ett_iax2_ies_apparent_addr = -1; /* apparent address IE */
160 static gint ett_iax2_fragment = -1;
161 static gint ett_iax2_fragments = -1;
163 static const fragment_items iax2_fragment_items = {
168 &hf_iax2_fragment_overlap,
169 &hf_iax2_fragment_overlap_conflict,
170 &hf_iax2_fragment_multiple_tails,
171 &hf_iax2_fragment_too_long_fragment,
172 &hf_iax2_fragment_error,
173 &hf_iax2_reassembled_in,
177 static dissector_handle_t data_handle;
179 /* data-call subdissectors, AST_DATAFORMAT_* */
180 static dissector_table_t iax2_dataformat_dissector_table;
181 /* voice/video call subdissectors, AST_FORMAT_* */
182 static dissector_table_t iax2_codec_dissector_table;
184 /* IAX2 Full-frame types */
185 static const value_string iax_frame_types[] = {
187 {AST_FRAME_DTMF_END, "DTMF End"},
188 {AST_FRAME_VOICE, "Voice"},
189 {AST_FRAME_VIDEO, "Video"},
190 {AST_FRAME_CONTROL, "Control"},
191 {AST_FRAME_NULL, "NULL"},
192 {AST_FRAME_IAX, "IAX"},
193 {AST_FRAME_TEXT, "Text"},
194 {AST_FRAME_IMAGE, "Image"},
195 {AST_FRAME_HTML, "HTML"},
196 {AST_FRAME_CNG, "Comfort Noise"},
197 {AST_FRAME_MODEM, "Modem"},
198 {AST_FRAME_DTMF_BEGIN, "DTMF Begin"},
202 /* Subclasses for IAX packets */
203 static const value_string iax_iax_subclasses[] = {
245 /* Subclassess for Control packets */
246 static const value_string iax_cmd_subclasses[] = {
255 {0xFF, "stop sounds"}, /* sent by app_dial, and not much else */
259 /* IAX2 to tap-voip call state mapping */
260 static const voip_call_state tap_cmd_voip_state[] = {
262 VOIP_COMPLETED, /*HANGUP*/
263 VOIP_RINGING, /*RING*/
264 VOIP_RINGING, /*RINGING*/
265 VOIP_IN_CALL, /*ANSWER*/
266 VOIP_REJECTED, /*BUSY*/
267 VOIP_UNKNOWN, /*TKOFFHK*/
268 VOIP_UNKNOWN /*OFFHOOK*/
272 /* Subclassess for Modem packets */
273 static const value_string iax_modem_subclasses[] = {
280 /* Information elements */
281 static const value_string iax_ies_type[] = {
282 {IAX_IE_CALLED_NUMBER, "Number/extension being called"},
283 {IAX_IE_CALLING_NUMBER, "Calling number"},
284 {IAX_IE_CALLING_ANI, "Calling number ANI for billing"},
285 {IAX_IE_CALLING_NAME, "Name of caller"},
286 {IAX_IE_CALLED_CONTEXT, "Context for number"},
287 {IAX_IE_USERNAME, "Username (peer or user) for authentication"},
288 {IAX_IE_PASSWORD, "Password for authentication"},
289 {IAX_IE_CAPABILITY, "Actual codec capability"},
290 {IAX_IE_FORMAT, "Desired codec format"},
291 {IAX_IE_LANGUAGE, "Desired language"},
292 {IAX_IE_VERSION, "Protocol version"},
293 {IAX_IE_ADSICPE, "CPE ADSI capability"},
294 {IAX_IE_DNID, "Originally dialed DNID"},
295 {IAX_IE_AUTHMETHODS, "Authentication method(s)"},
296 {IAX_IE_CHALLENGE, "Challenge data for MD5/RSA"},
297 {IAX_IE_MD5_RESULT, "MD5 challenge result"},
298 {IAX_IE_RSA_RESULT, "RSA challenge result"},
299 {IAX_IE_APPARENT_ADDR, "Apparent address of peer"},
300 {IAX_IE_REFRESH, "When to refresh registration"},
301 {IAX_IE_DPSTATUS, "Dialplan status"},
302 {IAX_IE_CALLNO, "Call number of peer"},
303 {IAX_IE_CAUSE, "Cause"},
304 {IAX_IE_IAX_UNKNOWN, "Unknown IAX command"},
305 {IAX_IE_MSGCOUNT, "How many messages waiting"},
306 {IAX_IE_AUTOANSWER, "Request auto-answering"},
307 {IAX_IE_MUSICONHOLD, "Request musiconhold with QUELCH"},
308 {IAX_IE_TRANSFERID, "Transfer Request Identifier"},
309 {IAX_IE_RDNIS, "Referring DNIS"},
310 {IAX_IE_PROVISIONING, "Provisioning info"},
311 {IAX_IE_AESPROVISIONING, "AES Provisioning info"},
312 {IAX_IE_DATETIME,"Date/Time"},
313 {IAX_IE_DEVICETYPE, "Device type"},
314 {IAX_IE_SERVICEIDENT, "Service Identifier"},
315 {IAX_IE_FIRMWAREVER, "Firmware revision"},
316 {IAX_IE_FWBLOCKDESC, "Firmware block description"},
317 {IAX_IE_FWBLOCKDATA, "Firmware block of data"},
318 {IAX_IE_PROVVER, "Provisioning version"},
319 {IAX_IE_CALLINGPRES, "Calling presentation"},
320 {IAX_IE_CALLINGTON, "Calling type of number"},
321 {IAX_IE_CALLINGTNS, "Calling transit network select"},
322 {IAX_IE_SAMPLINGRATE, "Supported sampling rates"},
323 {IAX_IE_CAUSECODE, "Hangup cause"},
324 {IAX_IE_ENCRYPTION, "Encryption format"},
325 {IAX_IE_ENCKEY, "Raw encryption key"},
326 {IAX_IE_CODEC_PREFS, "Codec preferences"},
327 {IAX_IE_RR_JITTER, "Received jitter"},
328 {IAX_IE_RR_LOSS, "Received loss"},
329 {IAX_IE_RR_PKTS, "Received frames"},
330 {IAX_IE_RR_DELAY, "Max playout delay in ms for received frames"},
331 {IAX_IE_RR_DROPPED, "Dropped frames"},
332 {IAX_IE_RR_OOO, "Frames received out of order"},
333 {IAX_IE_DATAFORMAT, "Data call format"},
337 static const value_string codec_types[] = {
338 {AST_FORMAT_G723_1, "G.723.1 compression"},
339 {AST_FORMAT_GSM, "GSM compression"},
340 {AST_FORMAT_ULAW, "Raw mu-law data (G.711)"},
341 {AST_FORMAT_ALAW, "Raw A-law data (G.711)"},
342 {AST_FORMAT_G726, "ADPCM (G.726, 32kbps)"},
343 {AST_FORMAT_ADPCM, "ADPCM (IMA)"},
344 {AST_FORMAT_SLINEAR, "Raw 16-bit Signed Linear (8000 Hz) PCM"},
345 {AST_FORMAT_LPC10, "LPC10, 180 samples/frame"},
346 {AST_FORMAT_G729A, "G.729a Audio"},
347 {AST_FORMAT_SPEEX, "SpeeX Free Compression"},
348 {AST_FORMAT_ILBC, "iLBC Free Compression"},
349 {AST_FORMAT_JPEG, "JPEG Images"},
350 {AST_FORMAT_PNG, "PNG Images"},
351 {AST_FORMAT_H261, "H.261 Video"},
352 {AST_FORMAT_H263, "H.263 Video"},
356 static const value_string iax_dataformats[] = {
357 {AST_DATAFORMAT_NULL, "N/A (analogue call?)"},
358 {AST_DATAFORMAT_V110, "ITU-T V.110 rate adaption"},
359 {AST_DATAFORMAT_H223_H245,"ITU-T H.223/H.245"},
364 static const value_string iax_packet_types[] = {
365 {IAX2_FULL_PACKET, "Full packet"},
366 {IAX2_MINI_VOICE_PACKET, "Mini voice packet"},
367 {IAX2_MINI_VIDEO_PACKET, "Mini video packet"},
368 {IAX2_META_PACKET, "Meta packet"},
372 static const value_string iax_causecodes[] = {
373 {AST_CAUSE_UNALLOCATED, "Unallocated"},
374 {AST_CAUSE_NO_ROUTE_TRANSIT_NET, "No route transit net"},
375 {AST_CAUSE_NO_ROUTE_DESTINATION, "No route to destination"},
376 {AST_CAUSE_CHANNEL_UNACCEPTABLE, "Channel unacceptable"},
377 {AST_CAUSE_CALL_AWARDED_DELIVERED, "Call awarded delivered"},
378 {AST_CAUSE_NORMAL_CLEARING, "Normal clearing"},
379 {AST_CAUSE_USER_BUSY, "User busy"},
380 {AST_CAUSE_NO_USER_RESPONSE, "No user response"},
381 {AST_CAUSE_NO_ANSWER, "No answer"},
382 {AST_CAUSE_CALL_REJECTED, "Call rejected"},
383 {AST_CAUSE_NUMBER_CHANGED, "Number changed"},
384 {AST_CAUSE_DESTINATION_OUT_OF_ORDER, "Destination out of order"},
385 {AST_CAUSE_INVALID_NUMBER_FORMAT, "Invalid number format"},
386 {AST_CAUSE_FACILITY_REJECTED, "Facility rejected"},
387 {AST_CAUSE_RESPONSE_TO_STATUS_ENQUIRY, "Response to status inquiry"},
388 {AST_CAUSE_NORMAL_UNSPECIFIED, "Normal unspecified"},
389 {AST_CAUSE_NORMAL_CIRCUIT_CONGESTION, "Normal circuit congestion"},
390 {AST_CAUSE_NETWORK_OUT_OF_ORDER, "Network out of order"},
391 {AST_CAUSE_NORMAL_TEMPORARY_FAILURE, "Normal temporary failure"},
392 {AST_CAUSE_SWITCH_CONGESTION, "Switch congestion"},
393 {AST_CAUSE_ACCESS_INFO_DISCARDED, "Access info discarded"},
394 {AST_CAUSE_REQUESTED_CHAN_UNAVAIL, "Requested channel unavailable"},
395 {AST_CAUSE_PRE_EMPTED, "Preempted"},
396 {AST_CAUSE_FACILITY_NOT_SUBSCRIBED, "Facility not subscribed"},
397 {AST_CAUSE_OUTGOING_CALL_BARRED, "Outgoing call barred"},
398 {AST_CAUSE_INCOMING_CALL_BARRED, "Incoming call barred"},
399 {AST_CAUSE_BEARERCAPABILITY_NOTAUTH, "Bearer capability not authorized"},
400 {AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, "Bearer capability not available"},
401 {AST_CAUSE_BEARERCAPABILITY_NOTIMPL, "Bearer capability not implemented"},
402 {AST_CAUSE_CHAN_NOT_IMPLEMENTED, "Channel not implemented"},
403 {AST_CAUSE_FACILITY_NOT_IMPLEMENTED, "Facility not implemented"},
404 {AST_CAUSE_INVALID_CALL_REFERENCE, "Invalid call reference"},
405 {AST_CAUSE_INCOMPATIBLE_DESTINATION, "Incompatible destination"},
406 {AST_CAUSE_INVALID_MSG_UNSPECIFIED, "Invalid message unspecified"},
407 {AST_CAUSE_MANDATORY_IE_MISSING, "Mandatory IE missing"},
408 {AST_CAUSE_MESSAGE_TYPE_NONEXIST, "Message type nonexistent"},
409 {AST_CAUSE_WRONG_MESSAGE, "Wrong message"},
410 {AST_CAUSE_IE_NONEXIST, "IE nonexistent"},
411 {AST_CAUSE_INVALID_IE_CONTENTS, "Invalid IE contents"},
412 {AST_CAUSE_WRONG_CALL_STATE, "Wrong call state"},
413 {AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, "Recovery on timer expire"},
414 {AST_CAUSE_MANDATORY_IE_LENGTH_ERROR, "Mandatory IE length error"},
415 {AST_CAUSE_PROTOCOL_ERROR, "Protocol error"},
416 {AST_CAUSE_INTERWORKING, "Interworking"},
421 /* ************************************************************************* */
423 /* In order to track IAX calls, we have a hash table which maps
424 * {addr,port type,port,call} to a unique circuit id.
426 * Each call has two such circuits associated with it (a forward and a
427 * reverse circuit, where 'forward' is defined as the direction the NEW
428 * packet went in), and we maintain an iax_call_data structure for each
429 * call, attached to both circuits with circuit_add_proto_data.
431 * Because {addr,port type,port,call} quadruplets can be reused
432 * (Asterisk reuses call numbers), circuit ids aren't unique to
433 * individual calls and we treat NEW packets somewhat specially. When we
434 * get such a packet, we see if there are any calls with a matching
435 * circuit id, and make sure that its circuits are marked as ended
436 * before that packet.
438 * A second complication is that we only know one quadruplet at the time
439 * the NEW packet is processed: there is therefore cunningness in
440 * iax_lookup_circuit_details() to look for replies to NEW packets and
441 * create the reverse circuit.
445 /* start with a hash of {addr,port type,port,call}->{id} */
453 /* this is where addr->data points to. it's put in here for easy freeing */
454 guint8 address_data[MAX_ADDRESS];
458 static GHashTable *iax_circuit_hashtab = NULL;
459 static guint circuitcount = 0;
461 /* the number of keys and values to reserve space for in each memory chunk.
462 We assume we won't be tracking many calls at once so this is quite low.
464 #define IAX_INIT_PACKET_COUNT 10
467 static gchar *key_to_str( const iax_circuit_key *key )
470 static gchar *strp, str[3][80];
478 /* why doesn't ep_address_to_str take a const pointer?
479 cast the warnings into oblivion. */
481 /* XXX - is this a case for ep_alloc? */
482 g_snprintf(strp, 80, "{%s:%i,%i}",
483 ep_address_to_str((address *)&key->addr),
491 static gint iax_circuit_equal(gconstpointer v, gconstpointer w)
493 const iax_circuit_key *v1 = (const iax_circuit_key *)v;
494 const iax_circuit_key *v2 = (const iax_circuit_key *)w;
497 result = ( ADDRESSES_EQUAL(&(v1->addr), &(v2->addr)) &&
498 v1->ptype == v2->ptype &&
499 v1->port == v2->port &&
500 v1->callno== v2->callno);
502 g_debug( "+++ Comparing for equality: %s, %s: %u",key_to_str(v1), key_to_str(v2), result);
508 static guint iax_circuit_hash (gconstpointer v)
510 const iax_circuit_key *key = (const iax_circuit_key *)v;
514 ADD_ADDRESS_TO_HASH(hash_val, &key->addr);
515 hash_val += (guint)(key->ptype);
516 hash_val += (guint)(key->port);
517 hash_val += (guint)(key->callno);
520 g_debug( "+++ Hashing key: %s, result %#x", key_to_str(key), hash_val );
523 return (guint) hash_val;
526 /* Find, or create, a circuit for the given
527 {address,porttype,port,call} quadruplet
529 static guint iax_circuit_lookup(const address *address_p,
535 guint32 *circuit_id_p;
537 key.addr = *address_p;
542 circuit_id_p = g_hash_table_lookup( iax_circuit_hashtab, &key);
543 if( ! circuit_id_p ) {
544 iax_circuit_key *new_key;
546 new_key = se_alloc(sizeof(iax_circuit_key));
547 new_key->addr.type = address_p->type;
548 new_key->addr.len = MIN(address_p->len,MAX_ADDRESS);
549 new_key->addr.data = new_key->address_data;
550 memcpy(new_key->address_data,address_p->data,new_key->addr.len);
551 new_key->ptype = ptype;
552 new_key->port = port;
553 new_key->callno = callno;
555 circuit_id_p = se_alloc(sizeof(iax_circuit_key));
556 *circuit_id_p = ++circuitcount;
558 g_hash_table_insert(iax_circuit_hashtab, new_key, circuit_id_p);
561 g_debug("Created new circuit id %u for node %s", *circuit_id_p, key_to_str(new_key));
565 return *circuit_id_p;
569 /* ************************************************************************* */
572 guint32 current_frag_id; /* invalid unless current_frag_bytes > 0 */
573 guint32 current_frag_bytes;
574 guint32 current_frag_minlen;
577 /* This is our per-call data structure, which is attached to both the
578 * forward and reverse circuits.
580 typedef struct iax_call_data {
581 /* For this data, src and dst are relative to the original direction under
582 which this call is stored. Obviously if the reversed flag is set true by
583 iax_find_call, src and dst are reversed relative to the direction the
584 actual source and destination of the data.
586 if the codec changes mid-call, we update it here; because we store a codec
587 number with each packet too, we handle going back to earlier packets
591 iax_dataformat_t dataformat;
592 guint32 src_codec, dst_codec;
593 guint32 src_vformat, dst_vformat;
595 /* when a transfer takes place, we'll get a new circuit id; we assume that we
596 don't try to transfer more than IAX_MAX_TRANSFERS times in a call */
597 guint forward_circuit_ids[IAX_MAX_TRANSFERS];
598 guint reverse_circuit_ids[IAX_MAX_TRANSFERS];
599 guint n_forward_circuit_ids;
600 guint n_reverse_circuit_ids;
602 /* this is the subdissector for the call */
603 dissector_handle_t subdissector;
605 /* the absolute start time of the call */
608 GHashTable *fid_table;
609 GHashTable *fragment_table;
610 iax_call_dirdata dirdata[2];
613 static void iax_init_hash( void )
615 if (iax_circuit_hashtab)
616 g_hash_table_destroy(iax_circuit_hashtab);
618 iax_circuit_hashtab = g_hash_table_new(iax_circuit_hash, iax_circuit_equal);
625 /* creates a new CT_IAX2 circuit with a specified circuit id for a call
627 * typically a call has up to three associated circuits: an original source, an
628 * original destination, and the result of a transfer.
630 * For each endpoint, a CT_IAX2 circuit is created and added to the call_data
633 * 'reversed' should be true if this end is the one which would have _received_
634 * the NEW packet, or it is an endpoint to which the 'destination' is being
638 static circuit_t *iax2_new_circuit_for_call(guint circuit_id, guint framenum, iax_call_data *iax_call,
643 if(( reversed && iax_call->n_reverse_circuit_ids >= IAX_MAX_TRANSFERS) ||
644 ( !reversed && iax_call->n_forward_circuit_ids >= IAX_MAX_TRANSFERS)) {
645 g_warning("Too many transfers for iax_call");
649 res = circuit_new(CT_IAX2,
653 circuit_add_proto_data(res, proto_iax2, iax_call);
656 iax_call -> reverse_circuit_ids[iax_call->n_reverse_circuit_ids++] = circuit_id;
658 iax_call -> forward_circuit_ids[iax_call->n_forward_circuit_ids++] = circuit_id;
664 /* returns true if this circuit id is a "forward" circuit for this call: ie, it
665 * is the point which _sent_ the original 'NEW' packet, or a point to which that
666 * end was subsequently transferred */
667 static gboolean is_forward_circuit(guint circuit_id,
668 const iax_call_data *iax_call)
671 for(i=0;i<iax_call->n_forward_circuit_ids;i++){
672 if(circuit_id == iax_call->forward_circuit_ids[i])
678 /* returns true if this circuit id is a "reverse" circuit for this call: ie, it
679 * is the point which _received_ the original 'NEW' packet, or a point to which that
680 * end was subsequently transferred */
681 static gboolean is_reverse_circuit(guint circuit_id,
682 const iax_call_data *iax_call)
685 for(i=0;i<iax_call->n_reverse_circuit_ids;i++){
686 if(circuit_id == iax_call->reverse_circuit_ids[i])
693 static iax_call_data *iax_lookup_call_from_dest( guint src_circuit_id,
694 guint dst_circuit_id,
696 gboolean *reversed_p)
698 circuit_t *dst_circuit;
699 iax_call_data * iax_call;
700 gboolean reversed = FALSE;
702 dst_circuit = find_circuit( CT_IAX2,
708 g_debug( "++ destination circuit not found, must have missed NEW packet" );
716 g_debug( "++ found destination circuit" );
719 iax_call = (iax_call_data *)circuit_get_proto_data(dst_circuit,proto_iax2);
721 /* there's no way we can create a CT_IAX2 circuit without adding
722 iax call data to it; assert this */
723 DISSECTOR_ASSERT(iax_call);
725 if( is_forward_circuit(dst_circuit_id, iax_call )) {
727 g_debug( "++ destination circuit matches forward_circuit_id of call, "
728 "therefore packet is reversed" );
733 if( iax_call -> n_reverse_circuit_ids == 0 ) {
734 /* we are going in the reverse direction, and this call
735 doesn't have a reverse circuit associated with it.
738 g_debug( "++ reverse_circuit_id of call is zero, need to create a "
739 "new reverse circuit for this call" );
742 iax2_new_circuit_for_call( src_circuit_id, framenum, iax_call, TRUE );
744 g_debug( "++ done" );
746 } else if( !is_reverse_circuit(src_circuit_id, iax_call )) {
747 g_warning( "IAX Packet %u from circuit ids %u->%u "
748 "conflicts with earlier call with circuit ids %u->%u",
750 src_circuit_id,dst_circuit_id,
751 iax_call->forward_circuit_ids[0],
752 iax_call->reverse_circuit_ids[0]);
755 } else if ( is_reverse_circuit(dst_circuit_id, iax_call)) {
757 g_debug( "++ destination circuit matches reverse_circuit_id of call, "
758 "therefore packet is forward" );
762 if( !is_forward_circuit(src_circuit_id, iax_call)) {
763 g_warning( "IAX Packet %u from circuit ids %u->%u "
764 "conflicts with earlier call with circuit ids %u->%u",
766 src_circuit_id,dst_circuit_id,
767 iax_call->forward_circuit_ids[0],
768 iax_call->reverse_circuit_ids[0]);
774 DISSECTOR_ASSERT_NOT_REACHED();
778 *reversed_p = reversed;
784 /* looks up an iax_call for this packet */
785 static iax_call_data *iax_lookup_call( packet_info *pinfo,
788 gboolean *reversed_p)
790 gboolean reversed = FALSE;
791 iax_call_data *iax_call = NULL;
792 guint src_circuit_id;
795 g_debug( "++ iax_lookup_circuit_details: Looking up circuit for frame %u, "
796 "from {%s:%u:%u} to {%s:%u:%u}", pinfo->fd->num,
797 ep_address_to_str(&pinfo->src),pinfo->srcport,scallno,
798 ep_address_to_str(&pinfo->dst),pinfo->destport,dcallno);
802 src_circuit_id = iax_circuit_lookup(&pinfo->src,pinfo->ptype,
803 pinfo->srcport,scallno);
806 /* the most reliable indicator of call is the destination callno, if
809 guint dst_circuit_id;
811 g_debug( "++ dcallno non-zero, looking up destination circuit" );
814 dst_circuit_id = iax_circuit_lookup(&pinfo->dst,pinfo->ptype,
815 pinfo->destport,dcallno);
817 iax_call = iax_lookup_call_from_dest(src_circuit_id, dst_circuit_id,
818 pinfo->fd->num, &reversed);
820 circuit_t *src_circuit;
822 /* in all other circumstances, the source circuit should already
823 * exist: its absense indicates that we missed the all-important NEW
827 src_circuit = find_circuit( CT_IAX2,
832 iax_call = (iax_call_data *)circuit_get_proto_data(src_circuit,proto_iax2);
834 /* there's no way we can create a CT_IAX2 circuit without adding
835 iax call data to it; assert this */
836 DISSECTOR_ASSERT(iax_call);
838 if( is_forward_circuit(src_circuit_id,iax_call))
840 else if(is_reverse_circuit(src_circuit_id,iax_call))
843 /* there's also no way we can attach an iax_call_data to a circuit
844 without the circuit being either the forward or reverse circuit
845 for that call; assert this too.
847 DISSECTOR_ASSERT_NOT_REACHED();
853 *reversed_p = reversed;
857 g_debug( "++ Found call for packet: id %u, reversed=%c", iax_call->forward_circuit_ids[0], reversed?'1':'0' );
859 g_debug( "++ Call not found. Must have missed the NEW packet?" );
866 /* initialise the per-direction parts of an iax_call_data structure */
867 static void init_dir_data(iax_call_dirdata *dirdata)
869 dirdata -> current_frag_bytes=0;
870 dirdata -> current_frag_minlen=0;
874 /* handles a NEW packet by creating a new iax call and forward circuit.
875 the reverse circuit is not created until the ACK is received and
876 is created by iax_lookup_circuit_details. */
877 static iax_call_data *iax_new_call( packet_info *pinfo,
882 static const nstime_t millisecond = {0, 1000000};
885 g_debug( "+ new_circuit: Handling NEW packet, frame %u", pinfo->fd->num );
888 circuit_id = iax_circuit_lookup(&pinfo->src,pinfo->ptype,
889 pinfo->srcport,scallno);
891 call = se_alloc(sizeof(iax_call_data));
892 call -> dataformat = 0;
893 call -> src_codec = 0;
894 call -> dst_codec = 0;
895 call -> n_forward_circuit_ids = 0;
896 call -> n_reverse_circuit_ids = 0;
897 call -> subdissector = NULL;
898 call -> start_time = pinfo->fd->abs_ts;
899 nstime_delta(&call -> start_time, &call -> start_time, &millisecond);
900 call -> fid_table = g_hash_table_new(g_direct_hash, g_direct_equal);
901 init_dir_data(&call->dirdata[0]);
902 init_dir_data(&call->dirdata[1]);
903 call->fragment_table = NULL;
904 fragment_table_init(&(call->fragment_table));
906 iax2_new_circuit_for_call(circuit_id,pinfo->fd->num,call,FALSE);
912 /* ************************************************************************* */
914 /* per-packet data */
915 typedef struct iax_packet_data {
916 gboolean first_time; /* we're dissecting this packet for the first time; so
917 things like codec and transfer requests should be
918 propogated into the call data */
919 iax_call_data *call_data;
922 nstime_t abstime; /* the absolute time of this packet, based on its
923 * timestamp and the NEW packet's time (-1 if unknown) */
926 static iax_packet_data *iax_new_packet_data(iax_call_data *call, gboolean reversed)
928 iax_packet_data *p = se_alloc(sizeof(iax_packet_data));
932 p->reversed=reversed;
938 static void iax2_populate_pinfo_from_packet_data(packet_info *pinfo, const iax_packet_data * p)
940 /* info for subdissectors. We always pass on the original forward circuit,
941 * and steal the p2p_dir flag to indicate the direction */
942 if( p->call_data == NULL ) {
943 /* if we missed the NEW packet for this call, call_data will be null. it's
944 * tbd what the best thing to do here is. */
945 pinfo -> ctype = CT_NONE;
947 pinfo -> ctype = CT_IAX2;
948 pinfo -> circuit_id = (guint32)p->call_data->forward_circuit_ids[0];
949 pinfo -> p2p_dir = p->reversed?P2P_DIR_RECV:P2P_DIR_SENT;
951 if (check_col (pinfo->cinfo, COL_IF_DIR))
952 col_set_str (pinfo->cinfo, COL_IF_DIR, p->reversed ? "rev" : "fwd" );
957 /* ************************************************************************* */
959 /* this is passed up from the IE dissector to the main dissector */
962 address peer_address;
963 port_type peer_ptype;
970 static guint32 dissect_fullpacket (tvbuff_t * tvb, guint32 offset,
973 proto_tree * iax2_tree,
974 proto_tree * main_tree);
977 static guint32 dissect_minipacket (tvbuff_t * tvb, guint32 offset,
980 proto_tree * iax2_tree,
981 proto_tree * main_tree);
983 static guint32 dissect_minivideopacket (tvbuff_t * tvb, guint32 offset,
986 proto_tree * iax2_tree,
987 proto_tree * main_tree);
989 static void dissect_payload(tvbuff_t *tvb, guint32 offset,
990 packet_info *pinfo, proto_tree *iax2_tree,
991 proto_tree *tree, guint32 ts, gboolean video,
992 iax_packet_data *iax_packet);
997 dissect_iax2 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
999 proto_item *iax2_item = NULL;
1000 proto_tree *iax2_tree = NULL;
1001 proto_tree *full_mini_subtree = NULL;
1002 guint32 offset = 0, len;
1003 guint16 scallno = 0;
1007 /* set up the protocol and info fields in the summary pane */
1008 if (check_col (pinfo->cinfo, COL_PROTOCOL))
1010 col_set_str (pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_IAX2);
1012 col_clear(pinfo->cinfo, COL_INFO);
1014 /* add the 'iax2' tree to the main tree */
1017 iax2_item = proto_tree_add_item (tree, proto_iax2, tvb, offset, -1, FALSE);
1018 iax2_tree = proto_item_add_subtree (iax2_item, ett_iax2);
1021 stmp = tvb_get_ntohs(tvb, offset);
1023 /* starting with 0x0000 indicates either a mini video packet or a 'meta'
1024 * packet, whatever that means */
1026 stmp = tvb_get_ntohs(tvb, offset);
1027 if( stmp & 0x8000 ) {
1028 /* mini video packet */
1029 type = IAX2_MINI_VIDEO_PACKET;
1030 scallno = stmp & 0x7FFF;
1034 type = IAX2_META_PACKET;
1037 /* The source call/fullpacket flag is common to both mini and full packets */
1038 scallno = tvb_get_ntohs(tvb, offset);
1040 if( scallno & 0x8000 )
1041 type = IAX2_FULL_PACKET;
1043 type = IAX2_MINI_VOICE_PACKET;
1049 proto_item *full_mini_base;
1051 full_mini_base = proto_tree_add_uint(iax2_tree, hf_iax2_packet_type, tvb, 0, offset, type);
1052 full_mini_subtree = proto_item_add_subtree(full_mini_base, ett_iax2_full_mini_subtree);
1055 proto_tree_add_item (full_mini_subtree, hf_iax2_scallno, tvb, offset-2, 2, FALSE);
1058 iax2_info->ptype = type;
1059 iax2_info->scallno = 0;
1060 iax2_info->dcallno = 0;
1061 iax2_info->ftype = 0;
1062 iax2_info->csub = 0;
1063 iax2_info->payload_len = 0;
1064 iax2_info->timestamp = 0;
1065 iax2_info->callState = VOIP_NO_STATE;
1066 iax2_info->messageName = NULL;
1067 iax2_info->callingParty = NULL;
1068 iax2_info->calledParty = NULL;
1069 iax2_info->payload_data = NULL;
1072 case IAX2_FULL_PACKET:
1073 len = dissect_fullpacket( tvb, offset, scallno, pinfo, full_mini_subtree, tree );
1075 case IAX2_MINI_VOICE_PACKET:
1076 iax2_info->messageName = "MINI_VOICE_PACKET";
1077 len = dissect_minipacket( tvb, offset, scallno, pinfo, full_mini_subtree, tree );
1079 case IAX2_MINI_VIDEO_PACKET:
1080 iax2_info->messageName = "MINI_VIDEO_PACKET";
1081 len = dissect_minivideopacket( tvb, offset, scallno, pinfo, full_mini_subtree, tree );
1083 case IAX2_META_PACKET:
1084 /* not implemented yet */
1085 iax2_info->messageName = "META_PACKET";
1092 /* update the 'length' of the main IAX2 header field so that it covers just the headers,
1093 not the audio data. */
1094 proto_item_set_len(iax2_item, len);
1095 tap_queue_packet(iax2_tap, pinfo, iax2_info);
1098 static proto_item *dissect_datetime_ie(tvbuff_t *tvb, guint32 offset, proto_tree *ies_tree)
1104 proto_tree_add_item (ies_tree, hf_iax2_ies[IAX_IE_DATETIME], tvb, offset + 2, 4, FALSE);
1105 ie_val = tvb_get_ntohl(tvb, offset+2);
1107 /* who's crazy idea for a time encoding was this? */
1108 tm.tm_sec = (ie_val & 0x1f) << 1;
1109 tm.tm_min = (ie_val>>5) & 0x3f;
1110 tm.tm_hour = (ie_val>>11) & 0x1f;
1111 tm.tm_mday = (ie_val>>16) & 0x1f;
1112 tm.tm_mon = ((ie_val>>21) & 0xf) - 1;
1113 tm.tm_year = ((ie_val>>25) & 0x7f) + 100;
1114 tm.tm_isdst= -1; /* there's no info on whether DST was in force; assume it's
1115 * the same as currently */
1117 datetime.secs = mktime(&tm);
1119 return proto_tree_add_time (ies_tree, hf_iax2_ie_datetime, tvb, offset+2, 4, &datetime);
1123 /* dissect the information elements in an IAX frame. Returns the updated offset */
1124 static guint32 dissect_ies (tvbuff_t * tvb, guint32 offset,
1125 proto_tree * iax_tree,
1126 iax2_ie_data *ie_data)
1128 DISSECTOR_ASSERT(ie_data);
1130 while (offset < tvb_reported_length (tvb)) {
1132 int ies_type = tvb_get_guint8(tvb, offset);
1133 int ies_len = tvb_get_guint8(tvb, offset + 1);
1134 guint16 apparent_addr_family;
1136 /* do non-tree-dependent stuff first */
1138 case IAX_IE_DATAFORMAT:
1139 if (ies_len != 4) THROW(ReportedBoundsError);
1140 ie_data -> dataformat = tvb_get_ntohl(tvb, offset+2);
1143 case IAX_IE_CALLED_NUMBER:
1144 iax2_info->calledParty = g_strdup(tvb_format_text(tvb, offset+2, ies_len));
1146 case IAX_IE_CALLING_NUMBER:
1147 iax2_info->callingParty = g_strdup(tvb_format_text(tvb, offset+2, ies_len));
1150 case IAX_IE_APPARENT_ADDR:
1151 /* The IAX2 I-D says that the "apparent address" structure
1152 "is the same as the linux struct sockaddr_in", without
1153 bothering to note that the address family field is in
1154 *host* byte order in that structure (the I-D seems to be
1155 assuming that "everything is a Vax^Wx86 or x86-64" with
1156 the address family field being little-endian).
1158 This means the address family values are the Linux
1159 address family values. */
1160 apparent_addr_family = tvb_get_letohs(tvb, offset+2);
1161 switch( apparent_addr_family ) {
1163 /* IAX is always over UDP */
1164 ie_data->peer_ptype = PT_UDP;
1165 ie_data->peer_port = tvb_get_ntohs(tvb, offset+4);
1167 /* the ip address is big-endian, but then so is peer_address.data */
1168 SET_ADDRESS(&ie_data->peer_address,AT_IPv4,4,tvb_get_ptr(tvb,offset+6,4));
1172 g_warning("Not supported in IAX dissector: peer address family of %u", apparent_addr_family);
1179 /* the rest of this stuff only needs doing if we have an iax_tree */
1182 proto_item *ti, *ie_item = NULL;
1183 proto_tree *ies_tree;
1184 int ie_hf = hf_iax2_ies[ies_type];
1186 ti = proto_tree_add_text(iax_tree, tvb, offset, ies_len+2, " " );
1188 ies_tree = proto_item_add_subtree(ti, ett_iax2_ie);
1190 proto_tree_add_text(ies_tree, tvb, offset, 1, "IE id: %s (0x%02X)",
1191 val_to_str(ies_type, iax_ies_type, "Unknown"),
1194 proto_tree_add_text(ies_tree, tvb, offset+1, 1, "Length: %u",ies_len);
1197 /* hf_iax2_ies[] is an array, indexed by IE number, of header-fields, one
1198 per IE. Apart from a couple of special cases which require more
1199 complex decoding, we can just look up an entry from the array, and add
1204 case IAX_IE_DATETIME:
1205 ie_item = dissect_datetime_ie(tvb,offset,ies_tree);
1209 case IAX_IE_CAPABILITY:
1211 proto_tree *codec_tree;
1213 if (ies_len != 4) THROW(ReportedBoundsError);
1216 proto_tree_add_item (ies_tree, ie_hf,
1217 tvb, offset + 2, ies_len, FALSE);
1219 proto_item_add_subtree (ie_item, ett_iax2_codecs);
1221 proto_tree_add_item(codec_tree, hf_iax2_cap_g723_1, tvb, offset + 2, ies_len, FALSE );
1222 proto_tree_add_item(codec_tree, hf_iax2_cap_gsm, tvb, offset + 2, ies_len, FALSE );
1223 proto_tree_add_item(codec_tree, hf_iax2_cap_ulaw, tvb, offset + 2, ies_len, FALSE );
1224 proto_tree_add_item(codec_tree, hf_iax2_cap_alaw, tvb, offset + 2, ies_len, FALSE );
1225 proto_tree_add_item(codec_tree, hf_iax2_cap_g726, tvb, offset + 2, ies_len, FALSE );
1226 proto_tree_add_item(codec_tree, hf_iax2_cap_adpcm, tvb, offset + 2, ies_len, FALSE );
1227 proto_tree_add_item(codec_tree, hf_iax2_cap_slinear, tvb, offset + 2, ies_len, FALSE );
1228 proto_tree_add_item(codec_tree, hf_iax2_cap_lpc10, tvb, offset + 2, ies_len, FALSE );
1229 proto_tree_add_item(codec_tree, hf_iax2_cap_g729a, tvb, offset + 2, ies_len, FALSE );
1230 proto_tree_add_item(codec_tree, hf_iax2_cap_speex, tvb, offset + 2, ies_len, FALSE );
1231 proto_tree_add_item(codec_tree, hf_iax2_cap_ilbc, tvb, offset + 2, ies_len, FALSE );
1232 proto_tree_add_item(codec_tree, hf_iax2_cap_jpeg, tvb, offset + 2, ies_len, FALSE );
1233 proto_tree_add_item(codec_tree, hf_iax2_cap_png, tvb, offset + 2, ies_len, FALSE );
1234 proto_tree_add_item(codec_tree, hf_iax2_cap_h261, tvb, offset + 2, ies_len, FALSE );
1235 proto_tree_add_item(codec_tree, hf_iax2_cap_h263, tvb, offset + 2, ies_len, FALSE );
1239 case IAX_IE_APPARENT_ADDR:
1241 proto_tree *sockaddr_tree = NULL;
1243 ie_item = proto_tree_add_text(ies_tree, tvb, offset + 2, 16, "Apparent Address");
1244 sockaddr_tree = proto_item_add_subtree(ie_item, ett_iax2_ies_apparent_addr);
1246 /* The IAX2 I-D says that the "apparent address" structure
1247 "is the same as the linux struct sockaddr_in", without
1248 bothering to note that the address family field is in
1249 *host* byte order in that structure (the I-D seems to be
1250 assuming that "everything is a Vax^Wx86 or x86-64" with
1251 the address family field being little-endian).
1253 This means the address family values are the Linux
1254 address family values. */
1255 apparent_addr_family = tvb_get_letohs(tvb, offset+2);
1256 proto_tree_add_uint(sockaddr_tree, hf_IAX_IE_APPARENTADDR_SINFAMILY, tvb, offset + 2, 2, apparent_addr_family);
1258 switch( apparent_addr_family ) {
1262 proto_tree_add_uint(sockaddr_tree, hf_IAX_IE_APPARENTADDR_SINPORT, tvb, offset + 4, 2, ie_data->peer_port);
1263 memcpy(&addr, ie_data->peer_address.data, 4);
1264 proto_tree_add_ipv4(sockaddr_tree, hf_IAX_IE_APPARENTADDR_SINADDR, tvb, offset + 6, 4, addr);
1273 /* throw an error if the IE isn't the expected length */
1274 gint explen = ftype_length(proto_registrar_get_nth(ie_hf)->type);
1275 if(explen != 0 && ies_len != explen)
1276 THROW(ReportedBoundsError);
1277 ie_item = proto_tree_add_item(ies_tree, ie_hf, tvb, offset + 2, ies_len, FALSE);
1279 /* we don't understand this ie: add a generic one */
1282 const gchar *ie_name = val_to_str(ies_type, iax_ies_type, "Unknown");
1286 value = tvb_get_guint8(tvb, offset + 2);
1288 proto_tree_add_uint_format(ies_tree, hf_IAX_IE_UNKNOWN_BYTE,
1289 tvb, offset+2, 1, value,
1290 "%s: %#02x", ie_name, value );
1294 value = tvb_get_ntohs(tvb, offset + 2);
1296 proto_tree_add_uint_format(ies_tree, hf_IAX_IE_UNKNOWN_I16,
1297 tvb, offset+2, 2, value,
1298 "%s: %#04x", ie_name, value );
1302 value = tvb_get_ntohl(tvb, offset + 2);
1304 proto_tree_add_uint_format(ies_tree, hf_IAX_IE_UNKNOWN_I32,
1305 tvb, offset+2, 4, value,
1306 "%s: %#08x", ie_name, value );
1310 ptr = tvb_get_ptr(tvb, offset + 2, ies_len);
1312 proto_tree_add_string_format(ies_tree, hf_IAX_IE_UNKNOWN_BYTES,
1313 tvb, offset+2, ies_len, ptr,
1314 "%s: %s", ie_name, ptr );
1321 /* by now, we *really* ought to have added an item */
1322 DISSECTOR_ASSERT(ie_item != NULL);
1324 /* Retrieve the text from the item we added, and append it to the main IE
1326 if(!PROTO_ITEM_IS_HIDDEN(ti)) {
1327 field_info *ie_finfo = PITEM_FINFO(ie_item);
1329 /* if the representation of the item has already been set, use that;
1330 else we have to allocate a block to put the text into */
1331 if( ie_finfo && ie_finfo->rep != NULL )
1332 proto_item_set_text(ti, "Information Element: %s",
1333 ie_finfo->rep->representation);
1335 guint8 *ie_val = NULL;
1336 ie_val = g_malloc(ITEM_LABEL_LENGTH);
1337 proto_item_fill_label(ie_finfo, ie_val);
1338 proto_item_set_text(ti, "Information Element: %s",
1345 offset += ies_len + 2;
1350 static guint32 uncompress_subclass(guint8 csub)
1352 /* If the SC_LOG flag is set, return 2^csub otherwise csub */
1354 /* special case for 'compressed' -1 */
1358 return 1 << (csub & 0x1F);
1361 return (guint32)csub;
1364 /* returns the new offset */
1365 static guint32 dissect_iax2_command(tvbuff_t * tvb, guint32 offset,
1366 packet_info * pinfo, proto_tree *tree,
1367 iax_packet_data *iax_packet)
1369 guint8 csub = tvb_get_guint8(tvb, offset);
1370 guint8 address_data[MAX_ADDRESS];
1371 iax2_ie_data ie_data;
1372 iax_call_data *iax_call;
1374 ie_data.peer_address.type = AT_NONE;
1375 ie_data.peer_address.len = 0;
1376 ie_data.peer_address.data = address_data;
1377 ie_data.peer_ptype = 0;
1378 ie_data.peer_port = 0;
1379 ie_data.peer_callno = 0;
1380 ie_data.dataformat = (guint32)-1;
1381 iax_call = iax_packet -> call_data;
1383 /* add the subclass */
1384 proto_tree_add_uint (tree, hf_iax2_iax_csub, tvb, offset, 1, csub);
1387 if (check_col (pinfo->cinfo, COL_INFO))
1388 col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
1389 val_to_str (csub, iax_iax_subclasses, "unknown (0x%02x)"));
1391 if (offset >= tvb_reported_length (tvb))
1394 offset += dissect_ies(tvb, offset, tree, &ie_data);
1396 /* if this is a data call, set up a subdissector for the circuit */
1397 if(iax_call && ie_data.dataformat != (guint32)-1 && iax_call -> subdissector == NULL) {
1398 iax_call -> subdissector = dissector_get_port_handle(iax2_dataformat_dissector_table, ie_data.dataformat );
1399 iax_call -> dataformat = ie_data.dataformat;
1402 /* if this is a transfer request, record it in the call data */
1403 if( csub == IAX_COMMAND_TXREQ && iax_packet -> first_time ) {
1404 if( ie_data.peer_address.type != AT_NONE && ie_data.peer_callno != 0 ) {
1405 guint tx_circuit = iax_circuit_lookup(&ie_data.peer_address,
1408 ie_data.peer_callno);
1411 g_debug("found transfer request for call %u->%u, to new id %u",
1412 iax_call->forward_circuit_ids[0],
1413 iax_call->reverse_circuit_ids[0],
1417 iax2_new_circuit_for_call(tx_circuit,pinfo->fd->num,iax_call,iax_packet->reversed);
1424 static void iax2_add_ts_fields(packet_info * pinfo, proto_tree * iax2_tree, iax_packet_data *iax_packet, guint16 shortts)
1426 guint32 longts = shortts;
1430 if(iax_packet->call_data == NULL) {
1431 /* no call info for this frame; perhaps we missed the NEW packet */
1435 if(iax_packet->abstime.secs == -1) {
1436 time_t start_secs = iax_packet->call_data->start_time.secs;
1437 gint32 abs_secs = (gint32) (start_secs + longts/1000);
1439 /* deal with short timestamps by assuming that packets are never more than
1440 * 16 seconds late */
1441 while(abs_secs < pinfo->fd->abs_ts.secs - 16) {
1443 abs_secs = (gint32) (start_secs + longts/1000);
1446 iax_packet->abstime.secs=abs_secs;
1447 iax_packet->abstime.nsecs=iax_packet->call_data->start_time.nsecs + (longts % 1000) * 1000000;
1448 if(iax_packet->abstime.nsecs >= 1000000000) {
1449 iax_packet->abstime.nsecs -= 1000000000;
1450 iax_packet->abstime.secs ++;
1453 iax2_info->timestamp = longts;
1456 item = proto_tree_add_time(iax2_tree, hf_iax2_absts, NULL, 0, 0, &iax_packet->abstime);
1457 PROTO_ITEM_SET_GENERATED(item);
1459 ts = pinfo->fd->abs_ts;
1460 nstime_delta(&ts, &ts, &iax_packet->abstime);
1462 item = proto_tree_add_time(iax2_tree, hf_iax2_lateness, NULL, 0, 0, &ts);
1463 PROTO_ITEM_SET_GENERATED(item);
1467 /* returns the new offset */
1469 dissect_fullpacket (tvbuff_t * tvb, guint32 offset,
1471 packet_info * pinfo, proto_tree * iax2_tree,
1472 proto_tree * main_tree)
1474 guint32 retransmission = 0;
1481 proto_tree *packet_type_tree = NULL;
1482 iax_call_data *iax_call;
1483 iax_packet_data *iax_packet;
1485 gboolean rtp_marker;
1488 * remove the top bit for retransmission detection
1490 dcallno = tvb_get_ntohs(tvb, offset);
1491 retransmission = dcallno & 0x8000;
1492 dcallno = dcallno & 0x7FFF;
1493 ts = tvb_get_ntohl(tvb, offset+2);
1494 type = tvb_get_guint8(tvb, offset + 8);
1495 csub = tvb_get_guint8(tvb, offset + 9);
1496 iax2_info->ftype = type;
1497 iax2_info->csub = csub;
1498 iax2_info->scallno = scallno;
1499 iax2_info->dcallno = dcallno;
1501 /* see if we've seen this packet before */
1502 iax_packet = (iax_packet_data *)p_get_proto_data(pinfo->fd,proto_iax2);
1504 /* if not, find or create an iax_call info structure for this IAX session. */
1506 if( type == AST_FRAME_IAX && csub == IAX_COMMAND_NEW ) {
1507 /* NEW packets start a new call */
1508 iax_call = iax_new_call(pinfo,scallno);
1511 iax_call = iax_lookup_call(pinfo, scallno, dcallno,
1515 iax_packet = iax_new_packet_data(iax_call, reversed);
1516 p_add_proto_data(pinfo->fd,proto_iax2,iax_packet);
1518 iax_call = iax_packet->call_data;
1519 reversed = iax_packet->reversed;
1522 iax2_populate_pinfo_from_packet_data(pinfo, iax_packet);
1525 proto_item *packet_type_base;
1527 proto_tree_add_item (iax2_tree, hf_iax2_dcallno, tvb, offset, 2, FALSE );
1529 proto_tree_add_item(iax2_tree, hf_iax2_retransmission, tvb, offset, 2, FALSE );
1533 proto_tree_add_uint (iax2_tree, hf_iax2_callno, tvb, 0, 4,
1534 iax_call->forward_circuit_ids[0] );
1535 PROTO_ITEM_SET_GENERATED(item);
1538 proto_tree_add_uint (iax2_tree, hf_iax2_ts, tvb, offset+2, 4, ts);
1539 iax2_add_ts_fields(pinfo, iax2_tree, iax_packet, (guint16)ts);
1541 proto_tree_add_item (iax2_tree, hf_iax2_oseqno, tvb, offset+6, 1,
1544 proto_tree_add_item (iax2_tree, hf_iax2_iseqno, tvb, offset+7, 1,
1546 packet_type_base = proto_tree_add_uint (iax2_tree, hf_iax2_type, tvb,
1549 /* add the type-specific subtree */
1550 packet_type_tree = proto_item_add_subtree (packet_type_base, ett_iax2_type);
1552 iax2_add_ts_fields(pinfo, iax2_tree, iax_packet, (guint16)ts);
1556 /* add frame type to info line */
1557 if (check_col (pinfo->cinfo, COL_INFO)) {
1558 col_add_fstr (pinfo->cinfo, COL_INFO, "%s, source call# %d, timestamp %ums",
1559 val_to_str (type, iax_frame_types, "Unknown (0x%02x)"),
1562 iax2_info->messageName = val_to_str (type, iax_frame_types, "Unknown (0x%02x)");
1566 offset=dissect_iax2_command(tvb,offset+9,pinfo,packet_type_tree,iax_packet);
1567 iax2_info->messageName = val_to_str (csub, iax_iax_subclasses, "unknown (0x%02x)");
1568 iax2_info->callState = csub;
1571 case AST_FRAME_DTMF_BEGIN:
1572 case AST_FRAME_DTMF_END:
1573 proto_tree_add_item (packet_type_tree, hf_iax2_dtmf_csub, tvb, offset+9, 1, FALSE);
1576 if (check_col (pinfo->cinfo, COL_INFO))
1577 col_append_fstr (pinfo->cinfo, COL_INFO, " digit %c", csub );
1580 case AST_FRAME_CONTROL:
1581 /* add the subclass */
1582 proto_tree_add_uint (packet_type_tree, hf_iax2_cmd_csub, tvb,
1586 if (check_col (pinfo->cinfo, COL_INFO))
1587 col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
1588 val_to_str (csub, iax_cmd_subclasses, "unknown (0x%02x)"));
1589 iax2_info->messageName = val_to_str (csub, iax_cmd_subclasses, "unknown (0x%02x)");
1590 if (csub <= 8) iax2_info->callState = tap_cmd_voip_state[csub];
1593 case AST_FRAME_VOICE:
1595 iax_packet -> codec = codec = uncompress_subclass(csub);
1597 if( packet_type_tree ) {
1599 proto_tree_add_item (packet_type_tree, hf_iax2_voice_csub, tvb, offset+9, 1, FALSE);
1600 item = proto_tree_add_uint (packet_type_tree, hf_iax2_voice_codec, tvb, offset+9, 1, codec);
1601 PROTO_ITEM_SET_GENERATED(item);
1608 iax_call->dst_codec = codec;
1610 iax_call->src_codec = codec;
1614 dissect_payload(tvb, offset, pinfo, iax2_tree, main_tree, ts, FALSE,iax_packet);
1617 case AST_FRAME_VIDEO:
1618 /* bit 6 of the csub is used to represent the rtp 'marker' bit */
1619 rtp_marker = csub & 0x40 ? TRUE:FALSE;
1620 iax_packet -> codec = codec = uncompress_subclass((guint8) (csub & ~40));
1622 if( packet_type_tree ) {
1624 proto_tree_add_item (packet_type_tree, hf_iax2_video_csub, tvb, offset+9, 1, FALSE);
1625 proto_tree_add_item (packet_type_tree, hf_iax2_marker, tvb, offset+9, 1, FALSE);
1626 item = proto_tree_add_uint (packet_type_tree, hf_iax2_video_codec, tvb, offset+9, 1, codec);
1627 PROTO_ITEM_SET_GENERATED(item);
1632 if( iax_call && iax_packet -> first_time ) {
1634 iax_call->dst_vformat = codec;
1636 iax_call->src_vformat = codec;
1640 if( rtp_marker && check_col (pinfo->cinfo, COL_INFO))
1641 col_append_str (pinfo->cinfo, COL_INFO, ", Mark" );
1644 dissect_payload(tvb, offset, pinfo, iax2_tree, main_tree, ts, TRUE, iax_packet);
1647 case AST_FRAME_MODEM:
1648 proto_tree_add_item (packet_type_tree, hf_iax2_modem_csub, tvb, offset+9, 1, FALSE);
1651 if (check_col (pinfo->cinfo, COL_INFO))
1652 col_append_fstr (pinfo->cinfo, COL_INFO, " %s",
1653 val_to_str (csub, iax_modem_subclasses, "unknown (0x%02x)"));
1656 case AST_FRAME_HTML:
1659 proto_tree_add_uint (packet_type_tree, hf_iax2_csub, tvb, offset+9,
1663 if (check_col (pinfo->cinfo, COL_INFO))
1664 col_append_fstr (pinfo->cinfo, COL_INFO, " subclass %d", csub );
1668 /* next time we come to parse this packet, don't propogate the codec into the
1670 iax_packet->first_time = FALSE;
1675 static iax_packet_data *iax2_get_packet_data_for_minipacket(packet_info * pinfo,
1679 /* see if we've seen this packet before */
1680 iax_packet_data *p = (iax_packet_data *)p_get_proto_data(pinfo->fd,proto_iax2);
1683 /* if not, find or create an iax_call info structure for this IAX session. */
1685 iax_call_data *iax_call;
1687 iax_call = iax_lookup_call(pinfo, scallno, 0, &reversed);
1689 p = iax_new_packet_data(iax_call,reversed);
1690 p_add_proto_data(pinfo->fd,proto_iax2,p);
1692 /* set the codec for this frame to be whatever the last full frame used */
1695 p->codec = reversed ? iax_call -> dst_vformat : iax_call -> src_vformat;
1697 p->codec = reversed ? iax_call -> dst_codec : iax_call -> src_codec;
1701 iax2_populate_pinfo_from_packet_data(pinfo, p);
1706 static guint32 dissect_minivideopacket (tvbuff_t * tvb, guint32 offset,
1707 guint16 scallno, packet_info * pinfo,
1708 proto_tree * iax2_tree, proto_tree *main_tree)
1711 iax_packet_data *iax_packet;
1712 gboolean rtp_marker;
1715 ts = tvb_get_ntohs(tvb, offset);
1717 /* bit 15 of the ts is used to represent the rtp 'marker' bit */
1718 rtp_marker = ts & 0x8000 ? TRUE:FALSE;
1721 iax_packet = iax2_get_packet_data_for_minipacket(pinfo, scallno, TRUE);
1724 if( iax_packet->call_data ) {
1726 proto_tree_add_uint (iax2_tree, hf_iax2_callno, tvb, 0, 4,
1727 iax_packet->call_data->forward_circuit_ids[0] );
1728 PROTO_ITEM_SET_GENERATED(item);
1731 proto_tree_add_item (iax2_tree, hf_iax2_minividts, tvb, offset, 2, FALSE);
1732 iax2_add_ts_fields(pinfo, iax2_tree, iax_packet, (guint16)ts);
1733 proto_tree_add_item (iax2_tree, hf_iax2_minividmarker, tvb, offset, 2, FALSE);
1735 iax2_add_ts_fields(pinfo, iax2_tree, iax_packet, (guint16)ts);
1740 if (check_col (pinfo->cinfo, COL_INFO))
1741 col_add_fstr (pinfo->cinfo, COL_INFO,
1742 "Mini video packet, source call# %d, timestamp %ums%s",
1743 scallno, ts, rtp_marker?", Mark":"");
1746 dissect_payload(tvb, offset, pinfo, iax2_tree, main_tree, ts, TRUE, iax_packet);
1748 /* next time we come to parse this packet, don't propogate the codec into the
1750 iax_packet->first_time = FALSE;
1756 dissect_minipacket (tvbuff_t * tvb, guint32 offset, guint16 scallno, packet_info * pinfo, proto_tree * iax2_tree,
1757 proto_tree *main_tree)
1760 iax_packet_data *iax_packet;
1763 ts = tvb_get_ntohs(tvb, offset);
1765 iax_packet = iax2_get_packet_data_for_minipacket(pinfo, scallno, FALSE);
1768 if( iax_packet->call_data ) {
1769 item = proto_tree_add_uint (iax2_tree, hf_iax2_callno, tvb, 0, 4,
1770 iax_packet->call_data->forward_circuit_ids[0] );
1771 PROTO_ITEM_SET_GENERATED(item);
1774 proto_tree_add_uint (iax2_tree, hf_iax2_minits, tvb, offset, 2, ts);
1775 iax2_add_ts_fields(pinfo, iax2_tree, iax_packet,(guint16)ts);
1777 iax2_add_ts_fields(pinfo, iax2_tree, iax_packet, (guint16)ts);
1783 if (check_col (pinfo->cinfo, COL_INFO))
1784 col_add_fstr (pinfo->cinfo, COL_INFO,
1785 "Mini packet, source call# %d, timestamp %ums",
1789 /* XXX fix the timestamp logic */
1790 dissect_payload(tvb, offset, pinfo, iax2_tree, main_tree, ts, FALSE, iax_packet);
1793 /* next time we come to parse this packet, don't propogate the codec into the
1795 iax_packet->first_time = FALSE;
1800 static void process_iax_pdu( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1801 gboolean video, iax_packet_data *iax_packet )
1803 guint32 codec = iax_packet -> codec;
1804 iax_call_data *iax_call = iax_packet -> call_data;
1806 #ifdef DEBUG_DESEGMENT
1807 g_debug("calling process_iax_pdu; len = %u", tvb_reported_length(tvb));
1810 if( !video && iax_call && iax_call->subdissector ) {
1811 call_dissector(iax_call->subdissector, tvb, pinfo, tree);
1812 }else if( codec != 0 && dissector_try_port(iax2_codec_dissector_table, codec, tvb, pinfo, tree )) {
1813 /* codec dissector handled our data */
1815 /* we don't know how to dissect our data: dissect it as data */
1816 call_dissector(data_handle,tvb, pinfo, tree);
1819 #ifdef DEBUG_DESEGMENT
1820 g_debug("called process_iax_pdu; pinfo->desegment_len=%u; pinfo->desegment_offset=%u",
1821 pinfo->desegment_len, pinfo->desegment_offset);
1825 static void desegment_iax(tvbuff_t *tvb, packet_info *pinfo, proto_tree *iax2_tree,
1826 proto_tree *tree, gboolean video, iax_packet_data *iax_packet )
1829 iax_call_data *iax_call = iax_packet -> call_data;
1830 iax_call_dirdata *dirdata;
1831 gpointer value=NULL;
1832 guint32 frag_offset=0;
1833 fragment_data *fd_head;
1834 gboolean must_desegment = FALSE;
1836 DISSECTOR_ASSERT(iax_call);
1838 pinfo->can_desegment = 2;
1839 pinfo->desegment_offset = 0;
1840 pinfo->desegment_len = 0;
1842 #ifdef DEBUG_DESEGMENT
1843 g_debug("dissecting packet %u", pinfo->fd->num);
1846 dirdata = &(iax_call->dirdata[!!(iax_packet->reversed)]);
1848 if((!pinfo->fd->flags.visited && dirdata->current_frag_bytes > 0) ||
1849 (value = g_hash_table_lookup(iax_call->fid_table,
1850 GUINT_TO_POINTER(pinfo->fd->num))) != NULL ) {
1851 /* then we are continuing an already-started pdu */
1853 guint32 frag_len = tvb_reported_length( tvb );
1856 #ifdef DEBUG_DESEGMENT
1857 g_debug("visited: %i; c_f_b: %u; hash: %u->%u", pinfo->fd->flags.visited?1:0,
1858 dirdata->current_frag_bytes, pinfo->fd->num, fid);
1861 if(!pinfo->fd->flags.visited) {
1863 fid = dirdata->current_frag_id;
1864 tot_len = dirdata->current_frag_minlen;
1865 g_hash_table_insert( iax_call->fid_table, GUINT_TO_POINTER(pinfo->fd->num), GUINT_TO_POINTER(fid) );
1866 frag_offset = dirdata->current_frag_bytes;
1867 dirdata->current_frag_bytes += frag_len;
1868 complete = dirdata->current_frag_bytes > tot_len;
1869 #ifdef DEBUG_DESEGMENT
1870 g_debug("hash: %u->%u; frag_offset: %u; c_f_b: %u; totlen: %u",
1871 pinfo->fd->num, fid, frag_offset, dirdata->current_frag_bytes, tot_len );
1874 fid = GPOINTER_TO_UINT(value);
1875 /* these values are unused by fragment_add if pinfo->fd->flags.visited */
1876 dirdata->current_frag_bytes = 0;
1880 /* fragment_add checks for already-added */
1881 fd_head = fragment_add( tvb, 0, pinfo, fid,
1882 iax_call->fragment_table,
1884 frag_len, !complete );
1886 if(fd_head && (pinfo->fd->num == fd_head->reassembled_in)) {
1888 tvbuff_t *next_tvb = tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen);
1889 add_new_data_source(pinfo, next_tvb, "Reassembled IAX2");
1891 process_iax_pdu(next_tvb,pinfo,tree,video,iax_packet);
1893 /* calculate the amount of data which was available to the higher-level
1894 dissector before we added this segment; if the returned offset is
1895 within that section, the higher-level dissector was unable to find any
1896 pdus; if it's after that, it found one or more complete PDUs.
1898 old_len = (gint32)(tvb_reported_length(next_tvb) - frag_len);
1899 if( pinfo->desegment_len &&
1900 pinfo->desegment_offset < old_len ) {
1901 /* oops, it wasn't actually complete */
1902 fragment_set_partial_reassembly(pinfo, fid, iax_call->fragment_table);
1903 if(pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT) {
1904 /* only one more byte should be enough for a retry */
1905 dirdata->current_frag_minlen = fd_head->datalen + 1;
1907 dirdata->current_frag_minlen = fd_head->datalen + pinfo->desegment_len;
1910 /* we successfully dissected some data; create the proto tree items for
1911 * the fragments, and flag any remaining data for desegmentation */
1913 proto_item *iax_tree_item, *frag_tree_item;
1914 /* this nargery is to insert the fragment tree into the main tree
1915 * between the IAX protocol entry and the subdissector entry */
1916 show_fragment_tree(fd_head, &iax2_fragment_items, tree, pinfo, next_tvb, &frag_tree_item);
1917 iax_tree_item = proto_item_get_parent( proto_tree_get_parent( iax2_tree ));
1918 if( frag_tree_item && iax_tree_item )
1919 proto_tree_move_item( tree, iax_tree_item, frag_tree_item );
1921 dirdata->current_frag_minlen = dirdata->current_frag_id = dirdata->current_frag_bytes = 0;
1923 if( pinfo->desegment_len ) {
1924 /* there's a bit of data left to desegment */
1925 must_desegment = TRUE;
1926 /* make desegment_offset relative to our tvb */
1927 pinfo->desegment_offset -= old_len;
1930 /* don't add a 'reassembled in' item for this pdu */
1935 /* This segment was not found in our table, so it doesn't
1936 contain a continuation of a higher-level PDU.
1937 Call the normal subdissector.
1940 process_iax_pdu(tvb,pinfo,tree,video,iax_packet);
1942 if(pinfo->desegment_len) {
1943 /* the higher-level dissector has asked for some more data - ie,
1944 the end of this segment does not coincide with the end of a
1945 higher-level PDU. */
1946 must_desegment = TRUE;
1952 /* must_desegment is set if the end of this segment (or the whole of it)
1953 * contained the start of a higher-level PDU; we must add whatever is left of
1954 * this segment (after pinfo->desegment_offset) to a fragment table for disassembly. */
1955 if(must_desegment) {
1956 guint32 fid = pinfo->fd->num; /* a new fragment id */
1957 guint32 deseg_offset = pinfo->desegment_offset;
1958 guint32 frag_len = tvb_reported_length_remaining(tvb,deseg_offset);
1959 dirdata->current_frag_id = fid;
1960 dirdata->current_frag_bytes = frag_len;
1962 if(pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT) {
1963 /* only one more byte should be enough for a retry */
1964 dirdata->current_frag_minlen = frag_len + 1;
1966 dirdata->current_frag_minlen = frag_len + pinfo->desegment_len;
1969 fd_head = fragment_add(tvb, deseg_offset, pinfo, fid,
1970 iax_call->fragment_table,
1971 0, frag_len, TRUE );
1972 #ifdef DEBUG_DESEGMENT
1973 g_debug("Start offset of undissected bytes: %u; "
1974 "Bytes remaining in this segment: %u; min required bytes: %u\n",
1975 deseg_offset, frag_len, frag_len + pinfo->desegment_len);
1979 /* add a 'reassembled in' item if necessary */
1980 if( fd_head != NULL ) {
1981 guint32 deseg_offset = pinfo->desegment_offset;
1982 if( fd_head->reassembled_in != 0 &&
1983 !(fd_head->flags & FD_PARTIAL_REASSEMBLY) ) {
1984 proto_item *iax_tree_item;
1985 iax_tree_item = proto_tree_add_uint( tree, hf_iax2_reassembled_in,
1986 tvb, deseg_offset, tvb_reported_length_remaining(tvb,deseg_offset),
1987 fd_head->reassembled_in);
1988 PROTO_ITEM_SET_GENERATED(iax_tree_item);
1990 /* this fragment is never reassembled */
1991 proto_tree_add_text( tree, tvb, deseg_offset, -1,
1992 "IAX2 fragment, unfinished");
1995 if( pinfo->desegment_offset == 0 ) {
1996 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAX2");
1997 col_set_str(pinfo->cinfo, COL_INFO, "[IAX2 segment of a reassembled PDU]");
2001 pinfo->can_desegment = 0;
2002 pinfo->desegment_offset = 0;
2003 pinfo->desegment_len = 0;
2006 static void dissect_payload(tvbuff_t *tvb, guint32 offset,
2007 packet_info *pinfo, proto_tree *iax2_tree,
2008 proto_tree *tree, guint32 ts, gboolean video,
2009 iax_packet_data *iax_packet)
2012 gboolean out_of_order = FALSE;
2015 guint32 codec = iax_packet -> codec;
2017 iax_call_data *iax_call = iax_packet -> call_data;
2019 /* keep compiler quiet */
2022 if( offset >= tvb_reported_length (tvb)) {
2023 col_append_str (pinfo->cinfo, COL_INFO, ", empty frame" );
2027 sub_tvb = tvb_new_subset_remaining(tvb, offset);
2029 /* XXX shouldn't pass through out-of-order packets. */
2031 if (check_col (pinfo->cinfo, COL_INFO)) {
2032 if( !video && iax_call && iax_call -> dataformat != 0 ) {
2033 col_append_fstr (pinfo->cinfo, COL_INFO, ", data, format %s",
2034 val_to_str (iax_call -> dataformat,
2035 iax_dataformats, "unknown (0x%02x)"));
2038 col_append_str (pinfo->cinfo, COL_INFO, " (out-of-order packet)");
2041 col_append_fstr (pinfo->cinfo, COL_INFO, ", %s",
2042 val_to_str (codec, codec_types, "unknown (0x%02x)"));
2046 nbytes = tvb_reported_length(sub_tvb);
2047 proto_tree_add_text( iax2_tree, sub_tvb, 0, -1,
2048 "IAX2 payload (%u byte%s)", nbytes,
2049 plurality( nbytes, "", "s" ));
2051 iax2_info->payload_len = nbytes;
2052 iax2_info->payload_data = tvb_get_ptr(sub_tvb, 0, -1);
2054 /* pass the rest of the block to a subdissector */
2055 if(iax_packet->call_data)
2056 desegment_iax( sub_tvb, pinfo, iax2_tree, tree, video, iax_packet );
2058 process_iax_pdu(sub_tvb,pinfo,tree,video,iax_packet);
2065 /* called at the start of a capture. We should clear out our static, per-capture
2070 iax_init_protocol(void)
2078 proto_register_iax2 (void)
2080 /* A header field is something you can search/filter on.
2082 * We create a structure to register our fields. It consists of an
2083 * array of hf_register_info structures, each of which are of the format
2084 * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
2087 static hf_register_info hf[] = {
2089 {&hf_iax2_packet_type,
2090 {"Packet type", "iax2.packet_type", FT_UINT8, BASE_DEC, VALS(iax_packet_types), 0,
2091 "Full/minivoice/minivideo/meta packet",
2095 {"Call identifier", "iax2.call", FT_UINT32, BASE_DEC, NULL, 0,
2096 "This is the identifier Wireshark assigns to identify this call. It does not correspond to any real field in the protocol", HFILL }},
2099 {"Source call", "iax2.src_call", FT_UINT16, BASE_DEC, NULL, 0x7FFF,
2100 "src_call holds the number of this call at the packet source pbx",
2103 /* FIXME could this be turned into a FRAMENUM field? */
2105 {"Destination call", "iax2.dst_call", FT_UINT16, BASE_DEC, NULL, 0x7FFF,
2106 "dst_call holds the number of this call at the packet destination",
2109 {&hf_iax2_retransmission,
2110 {"Retransmission", "iax2.retransmission", FT_BOOLEAN, 16,
2112 "retransmission is set if this packet is a retransmission of an earlier failed packet", HFILL}},
2115 {"Timestamp", "iax2.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
2116 "timestamp is the time, in ms after the start of this call, at which this packet was transmitted",
2120 {"Timestamp", "iax2.timestamp", FT_UINT16, BASE_DEC, NULL, 0x0,
2121 "timestamp is the time, in ms after the start of this call, at which this packet was transmitted",
2124 {&hf_iax2_minividts,
2125 {"Timestamp", "iax2.timestamp", FT_UINT16, BASE_DEC, NULL, 0x7FFF,
2126 "timestamp is the time, in ms after the start of this call, at which this packet was transmitted",
2130 {"Absolute Time", "iax2.abstime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
2131 "The absoulte time of this packet (calculated by adding the IAX timestamp to the start time of this call)",
2135 {"Lateness", "iax2.lateness", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
2136 "The lateness of this packet compared to its timestamp",
2139 {&hf_iax2_minividmarker,
2140 {"Marker", "iax2.video.marker", FT_UINT16, BASE_DEC, NULL, 0x8000,
2141 "RTP end-of-frame marker",
2145 {"Outbound seq.no.", "iax2.oseqno", FT_UINT16, BASE_DEC, NULL,
2147 "oseqno is the sequence no of this packet. The first packet has oseqno==0, and subsequent packets increment the oseqno by 1",
2151 {"Inbound seq.no.", "iax2.iseqno", FT_UINT16, BASE_DEC, NULL, 0x0,
2152 "iseqno is the sequence no of the last successfully received packet",
2156 {"Type", "iax2.type", FT_UINT8, BASE_DEC, VALS (iax_frame_types),
2158 "For full IAX2 frames, type is the type of frame",
2162 {"Unknown subclass", "iax2.subclass", FT_UINT8, BASE_DEC, NULL, 0x0,
2163 "Subclass of unknown type of full IAX2 frame",
2166 {&hf_iax2_dtmf_csub,
2167 {"DTMF subclass (digit)", "iax2.dtmf.subclass", FT_STRINGZ, BASE_NONE, NULL, 0x0,
2168 "DTMF subclass gives the DTMF digit",
2172 {"Control subclass", "iax2.control.subclass", FT_UINT8, BASE_DEC,
2173 VALS (iax_cmd_subclasses), 0x0,
2174 "This gives the command number for a Control packet.", HFILL}},
2177 {"IAX subclass", "iax2.iax.subclass", FT_UINT8, BASE_DEC,
2178 VALS (iax_iax_subclasses),
2180 "IAX subclass gives the command number for IAX signalling packets", HFILL}},
2182 {&hf_iax2_voice_csub,
2183 {"Voice Subclass (compressed codec no)", "iax2.voice.subclass", FT_UINT8, BASE_DEC, NULL, 0x0,
2187 {&hf_iax2_voice_codec,
2188 {"CODEC", "iax2.voice.codec", FT_UINT32, BASE_HEX, VALS (codec_types),
2190 "CODEC gives the codec used to encode audio data", HFILL}},
2192 {&hf_iax2_video_csub,
2193 {"Video Subclass (compressed codec no)", "iax2.video.subclass", FT_UINT8, BASE_DEC, NULL, 0xBF,
2198 {"Marker", "iax2.video.marker", FT_BOOLEAN, 8, NULL, 0x40,
2199 "RTP end-of-frame marker",
2202 {&hf_iax2_video_codec,
2203 {"CODEC", "iax2.video.codec", FT_UINT32, BASE_HEX, VALS (codec_types), 0,
2204 "The codec used to encode video data", HFILL}},
2206 {&hf_iax2_modem_csub,
2207 {"Modem subclass", "iax2.modem.subclass", FT_UINT8, BASE_DEC,
2208 VALS (iax_modem_subclasses),
2210 "Modem subclass gives the type of modem", HFILL}},
2213 * Decoding for the ies
2216 {&hf_IAX_IE_APPARENTADDR_SINFAMILY,
2217 {"Family", "iax2.iax.app_addr.sinfamily", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
2218 {&hf_IAX_IE_APPARENTADDR_SINPORT,
2219 {"Port", "iax2.iax.app_addr.sinport", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
2220 {&hf_IAX_IE_APPARENTADDR_SINADDR,
2221 {"Address", "iax2.iax.app_addr.sinaddr", FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL }},
2223 {&hf_iax2_ies[IAX_IE_CALLED_NUMBER],
2224 {"Number/extension being called", "iax2.iax.called_number",
2226 BASE_NONE, NULL, 0x0, NULL, HFILL}},
2228 {&hf_iax2_ies[IAX_IE_CALLING_NUMBER],
2229 {"Calling number", "iax2.iax.calling_number", FT_STRING,
2233 {&hf_iax2_ies[IAX_IE_CALLING_ANI],
2234 {"Calling number ANI for billing", "iax2.iax.calling_ani",
2236 BASE_NONE, NULL, 0x0, NULL, HFILL}},
2238 {&hf_iax2_ies[IAX_IE_CALLING_NAME],
2239 {"Name of caller", "iax2.iax.calling_name", FT_STRING, BASE_NONE,
2243 {&hf_iax2_ies[IAX_IE_CALLED_CONTEXT],
2244 {"Context for number", "iax2.iax.called_context", FT_STRING,
2246 NULL, 0x0, NULL, HFILL}},
2248 {&hf_iax2_ies[IAX_IE_USERNAME],
2249 {"Username (peer or user) for authentication",
2250 "iax2.iax.username",
2251 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
2253 {&hf_iax2_ies[IAX_IE_PASSWORD],
2254 {"Password for authentication", "iax2.iax.password", FT_STRING,
2255 BASE_NONE, NULL, 0x0, NULL, HFILL}},
2257 {&hf_iax2_ies[IAX_IE_CAPABILITY],
2258 {"Actual codec capability", "iax2.iax.capability", FT_UINT32,
2260 NULL, 0x0, NULL, HFILL}},
2262 {&hf_iax2_ies[IAX_IE_FORMAT],
2263 {"Desired codec format", "iax2.iax.format", FT_UINT32, BASE_HEX,
2264 VALS (codec_types), 0x0, NULL, HFILL}},
2266 {&hf_iax2_ies[IAX_IE_LANGUAGE],
2267 {"Desired language", "iax2.iax.language", FT_STRING, BASE_NONE,
2271 {&hf_iax2_ies[IAX_IE_VERSION],
2272 {"Protocol version", "iax2.iax.version", FT_UINT16, BASE_HEX, NULL,
2276 {&hf_iax2_ies[IAX_IE_ADSICPE],
2277 {"CPE ADSI capability", "iax2.iax.cpe_adsi", FT_UINT16, BASE_HEX,
2281 {&hf_iax2_ies[IAX_IE_DNID],
2282 {"Originally dialed DNID", "iax2.iax.dnid", FT_STRING, BASE_NONE,
2286 {&hf_iax2_ies[IAX_IE_AUTHMETHODS],
2287 {"Authentication method(s)", "iax2.iax.auth.methods", FT_UINT16,
2289 NULL, 0x0, NULL, HFILL}},
2291 {&hf_iax2_ies[IAX_IE_CHALLENGE],
2292 {"Challenge data for MD5/RSA", "iax2.iax.auth.challenge",
2294 BASE_NONE, NULL, 0x0, NULL, HFILL}},
2296 {&hf_iax2_ies[IAX_IE_MD5_RESULT],
2297 {"MD5 challenge result", "iax2.iax.auth.md5", FT_STRING,
2301 {&hf_iax2_ies[IAX_IE_RSA_RESULT],
2302 {"RSA challenge result", "iax2.iax.auth.rsa", FT_STRING,
2306 {&hf_iax2_ies[IAX_IE_REFRESH],
2307 {"When to refresh registration", "iax2.iax.refresh", FT_INT16,
2309 NULL, 0x0, NULL, HFILL}},
2311 {&hf_iax2_ies[IAX_IE_DPSTATUS],
2312 {"Dialplan status", "iax2.iax.dialplan_status", FT_UINT16,
2316 {&hf_iax2_ies[IAX_IE_CALLNO],
2317 {"Call number of peer", "iax2.iax.call_no", FT_UINT16, BASE_DEC,
2321 {&hf_iax2_ies[IAX_IE_CAUSE],
2322 {"Cause", "iax2.iax.cause", FT_STRING, BASE_NONE, NULL, 0x0, NULL,
2325 {&hf_iax2_ies[IAX_IE_IAX_UNKNOWN],
2326 {"Unknown IAX command", "iax2.iax.iax_unknown", FT_BYTES,
2330 {&hf_iax2_ies[IAX_IE_MSGCOUNT],
2331 {"How many messages waiting", "iax2.iax.msg_count", FT_INT16,
2333 NULL, 0x0, NULL, HFILL}},
2335 {&hf_iax2_ies[IAX_IE_AUTOANSWER],
2336 {"Request auto-answering", "iax2.iax.autoanswer", FT_NONE,
2338 NULL, 0x0, NULL, HFILL}},
2340 {&hf_iax2_ies[IAX_IE_MUSICONHOLD],
2341 {"Request musiconhold with QUELCH", "iax2.iax.moh", FT_NONE,
2343 NULL, 0x0, NULL, HFILL}},
2345 {&hf_iax2_ies[IAX_IE_TRANSFERID],
2346 {"Transfer Request Identifier", "iax2.iax.transferid", FT_UINT32,
2347 BASE_HEX, NULL, 0x0, NULL, HFILL}},
2349 {&hf_iax2_ies[IAX_IE_RDNIS],
2350 {"Referring DNIS", "iax2.iax.rdnis", FT_STRING, BASE_NONE, NULL,
2354 {&hf_iax2_ies[IAX_IE_PROVISIONING],
2355 {"Provisioning info","iax2.iax.provisioning", FT_STRING, BASE_NONE,
2356 NULL, 0x0, NULL, HFILL}},
2358 {&hf_iax2_ies[IAX_IE_AESPROVISIONING],
2359 {"AES Provisioning info","iax2.iax.aesprovisioning", FT_STRING, BASE_NONE,
2360 NULL, 0x0, NULL, HFILL}},
2362 {&hf_iax2_ies[IAX_IE_DATETIME],
2363 {"Date/Time", "iax2.iax.datetime.raw", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
2365 {&hf_iax2_ie_datetime,
2366 {"Date/Time", "iax2.iax.datetime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
2368 {&hf_iax2_ies[IAX_IE_DEVICETYPE],
2369 {"Device type", "iax2.iax.devicetype", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
2371 {&hf_iax2_ies[IAX_IE_SERVICEIDENT],
2372 {"Service identifier", "iax2.iax.serviceident", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
2374 {&hf_iax2_ies[IAX_IE_FIRMWAREVER],
2375 {"Firmware version", "iax2.iax.firmwarever", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2377 {&hf_iax2_ies[IAX_IE_FWBLOCKDESC],
2378 {"Firmware block description", "iax2.iax.fwblockdesc", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2380 {&hf_iax2_ies[IAX_IE_FWBLOCKDATA],
2381 {"Firmware block of data", "iax2.iax.fwblockdata", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
2383 {&hf_iax2_ies[IAX_IE_PROVVER],
2384 {"Provisioning version", "iax2.iax.provver", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2386 {&hf_iax2_ies[IAX_IE_CALLINGPRES],
2387 {"Calling presentation", "iax2.iax.callingpres", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2389 {&hf_iax2_ies[IAX_IE_CALLINGTON],
2390 {"Calling type of number", "iax2.iax.callington", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2392 {&hf_iax2_ies[IAX_IE_CALLINGTNS],
2393 {"Calling transit network select", "iax2.iax.callingtns", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2395 {&hf_iax2_ies[IAX_IE_SAMPLINGRATE],
2396 {"Supported sampling rates", "iax2.iax.samplingrate", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2398 {&hf_iax2_ies[IAX_IE_CAUSECODE],
2399 {"Hangup cause", "iax2.iax.causecode", FT_UINT8, BASE_HEX, VALS(iax_causecodes),
2402 {&hf_iax2_ies[IAX_IE_ENCRYPTION],
2403 {"Encryption format", "iax2.iax.encryption", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2405 {&hf_iax2_ies[IAX_IE_ENCKEY],
2406 {"Encryption key", "iax2.iax.enckey", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
2408 {&hf_iax2_ies[IAX_IE_CODEC_PREFS],
2409 {"Codec negotiation", "iax2.iax.codecprefs", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
2411 {&hf_iax2_ies[IAX_IE_RR_JITTER],
2412 {"Received jitter (as in RFC1889)", "iax2.iax.rrjitter", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2414 {&hf_iax2_ies[IAX_IE_RR_LOSS],
2415 {"Received loss (high byte loss pct, low 24 bits loss count, as in rfc1889)", "iax2.iax.rrloss",
2416 FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2418 {&hf_iax2_ies[IAX_IE_RR_PKTS],
2419 {"Total frames received", "iax2.iax.rrpkts", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2421 {&hf_iax2_ies[IAX_IE_RR_DELAY],
2422 {"Max playout delay in ms for received frames", "iax2.iax.rrdelay", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2424 {&hf_iax2_ies[IAX_IE_RR_DROPPED],
2425 {"Dropped frames (presumably by jitterbuffer)", "iax2.iax.rrdropped", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2427 {&hf_iax2_ies[IAX_IE_RR_OOO],
2428 {"Frame received out of order", "iax2.iax.rrooo", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL}},
2430 {&hf_iax2_ies[IAX_IE_DATAFORMAT],
2431 {"Data call format", "iax2.iax.dataformat", FT_UINT32, BASE_HEX,
2432 VALS(iax_dataformats), 0x0, NULL, HFILL}},
2434 {&hf_IAX_IE_UNKNOWN_BYTE,
2435 {"Unknown", "iax2.iax.unknownbyte", FT_UINT8, BASE_HEX, NULL,
2436 0x0, "Raw data for unknown IEs",
2438 {&hf_IAX_IE_UNKNOWN_I16,
2439 {"Unknown", "iax2.iax.unknownshort", FT_UINT16, BASE_HEX, NULL,
2440 0x0, "Raw data for unknown IEs",
2442 {&hf_IAX_IE_UNKNOWN_I32,
2443 {"Unknown", "iax2.iax.unknownlong", FT_UINT32, BASE_HEX, NULL,
2444 0x0, "Raw data for unknown IEs",
2446 {&hf_IAX_IE_UNKNOWN_BYTES,
2447 {"Unknown", "iax2.iax.unknownstring", FT_STRING, BASE_NONE, NULL,
2448 0x0, "Raw data for unknown IEs",
2452 {&hf_iax2_cap_g723_1,
2453 {"G.723.1 compression", "iax2.cap.g723_1", FT_BOOLEAN, 32,
2454 TFS(&tfs_supported_not_supported), AST_FORMAT_G723_1,
2458 {"GSM compression", "iax2.cap.gsm", FT_BOOLEAN, 32,
2459 TFS(&tfs_supported_not_supported), AST_FORMAT_GSM,
2463 {"Raw mu-law data (G.711)", "iax2.cap.ulaw",FT_BOOLEAN, 32,
2464 TFS(&tfs_supported_not_supported), AST_FORMAT_ULAW,
2468 {"Raw A-law data (G.711)", "iax2.cap.alaw",FT_BOOLEAN, 32,
2469 TFS(&tfs_supported_not_supported), AST_FORMAT_ALAW,
2473 {"G.726 compression", "iax2.cap.g726",FT_BOOLEAN, 32,
2474 TFS(&tfs_supported_not_supported), AST_FORMAT_G726,
2477 {&hf_iax2_cap_adpcm,
2478 {"ADPCM", "iax2.cap.adpcm", FT_BOOLEAN, 32,
2479 TFS(&tfs_supported_not_supported), AST_FORMAT_ADPCM,
2482 {&hf_iax2_cap_slinear,
2483 {"Raw 16-bit Signed Linear (8000 Hz) PCM", "iax2.cap.slinear",
2484 FT_BOOLEAN, 32, TFS(&tfs_supported_not_supported), AST_FORMAT_SLINEAR,
2487 {&hf_iax2_cap_lpc10,
2488 {"LPC10, 180 samples/frame", "iax2.cap.lpc10", FT_BOOLEAN, 32,
2489 TFS(&tfs_supported_not_supported), AST_FORMAT_LPC10,
2492 {&hf_iax2_cap_g729a,
2493 {"G.729a Audio", "iax2.cap.g729a", FT_BOOLEAN, 32,
2494 TFS(&tfs_supported_not_supported), AST_FORMAT_G729A,
2497 {&hf_iax2_cap_speex,
2498 {"SPEEX Audio", "iax2.cap.speex", FT_BOOLEAN, 32,
2499 TFS(&tfs_supported_not_supported), AST_FORMAT_SPEEX,
2503 {"iLBC Free compressed Audio", "iax2.cap.ilbc", FT_BOOLEAN, 32,
2504 TFS(&tfs_supported_not_supported), AST_FORMAT_ILBC,
2508 {"JPEG images", "iax2.cap.jpeg", FT_BOOLEAN, 32,
2509 TFS(&tfs_supported_not_supported), AST_FORMAT_JPEG,
2513 {"PNG images", "iax2.cap.png", FT_BOOLEAN, 32,
2514 TFS(&tfs_supported_not_supported), AST_FORMAT_PNG,
2518 {"H.261 video", "iax2.cap.h261", FT_BOOLEAN, 32,
2519 TFS(&tfs_supported_not_supported), AST_FORMAT_H261,
2523 {"H.263 video", "iax2.cap.h263", FT_BOOLEAN, 32,
2524 TFS(&tfs_supported_not_supported), AST_FORMAT_H263,
2527 /* reassembly stuff */
2528 {&hf_iax2_fragments,
2529 {"IAX2 Fragments", "iax2.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
2533 {"IAX2 Fragment data", "iax2.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2536 {&hf_iax2_fragment_overlap,
2537 {"Fragment overlap", "iax2.fragment.overlap", FT_BOOLEAN, BASE_NONE,
2538 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
2540 {&hf_iax2_fragment_overlap_conflict,
2541 {"Conflicting data in fragment overlap", "iax2.fragment.overlap.conflict",
2542 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2543 "Overlapping fragments contained conflicting data", HFILL }},
2545 {&hf_iax2_fragment_multiple_tails,
2546 {"Multiple tail fragments found", "iax2.fragment.multipletails",
2547 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2548 "Several tails were found when defragmenting the packet", HFILL }},
2550 {&hf_iax2_fragment_too_long_fragment,
2551 {"Fragment too long", "iax2.fragment.toolongfragment",
2552 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2553 "Fragment contained data past end of packet", HFILL }},
2555 {&hf_iax2_fragment_error,
2556 {"Defragmentation error", "iax2.fragment.error",
2557 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2558 "Defragmentation error due to illegal fragments", HFILL }},
2560 {&hf_iax2_reassembled_in,
2561 {"IAX2 fragment, reassembled in frame", "iax2.reassembled_in",
2562 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2563 "This IAX2 packet is reassembled in this frame", HFILL }}
2566 static gint *ett[] = {
2568 &ett_iax2_full_mini_subtree,
2572 &ett_iax2_ies_apparent_addr,
2577 /* initialise the hf_iax2_ies[] array to -1 */
2578 memset(hf_iax2_ies,0xff,sizeof(hf_iax2_ies));
2581 proto_register_protocol ("Inter-Asterisk eXchange v2", "IAX2", "iax2");
2582 proto_register_field_array (proto_iax2, hf, array_length (hf));
2583 proto_register_subtree_array (ett, array_length (ett));
2585 register_dissector("iax2", dissect_iax2, proto_iax2);
2587 iax2_codec_dissector_table = register_dissector_table(
2588 "iax2.codec","IAX codec number", FT_UINT32, BASE_HEX);
2589 iax2_dataformat_dissector_table = register_dissector_table(
2590 "iax2.dataformat","IAX dataformat number", FT_UINT32, BASE_HEX);
2592 /* register our init routine to be called at the start of a capture,
2593 to clear out our hash tables etc */
2594 register_init_routine(&iax_init_protocol);
2595 iax2_tap = register_tap("IAX2");
2599 proto_reg_handoff_iax2 (void)
2601 dissector_add("udp.port", IAX2_PORT, find_dissector("iax2"));
2602 dissector_add("iax2.dataformat", AST_DATAFORMAT_V110, find_dissector("v110"));
2603 data_handle = find_dissector("data");
2608 * This sets up the indentation style for this file in emacs.
2615 * vim:set ts=8 sts=2 sw=2 noet: