MSWSP: fix dissect_mswsp_smb()
[wireshark-wip.git] / epan / dissectors / packet-h223.c
blob0b1a60bc1d9d19e07e0cced5ec9633e9c824a1f2
1 /* packet-h223.c
2 * Routines for H.223 packet dissection
3 * Copyright (c) 2004-5 MX Telecom Ltd <richardv@mxtelecom.com>
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <glib.h>
29 #include <epan/wmem/wmem.h>
30 #include <epan/bitswap.h>
31 #include <epan/circuit.h>
32 #include <epan/conversation.h>
33 #include <epan/packet.h>
34 #include <epan/exceptions.h>
35 #include <epan/stream.h>
36 #include <epan/reassemble.h>
37 #include <epan/golay.h>
38 #include <epan/iax2_codec_type.h>
39 #include <epan/show_exception.h>
40 #include <epan/asn1.h>
41 #include <epan/dissectors/packet-h245.h>
43 #include "packet-h223.h"
45 #include <string.h>
47 /* #define DEBUG_H223 */
49 /* debug the mux-pdu defragmentation code. warning: verbose output! */
50 /* #define DEBUG_H223_FRAGMENTATION */
52 #define PROTO_TAG_H223 "H223"
54 /* Wireshark ID of the H.223 protocol */
55 static int proto_h223 = -1;
57 /* The following hf_* variables are used to hold the Wireshark IDs of
58 * our header fields; they are filled out when we call
59 * proto_register_field_array() in proto_register_h223()
61 /* static int hf_h223_non_h223_data = -1; */
62 static int hf_h223_mux_stuffing_pdu = -1;
63 static int hf_h223_mux_pdu = -1;
64 static int hf_h223_mux_header = -1;
65 static int hf_h223_mux_rawhdr = -1;
66 static int hf_h223_mux_correctedhdr = -1;
67 static int hf_h223_mux_mc = -1;
68 static int hf_h223_mux_mpl = -1;
69 static int hf_h223_mux_deact = -1;
70 static int hf_h223_mux_vc = -1;
71 static int hf_h223_mux_extra = -1;
72 static int hf_h223_mux_hdlc2 = -1;
73 static int hf_h223_mux_fragments = -1;
74 static int hf_h223_mux_fragment = -1;
75 static int hf_h223_mux_fragment_overlap = -1;
76 static int hf_h223_mux_fragment_overlap_conflict = -1;
77 static int hf_h223_mux_fragment_multiple_tails = -1;
78 static int hf_h223_mux_fragment_too_long_fragment = -1;
79 static int hf_h223_mux_fragment_error = -1;
80 static int hf_h223_mux_fragment_count = -1;
81 static int hf_h223_mux_reassembled_in = -1;
82 static int hf_h223_mux_reassembled_length = -1;
84 static int hf_h223_al_fragments = -1;
85 static int hf_h223_al_fragment = -1;
86 static int hf_h223_al_fragment_overlap = -1;
87 static int hf_h223_al_fragment_overlap_conflict = -1;
88 static int hf_h223_al_fragment_multiple_tails = -1;
89 static int hf_h223_al_fragment_too_long_fragment = -1;
90 static int hf_h223_al_fragment_error = -1;
91 static int hf_h223_al_fragment_count = -1;
92 static int hf_h223_al_reassembled_in = -1;
93 static int hf_h223_al_reassembled_length = -1;
95 static int hf_h223_al1 = -1;
96 static int hf_h223_al1_framed = -1;
97 static int hf_h223_al2 = -1;
98 static int hf_h223_al2_sequenced = -1;
99 static int hf_h223_al2_unsequenced = -1;
100 static int hf_h223_al2_seqno = -1;
101 static int hf_h223_al2_crc = -1;
102 static int hf_h223_al2_crc_bad = -1;
104 static int hf_h223_al_payload = -1;
106 /* These are the ids of the subtrees that we may be creating */
107 static gint ett_h223 = -1;
108 static gint ett_h223_non_h223_data = -1;
109 static gint ett_h223_mux_stuffing_pdu = -1;
110 static gint ett_h223_mux_pdu = -1;
111 static gint ett_h223_mux_header = -1;
112 static gint ett_h223_mux_deact = -1;
113 static gint ett_h223_mux_vc = -1;
114 static gint ett_h223_mux_extra = -1;
115 static gint ett_h223_mux_fragments = -1;
116 static gint ett_h223_mux_fragment = -1;
117 static gint ett_h223_al_fragments = -1;
118 static gint ett_h223_al_fragment = -1;
119 static gint ett_h223_al1 = -1;
120 static gint ett_h223_al2 = -1;
121 static gint ett_h223_al_payload = -1;
123 /* These are the handles of our subdissectors */
124 static dissector_handle_t data_handle;
125 static dissector_handle_t srp_handle;
127 static const fragment_items h223_mux_frag_items _U_ = {
128 &ett_h223_mux_fragment,
129 &ett_h223_mux_fragments,
130 &hf_h223_mux_fragments,
131 &hf_h223_mux_fragment,
132 &hf_h223_mux_fragment_overlap,
133 &hf_h223_mux_fragment_overlap_conflict,
134 &hf_h223_mux_fragment_multiple_tails,
135 &hf_h223_mux_fragment_too_long_fragment,
136 &hf_h223_mux_fragment_error,
137 &hf_h223_mux_fragment_count,
138 &hf_h223_mux_reassembled_in,
139 &hf_h223_mux_reassembled_length,
140 /* Reassembled data field */
141 NULL,
142 "fragments"
145 static const fragment_items h223_al_frag_items = {
146 &ett_h223_al_fragment,
147 &ett_h223_al_fragments,
148 &hf_h223_al_fragments,
149 &hf_h223_al_fragment,
150 &hf_h223_al_fragment_overlap,
151 &hf_h223_al_fragment_overlap_conflict,
152 &hf_h223_al_fragment_multiple_tails,
153 &hf_h223_al_fragment_too_long_fragment,
154 &hf_h223_al_fragment_error,
155 &hf_h223_al_fragment_count,
156 &hf_h223_al_reassembled_in,
157 &hf_h223_al_reassembled_length,
158 /* Reassembled data field */
159 NULL,
160 "fragments"
163 /* this is a fudge to pass pdu_offset into add_h223_mux_element() */
164 static guint32 pdu_offset;
166 /***************************************************************************
168 * virtual circuit number handling
170 * we have to be able to manage more than one H.223 call at a time,
171 * so have a hash which maps {call,vc} to an integer.
174 typedef struct _h223_call_info h223_call_info;
176 typedef struct {
177 const h223_call_info* call; /* h223 call */
178 guint32 vc; /* child circuit */
179 } circuit_chain_key;
181 static GHashTable *circuit_chain_hashtable = NULL;
182 static guint circuit_chain_count = 1;
184 /* Hash Functions */
185 static gint
186 circuit_chain_equal(gconstpointer v, gconstpointer w)
188 const circuit_chain_key *v1 = (const circuit_chain_key *)v;
189 const circuit_chain_key *v2 = (const circuit_chain_key *)w;
190 gint result;
191 result = ( v1->call == v2->call &&
192 v1->vc == v2 -> vc );
193 return result;
196 static guint
197 circuit_chain_hash (gconstpointer v)
199 const circuit_chain_key *key = (const circuit_chain_key *)v;
200 guint hash_val = ((guint32)(unsigned long)(key->call))^(((guint32)key->vc) << 16);
201 return hash_val;
204 static guint32
205 circuit_chain_lookup(const h223_call_info* call_info, guint32 child_vc)
207 circuit_chain_key key, *new_key;
208 guint32 circuit_id;
209 key.call = call_info;
210 key.vc = child_vc;
211 circuit_id = GPOINTER_TO_UINT(g_hash_table_lookup( circuit_chain_hashtable, &key ));
212 if( circuit_id == 0 ) {
213 new_key = wmem_new(wmem_file_scope(), circuit_chain_key);
214 *new_key = key;
215 circuit_id = ++circuit_chain_count;
216 g_hash_table_insert(circuit_chain_hashtable, new_key, GUINT_TO_POINTER(circuit_id));
218 return circuit_id;
221 static void
222 circuit_chain_init(void)
224 if (circuit_chain_hashtable)
225 g_hash_table_destroy(circuit_chain_hashtable);
226 circuit_chain_hashtable = g_hash_table_new(circuit_chain_hash, circuit_chain_equal);
227 circuit_chain_count = 1;
231 /***************************************************************************
233 * Call information management
237 /* we keep information on each call in an h223_call_info structure
239 * We attach the h223_call_info structures to individual calls with
240 * circuit_add_proto_data().
243 typedef struct _h223_mux_element_listitem h223_mux_element_listitem;
244 struct _h223_mux_element_listitem {
245 h223_mux_element *me;
246 guint32 first_frame;
247 guint32 pdu_offset;
248 h223_mux_element_listitem *next;
251 /* we have this information for each stream */
252 typedef struct {
253 h223_mux_element_listitem* mux_table[16];
254 } h223_call_direction_data;
257 struct _h223_call_info {
258 /* H.223 level: 0 for standard H223, 1, 2 or 3 for the enhanced protocols
259 specified in the annexes
261 int h223_level;
263 /* for H.223 streams over TCP (as opposed to IAX), this
264 stores the source address and port of the first packet spotted,
265 so that we can differentiate directions.
267 address srcaddress;
268 guint32 srcport;
270 h223_call_direction_data direction_data[2];
273 typedef struct _h223_lc_params_listitem h223_lc_params_listitem;
274 struct _h223_lc_params_listitem
276 h223_lc_params *lc_params;
277 guint32 first_frame;
278 guint32 last_frame;
279 h223_lc_params_listitem *next;
282 typedef struct {
283 h223_lc_params_listitem *lc_params[2];
284 h223_call_info *call_info;
285 } h223_vc_info;
287 static void
288 add_h223_mux_element(h223_call_direction_data *direct, guint8 mc, h223_mux_element *me, guint32 framenum)
290 h223_mux_element_listitem *li;
291 h223_mux_element_listitem **old_li_ptr;
292 h223_mux_element_listitem *old_li;
294 DISSECTOR_ASSERT(mc < 16);
296 li = wmem_new(wmem_file_scope(), h223_mux_element_listitem);
297 old_li_ptr = &(direct->mux_table[mc]);
298 old_li = *old_li_ptr;
299 if( !old_li ) {
300 direct->mux_table[mc] = li;
301 } else {
302 while( old_li->next ) {
303 old_li_ptr = &(old_li->next);
304 old_li = *old_li_ptr;
306 if( framenum < old_li->first_frame || (framenum == old_li->first_frame && pdu_offset < old_li->pdu_offset) )
307 return;
308 else if ( framenum == old_li->first_frame && pdu_offset == old_li->pdu_offset )
309 *old_li_ptr = li; /* replace the tail of the list with the new item, since */
310 /* a single h223 pdu has just set the same MC twice.. */
311 else
312 old_li->next = li;
314 li->first_frame = framenum;
315 li->pdu_offset = pdu_offset;
316 li->next = 0;
317 li->me = me;
320 static h223_mux_element*
321 find_h223_mux_element(h223_call_direction_data* direct, guint8 mc, guint32 framenum, guint32 pkt_offset)
323 h223_mux_element_listitem* li;
325 DISSECTOR_ASSERT(mc < 16);
327 li = direct->mux_table[mc];
329 while( li && li->next && li->next->first_frame < framenum )
330 li = li->next;
331 while( li && li->next && li->next->first_frame == framenum && li->next->pdu_offset < pkt_offset )
332 li = li->next;
333 if( li ) {
334 return li->me;
335 } else {
336 return NULL;
340 static void
341 add_h223_lc_params(h223_vc_info* vc_info, int direction, h223_lc_params *lc_params, guint32 framenum )
343 h223_lc_params_listitem *li = wmem_new(wmem_file_scope(), h223_lc_params_listitem);
344 h223_lc_params_listitem **old_li_ptr = &(vc_info->lc_params[direction ? 0 : 1]);
345 h223_lc_params_listitem *old_li = *old_li_ptr;
346 if( !old_li ) {
347 vc_info->lc_params[direction ? 0 : 1] = li;
348 } else {
349 while( old_li->next ) {
350 old_li_ptr = &(old_li->next);
351 old_li = *old_li_ptr;
353 if( framenum < old_li->first_frame )
354 return;
355 else if( framenum == old_li->first_frame )
356 *old_li_ptr = li;
357 else {
358 old_li->next = li;
359 old_li->last_frame = framenum - 1;
362 li->first_frame = framenum;
363 li->last_frame = 0;
364 li->next = 0;
365 li->lc_params = lc_params;
368 static h223_lc_params*
369 find_h223_lc_params(h223_vc_info* vc_info, int direction, guint32 framenum)
371 h223_lc_params_listitem* li = vc_info->lc_params[direction? 0 : 1];
372 while( li && li->next && li->next->first_frame <= framenum )
373 li = li->next;
374 if( li )
375 return li->lc_params;
376 else
377 return NULL;
380 static void
381 init_direction_data(h223_call_direction_data *direct)
383 int i;
384 h223_mux_element *mc0_element;
386 for ( i = 0; i < 16; ++i )
387 direct->mux_table[i] = NULL;
389 /* set up MC 0 to contain just VC 0 */
390 mc0_element = wmem_new(wmem_file_scope(), h223_mux_element);
391 add_h223_mux_element( direct, 0, mc0_element, 0 );
392 mc0_element->sublist = NULL;
393 mc0_element->vc = 0;
394 mc0_element->repeat_count = 0; /* until closing flag */
395 mc0_element->next = NULL;
398 static h223_vc_info*
399 h223_vc_info_new( h223_call_info* call_info )
401 h223_vc_info *vc_info = wmem_new(wmem_file_scope(), h223_vc_info);
402 vc_info->lc_params[0] = vc_info->lc_params[1] = NULL;
403 vc_info->call_info = call_info;
404 return vc_info;
407 static void
408 init_logical_channel( guint32 start_frame, h223_call_info* call_info, int vc, int direction, h223_lc_params* params )
410 guint32 circuit_id = circuit_chain_lookup(call_info, vc);
411 circuit_t *subcircuit;
412 h223_vc_info *vc_info;
413 subcircuit = find_circuit( CT_H223, circuit_id, start_frame );
415 if( subcircuit == NULL ) {
416 subcircuit = circuit_new( CT_H223, circuit_id, start_frame );
417 #ifdef DEBUG_H223
418 g_debug("%d: Created new circuit %d for call %p VC %d", start_frame, circuit_id, call_info, vc);
419 #endif
420 vc_info = h223_vc_info_new( call_info );
421 circuit_add_proto_data( subcircuit, proto_h223, vc_info );
422 } else {
423 vc_info = (h223_vc_info *)circuit_get_proto_data( subcircuit, proto_h223 );
425 add_h223_lc_params( vc_info, direction, params, start_frame );
428 /* create a brand-new h223_call_info structure */
429 static h223_call_info *
430 create_call_info( guint32 start_frame )
432 h223_call_info *datax;
433 h223_lc_params *vc0_params;
435 datax = wmem_new(wmem_file_scope(), h223_call_info);
437 /* initialise the call info */
438 init_direction_data(&datax -> direction_data[0]);
439 init_direction_data(&datax -> direction_data[1]);
441 /* FIXME shouldn't this be figured out dynamically? */
442 datax -> h223_level = 2;
444 vc0_params = wmem_new(wmem_file_scope(), h223_lc_params);
445 vc0_params->al_type = al1Framed;
446 vc0_params->al_params = NULL;
447 vc0_params->segmentable = TRUE;
448 vc0_params->subdissector = srp_handle;
449 init_logical_channel( start_frame, datax, 0, P2P_DIR_SENT, vc0_params );
450 init_logical_channel( start_frame, datax, 0, P2P_DIR_RECV, vc0_params );
451 return datax;
454 /* find or create call_info struct for calls over circuits (eg, IAX) */
455 static h223_call_info *
456 find_or_create_call_info_circ(packet_info * pinfo)
458 h223_call_info *datax;
459 circuit_t *circ = NULL;
461 if(pinfo->ctype != CT_NONE)
462 circ = find_circuit( pinfo->ctype, pinfo->circuit_id, pinfo->fd->num );
463 if(circ == NULL)
464 return NULL;
466 datax = (h223_call_info *)circuit_get_proto_data(circ, proto_h223);
468 if( datax == NULL ) {
469 datax = create_call_info(pinfo->fd->num);
471 #ifdef DEBUG_H223
472 g_debug("%u: Created new call %p for circuit %p ctype %d, id %u",
473 pinfo->fd->num, datax, circ, pinfo->ctype, pinfo->circuit_id);
474 #endif
475 circuit_add_proto_data(circ, proto_h223, datax);
478 /* work out what direction we're really going in */
479 if( pinfo->p2p_dir < 0 || pinfo->p2p_dir > 1)
480 pinfo->p2p_dir = P2P_DIR_SENT;
482 return datax;
485 /* find or create call_info struct for calls over conversations (eg, RTP) */
486 static h223_call_info *
487 find_or_create_call_info_conv(packet_info * pinfo)
489 h223_call_info *datax;
490 conversation_t *conv;
492 /* assume we're running atop TCP or RTP; use the conversation support */
493 conv = find_conversation( pinfo->fd->num,
494 &pinfo->src,&pinfo->dst,
495 pinfo->ptype,
496 pinfo->srcport,pinfo->destport, 0 );
498 /* both RTP and TCP track their conversations, so just assert here if
499 * we can't find one */
500 DISSECTOR_ASSERT(conv);
502 datax = (h223_call_info *)conversation_get_proto_data(conv, proto_h223);
504 if(datax == NULL && pinfo->ptype == PT_UDP ) {
505 conversation_t *conv2;
507 /* RTP tracks the two sides of the conversation totally separately;
508 * this messes us up totally.
510 * Look for another converstation, going in the opposite direction.
512 conv2 = find_conversation( pinfo->fd->num,
513 &pinfo->dst,&pinfo->src,
514 pinfo->ptype,
515 pinfo->destport,pinfo->srcport, 0 );
516 if(conv2 != NULL)
517 datax = (h223_call_info *)conversation_get_proto_data(conv2, proto_h223);
519 if(datax != NULL) {
520 #ifdef DEBUG_H223
521 g_debug("%u: Identified conv %p as reverse of conv %p with call %p and type=%u src=%u.%u.%u.%u:%u dst=%u.%u.%u.%u:%u",
522 pinfo->fd->num, conv, conv2, datax, pinfo->ptype,
523 pinfo->dst.data[0], pinfo->dst.data[1], pinfo->dst.data[2], pinfo->dst.data[3],
524 pinfo->destport,
525 pinfo->src.data[0], pinfo->src.data[1], pinfo->src.data[2], pinfo->src.data[3],
526 pinfo->srcport);
527 #endif
528 conversation_add_proto_data(conv, proto_h223, datax);
532 /* we still haven't found any call data - create a new one for this
533 * conversation */
534 if(datax == NULL) {
535 datax = create_call_info(pinfo->fd->num);
537 #ifdef DEBUG_H223
538 g_debug("%u: Created new call %p for conv %p type=%u src=%u.%u.%u.%u:%u dst=%u.%u.%u.%u:%u",
539 pinfo->fd->num, datax, conv, pinfo->ptype,
540 pinfo->src.data[0], pinfo->src.data[1], pinfo->src.data[2], pinfo->src.data[3],
541 pinfo->srcport,
542 pinfo->dst.data[0], pinfo->dst.data[1], pinfo->dst.data[2], pinfo->dst.data[3],
543 pinfo->destport);
544 #endif
546 conversation_add_proto_data(conv, proto_h223, datax);
547 /* add the source details so we can distinguish directions
548 * in future */
549 COPY_ADDRESS(&(datax -> srcaddress), &(pinfo->src));
550 datax -> srcport = pinfo->srcport;
553 /* work out what direction we're really going in */
554 if( ADDRESSES_EQUAL( &(pinfo->src), &(datax->srcaddress))
555 && pinfo->srcport == datax->srcport )
556 pinfo->p2p_dir = P2P_DIR_SENT;
557 else
558 pinfo->p2p_dir = P2P_DIR_RECV;
560 return datax;
563 static h223_call_info *
564 find_or_create_call_info ( packet_info * pinfo )
566 h223_call_info *datax;
568 datax = find_or_create_call_info_circ(pinfo);
569 if(datax == NULL)
570 datax = find_or_create_call_info_conv(pinfo);
571 return datax;
574 /* called from the h245 dissector to handle a MultiplexEntrySend message */
575 static void
576 h223_set_mc( packet_info* pinfo, guint8 mc, h223_mux_element* me )
578 circuit_t *circ = find_circuit( pinfo->ctype, pinfo->circuit_id, pinfo->fd->num );
579 h223_vc_info* vc_info;
581 /* if this h245 pdu packet came from an h223 circuit, add the details on
582 * the new mux entry */
583 if(circ) {
584 vc_info = (h223_vc_info *)circuit_get_proto_data(circ, proto_h223);
585 add_h223_mux_element( &(vc_info->call_info->direction_data[pinfo->p2p_dir ? 0 : 1]), mc, me, pinfo->fd->num );
589 /* called from the h245 dissector to handle an OpenLogicalChannelAck message */
590 static void
591 h223_add_lc( packet_info* pinfo, guint16 lc, h223_lc_params* params )
593 circuit_t *circ = find_circuit( pinfo->ctype, pinfo->circuit_id, pinfo->fd->num );
594 h223_vc_info* vc_info;
596 /* if this h245 pdu packet came from an h223 circuit, add the details on
597 * the new channel */
598 if(circ) {
599 vc_info = (h223_vc_info *)circuit_get_proto_data(circ, proto_h223);
600 init_logical_channel( pinfo->fd->num, vc_info->call_info, lc, pinfo->p2p_dir, params );
604 /************************************************************************************
606 * AL-PDU dissection
609 static const guint8 crctable[256] = {
610 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
611 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
612 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
613 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
614 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
615 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
616 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
617 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
618 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
619 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
620 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
621 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
622 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
623 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
624 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
625 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf };
627 static guint8 h223_al2_crc8bit( tvbuff_t *tvb ) {
628 guint32 len = tvb_reported_length(tvb) - 1;
629 const guint8* datax = tvb_get_ptr( tvb, 0, len );
630 unsigned char crc = 0;
631 guint32 pos = 0;
632 DISSECTOR_ASSERT(tvb_reported_length(tvb) >= 1);
633 while ( len-- )
634 crc = crctable[crc^datax[pos++]];
635 return crc;
638 static void
639 dissect_mux_al_pdu( tvbuff_t *tvb, packet_info *pinfo, proto_tree *vc_tree,
640 /* circuit_t* vc_circuit, */
641 h223_lc_params* lc_params )
643 proto_tree *al_tree = NULL;
644 proto_item *al_item, *hidden_item;
645 proto_tree *al_subtree;
646 proto_item *al_subitem = NULL;
647 proto_item *tmp_item;
648 tvbuff_t *next_tvb = NULL;
649 dissector_handle_t subdissector = lc_params->subdissector;
650 guint32 len = tvb_reported_length(tvb);
652 guint8 calc_checksum;
653 guint8 real_checksum;
654 gboolean al2_sequenced = FALSE;
655 int data_start;
657 switch( lc_params->al_type ) {
658 case al1Framed:
659 case al1NotFramed:
660 al_item = proto_tree_add_none_format(vc_tree, hf_h223_al1, tvb, 0, -1, "H.223 AL1 (%sframed)",
661 (lc_params->al_type==al1Framed)?"":"not ");
662 al_tree = proto_item_add_subtree (al_item, ett_h223_al1);
663 if(lc_params->al_type == al1Framed) {
664 hidden_item = proto_tree_add_boolean(al_tree, hf_h223_al1_framed, tvb, 0, 1, TRUE );
665 PROTO_ITEM_SET_HIDDEN(hidden_item);
667 next_tvb = tvb;
668 al_subitem = proto_tree_add_item(al_tree, hf_h223_al_payload, next_tvb, 0, -1, ENC_NA);
669 break;
671 case al2WithSequenceNumbers:
672 al2_sequenced = TRUE;
673 /* fall-through */
674 case al2WithoutSequenceNumbers:
675 tmp_item = proto_tree_add_boolean(vc_tree, hf_h223_al2, tvb, 0, 0, TRUE );
677 al_item = proto_tree_add_item(vc_tree,
678 al2_sequenced?hf_h223_al2_sequenced:hf_h223_al2_unsequenced,
679 tvb, 0, -1, ENC_NA);
680 al_tree = proto_item_add_subtree (al_item, ett_h223_al2);
682 PROTO_ITEM_SET_GENERATED(tmp_item);
684 /* check minimum payload length */
685 if(len < (al2_sequenced?2U:1U))
686 THROW(BoundsError);
688 data_start = 0;
689 if( al2_sequenced ) {
690 proto_tree_add_item(al_tree, hf_h223_al2_seqno, tvb, 0, 1, ENC_LITTLE_ENDIAN);
691 data_start++;
694 next_tvb = tvb_new_subset( tvb, data_start, len-1-data_start, len-1-data_start );
695 al_subitem = proto_tree_add_item(al_tree, hf_h223_al_payload, next_tvb, 0, -1, ENC_NA);
697 calc_checksum = h223_al2_crc8bit(tvb);
698 real_checksum = tvb_get_guint8(tvb, len - 1);
700 if( calc_checksum == real_checksum ) {
701 proto_tree_add_uint_format_value(al_tree, hf_h223_al2_crc, tvb, len - 1, 1, real_checksum,
702 "0x%02x (correct)", real_checksum );
703 } else {
704 proto_tree_add_uint_format_value(al_tree, hf_h223_al2_crc, tvb, len - 1, 1, real_checksum,
705 "0x%02x (incorrect, should be 0x%02x)", real_checksum, calc_checksum );
706 tmp_item = proto_tree_add_boolean( al_tree, hf_h223_al2_crc_bad, tvb, len - 1, 1, TRUE );
707 PROTO_ITEM_SET_GENERATED(tmp_item);
709 /* don't pass pdus which fail checksums on to the subdissector */
710 subdissector = data_handle;
712 break;
713 default:
714 call_dissector(data_handle, tvb, pinfo, vc_tree);
715 return;
718 if (!subdissector)
719 subdissector = data_handle;
721 al_subtree = proto_item_add_subtree(al_subitem, ett_h223_al_payload);
722 call_dissector(subdissector, next_tvb, pinfo, al_subtree);
725 /************************************************************************************
727 * MUX-PDU dissection
731 /* dissect a fragment of a MUX-PDU which belongs to a particular VC
733 * tvb buffer containing the MUX-PDU fragment
734 * pinfo info on the packet containing the last fragment of the MUX-PDU
735 * pkt_offset offset within the block from the superdissector where the
736 * fragment starts (must increase monotonically for constant pinfo->fd->num)
737 * pdu_tree dissection tree for the PDU; a single item will be added (with
738 * its own subtree)
739 * vc VC for this SDU
740 * end_of_mux_sdu true if this is a segmentable VC and this is the last
741 * fragment in an SDU
743 static void
744 dissect_mux_sdu_fragment(tvbuff_t *volatile next_tvb, packet_info *pinfo,
745 guint32 pkt_offset, proto_tree *pdu_tree,
746 h223_call_info* call_info, guint16 vc,
747 gboolean end_of_mux_sdu)
749 /* update the circuit details before passing to a subdissector */
750 guint32 orig_circuit = pinfo->circuit_id;
751 guint32 orig_ctype = pinfo->ctype;
752 pinfo->circuit_id=circuit_chain_lookup(call_info, vc);
753 pinfo->ctype=CT_H223;
755 TRY {
756 circuit_t *subcircuit=find_circuit(pinfo->ctype,pinfo->circuit_id,pinfo->fd->num);
757 proto_tree *vc_tree = NULL;
758 proto_item *vc_item;
759 h223_vc_info *vc_info = NULL;
760 h223_lc_params *lc_params = NULL;
762 if(pdu_tree) {
763 vc_item = proto_tree_add_uint(pdu_tree, hf_h223_mux_vc, next_tvb, 0, tvb_reported_length(next_tvb), vc);
764 vc_tree = proto_item_add_subtree (vc_item, ett_h223_mux_vc);
767 if( subcircuit == NULL ) {
768 g_message( "Frame %d: Subcircuit id %d not found for call %p VC %d", pinfo->fd->num,
769 pinfo->circuit_id, (void *)call_info, vc );
770 } else {
771 vc_info = (h223_vc_info *)circuit_get_proto_data(subcircuit, proto_h223);
772 if( vc_info != NULL ) {
773 lc_params = find_h223_lc_params( vc_info, pinfo->p2p_dir, pinfo->fd->num );
778 if( lc_params != NULL ) {
779 if( lc_params->segmentable && lc_params->al_type != al1NotFramed ) {
780 stream_t *substream;
781 stream_pdu_fragment_t *frag;
783 substream = find_stream_circ(subcircuit,pinfo->p2p_dir);
784 if(substream == NULL )
785 substream = stream_new_circ(subcircuit,pinfo->p2p_dir);
786 frag = stream_find_frag(substream,pinfo->fd->num,pkt_offset);
788 if(frag == NULL ) {
789 #ifdef DEBUG_H223
790 g_debug("%d: New H.223 VC fragment: Parent circuit %d; subcircuit %d; offset %d; len %d, end %d",
791 pinfo->fd->num, orig_circuit, pinfo->circuit_id, pkt_offset, tvb_reported_length(next_tvb), end_of_mux_sdu);
792 #endif
793 frag = stream_add_frag(substream,pinfo->fd->num,pkt_offset,
794 next_tvb,pinfo,!end_of_mux_sdu);
795 } else {
796 #ifdef DEBUG_H223
797 g_debug("%d: Found H.223 VC fragment: Parent circuit %d; subcircuit %d; offset %d; len %d, end %d",
798 pinfo->fd->num, orig_circuit, pinfo->circuit_id, pkt_offset, tvb_reported_length(next_tvb), end_of_mux_sdu);
799 #endif
802 next_tvb = stream_process_reassembled(
803 next_tvb, 0, pinfo,
804 "Reassembled H.223 AL-PDU",
805 frag, &h223_al_frag_items,
806 NULL, vc_tree);
809 if(next_tvb) {
810 /* fudge to pass pkt_offset down to add_h223_mux_element,
811 * should it be called */
812 pdu_offset = pkt_offset;
813 dissect_mux_al_pdu(next_tvb, pinfo, vc_tree,/* subcircuit,*/ lc_params );
815 } else {
816 call_dissector(data_handle,next_tvb,pinfo,vc_tree);
820 /* restore the original circuit details for future PDUs */
821 FINALLY {
822 pinfo->ctype=(circuit_type)orig_ctype;
823 pinfo->circuit_id=orig_circuit;
825 ENDTRY;
828 static guint32
829 mux_element_sublist_size( h223_mux_element* me )
831 h223_mux_element *current_me = me->next;
832 guint32 length = 0;
833 while ( current_me ) {
834 if ( current_me->sublist )
835 length += current_me->repeat_count * mux_element_sublist_size( current_me->sublist );
836 else
837 length += current_me->repeat_count;
838 current_me = current_me->next;
840 if ( length == 0 ) { /* should never happen, but to avoid infinite loops... */
841 DISSECTOR_ASSERT_NOT_REACHED();
842 length = 1;
844 return length;
847 /* dissect part of a MUX-PDU payload according to a multiplex list
849 * tvb buffer containing entire mux-pdu payload
850 * pinfo info on the packet containing the last fragment of the MUX-PDU
851 * pkt_offset offset within the block from the superdissector where the
852 * MUX-PDU starts (must increase monotonically for constant
853 * pinfo->fd->num)
854 * pdu_tree dissection tree for the PDU
855 * call_info data structure for h223 call
856 * me top of mux list
857 * offset offset within tvb to start work
858 * endOfMuxSdu true if the end-of-sdu flag was set
860 static guint32
861 dissect_mux_payload_by_me_list( tvbuff_t *tvb, packet_info *pinfo,
862 guint32 pkt_offset, proto_tree *pdu_tree,
863 h223_call_info* call_info,
864 h223_mux_element *me, guint32 offset,
865 gboolean endOfMuxSdu )
867 guint32 len = tvb_reported_length(tvb);
868 guint32 frag_len;
869 guint32 sublist_len;
870 int i;
871 while ( me ) {
872 if ( me->sublist ) {
873 if ( me->repeat_count == 0 ) {
874 for(sublist_len = mux_element_sublist_size( me->sublist );
875 offset + sublist_len <= len;
876 offset = dissect_mux_payload_by_me_list( tvb, pinfo, pkt_offset, pdu_tree,
877 call_info, me->sublist, offset, endOfMuxSdu ) );
878 } else {
879 for(i = 0; i < me->repeat_count; ++i)
880 offset = dissect_mux_payload_by_me_list( tvb, pinfo, pkt_offset, pdu_tree,
881 call_info, me->sublist, offset, endOfMuxSdu );
883 } else {
884 if ( me->repeat_count == 0 )
885 frag_len = len - offset;
886 else
887 frag_len = me->repeat_count;
888 if(frag_len > 0) {
889 tvbuff_t *next_tvb;
890 next_tvb = tvb_new_subset(tvb, offset, frag_len, frag_len);
891 dissect_mux_sdu_fragment( next_tvb, pinfo, pkt_offset + offset, pdu_tree,
892 call_info, me->vc, (offset+frag_len==len) && endOfMuxSdu);
893 offset += frag_len;
896 me = me->next;
898 return offset;
901 /* dissect the payload of a MUX-PDU
903 * tvb buffer containing entire mux-pdu payload
904 * pinfo info on the packet containing the last fragment of the MUX-PDU
905 * pkt_offset offset within the block from the superdissector where the
906 * MUX-PDU starts (must increase monotonically for constant
907 * pinfo->fd->num)
908 * pdu_tree dissection tree for the PDU
909 * call_info data structure for h223 call
910 * mc multiplex code for this PDU
911 * endOfMuxSdu true if the end-of-sdu flag was set
913 static void
914 dissect_mux_payload( tvbuff_t *tvb, packet_info *pinfo, guint32 pkt_offset,
915 proto_tree *pdu_tree, h223_call_info *call_info,
916 guint8 mc, gboolean endOfMuxSdu )
918 guint32 len = tvb_reported_length(tvb);
920 h223_mux_element* me = find_h223_mux_element( &(call_info->direction_data[pinfo->p2p_dir ? 0 : 1]), mc, pinfo->fd->num, pkt_offset );
922 if( me ) {
923 dissect_mux_payload_by_me_list( tvb, pinfo, pkt_offset, pdu_tree, call_info, me, 0, endOfMuxSdu );
924 } else {
925 /* no entry found in mux-table. ignore packet and dissect as data */
926 proto_tree *vc_tree = NULL;
928 if(pdu_tree) {
929 proto_item *vc_item = proto_tree_add_item(pdu_tree, hf_h223_mux_deact, tvb, 0, len, ENC_NA);
930 vc_tree = proto_item_add_subtree(vc_item, ett_h223_mux_deact);
932 call_dissector(data_handle,tvb,pinfo,vc_tree);
936 /* dissect a reassembled mux-pdu
938 * tvb buffer containing mux-pdu, including header and closing flag
939 * pinfo packet info for packet containing the end of the mux-pdu
940 * pkt_offset offset within the block from the superdissector where the
941 * MUX-PDU starts (must increase monotonically for constant
942 * pinfo->fd->num)
943 * h223_tree dissection tree for h223 protocol; a single item will be added
944 * (with a sub-tree)
945 * call_info h223 info structure for this h223 call
946 * pdu_no index of this pdu within the call
948 static void
949 dissect_mux_pdu( tvbuff_t *tvb, packet_info *pinfo, guint32 pkt_offset,
950 proto_tree *h223_tree, h223_call_info *call_info)
952 guint32 offset = 0;
953 /* actual (as opposed to reported) payload len */
954 guint32 len;
955 guint32 raw_hdr = 0, correct_hdr = 0;
956 gint32 errors = 0;
957 guint16 closing_flag = 0;
958 guint8 mc = 0;
959 guint8 mpl = 0;
960 gboolean end_of_mux_sdu = FALSE;
961 tvbuff_t *pdu_tvb;
963 proto_item *pdu_item = NULL;
964 proto_tree *pdu_tree = NULL;
966 #ifdef DEBUG_H223_FRAGMENTATION
967 g_debug("%u: dissecting complete H.223 MUX-PDU, pkt_offset %u, len %u",
968 pinfo->fd->num, pkt_offset, tvb_reported_length(tvb));
969 #endif
971 switch(call_info->h223_level) {
972 case 0: case 1:
973 raw_hdr = tvb_get_guint8(tvb,0);
974 mc = (guint8)((raw_hdr>>1) & 0xf);
975 end_of_mux_sdu = raw_hdr & 1;
976 offset++;
977 /* closing flag is one byte long for h223 level 0, two for level 1 */
978 len = mpl = tvb_length_remaining(tvb, offset)-(call_info->h223_level+1);
980 /* XXX should ignore pdus with incorrect HECs */
981 break;
983 case 2:
984 raw_hdr = tvb_get_letoh24(tvb,0);
985 errors = golay_errors(raw_hdr);
986 offset += 3;
987 len = tvb_length_remaining(tvb,offset)-2;
989 if(errors != -1) {
990 correct_hdr = raw_hdr ^ (guint32)errors;
992 mc = (guint8)(correct_hdr & 0xf);
993 mpl = (guint8)((correct_hdr >> 4) & 0xff);
995 /* we should never have been called if there's not enough data in
996 * available. */
997 DISSECTOR_ASSERT(len >= mpl);
999 closing_flag = tvb_get_ntohs(tvb,offset+len);
1000 end_of_mux_sdu = (closing_flag==(0xE14D ^ 0xFFFF));
1001 } else {
1002 mc = 0;
1003 mpl = len;
1005 break;
1007 case 3:
1008 /* XXX not implemented */
1009 default:
1010 DISSECTOR_ASSERT_NOT_REACHED();
1014 if( h223_tree ) {
1015 if( mpl == 0 ) {
1016 pdu_item = proto_tree_add_item (h223_tree, hf_h223_mux_stuffing_pdu, tvb, 0, -1, ENC_NA);
1017 pdu_tree = proto_item_add_subtree (pdu_item, ett_h223_mux_stuffing_pdu);
1018 } else {
1019 pdu_item = proto_tree_add_item (h223_tree, hf_h223_mux_pdu, tvb, 0, -1, ENC_NA);
1020 pdu_tree = proto_item_add_subtree (pdu_item, ett_h223_mux_pdu);
1024 if( pdu_tree ) {
1025 proto_item *item = proto_tree_add_item (pdu_tree, hf_h223_mux_header, tvb, 0, offset, ENC_NA);
1026 proto_tree *hdr_tree = proto_item_add_subtree (item, ett_h223_mux_header);
1028 switch(call_info->h223_level) {
1029 case 0: case 1:
1030 proto_tree_add_uint(hdr_tree,hf_h223_mux_mc,tvb,0,1,mc);
1031 break;
1033 case 2:
1034 if( errors == -1 ) {
1035 proto_tree_add_uint_format_value(hdr_tree, hf_h223_mux_rawhdr, tvb,
1036 0, 3, raw_hdr,
1037 "0x%06x (uncorrectable errors)", raw_hdr );
1038 } else {
1039 if( errors == 0 ) {
1040 proto_tree_add_uint_format_value(hdr_tree, hf_h223_mux_rawhdr, tvb,
1041 0, 3, raw_hdr,
1042 "0x%06x (correct)", raw_hdr );
1043 } else {
1044 proto_tree_add_uint_format_value(hdr_tree, hf_h223_mux_rawhdr, tvb,
1045 0, 3, raw_hdr,
1046 "0x%06x (errors are 0x%06x)", raw_hdr, errors );
1048 item = proto_tree_add_uint(hdr_tree,hf_h223_mux_correctedhdr,tvb,0,3,
1049 correct_hdr);
1050 PROTO_ITEM_SET_GENERATED(item);
1051 proto_tree_add_uint(hdr_tree,hf_h223_mux_mc,tvb,0,1,mc);
1052 proto_tree_add_uint(hdr_tree,hf_h223_mux_mpl,tvb,0,2,mpl);
1054 break;
1056 case 3:
1057 /* XXX not implemented */
1058 default:
1059 DISSECTOR_ASSERT_NOT_REACHED();
1063 if(mpl > 0) {
1064 pdu_tvb = tvb_new_subset(tvb, offset, len, mpl);
1065 if(errors != -1) {
1066 dissect_mux_payload(pdu_tvb,pinfo,pkt_offset+offset,pdu_tree,call_info,mc,end_of_mux_sdu);
1067 } else {
1068 call_dissector(data_handle,pdu_tvb,pinfo,pdu_tree);
1070 offset += mpl;
1073 /* any extra data in the PDU, beyond that indictated by the mpl, is
1074 dissected as data. */
1075 len -= mpl;
1076 if( len > 0 ) {
1077 tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, len, len);
1078 proto_tree *vc_tree = NULL;
1080 if( pdu_tree ) {
1081 proto_item *vc_item = proto_tree_add_item(pdu_tree, hf_h223_mux_extra, next_tvb, 0, len, ENC_NA);
1082 vc_tree = proto_item_add_subtree(vc_item, ett_h223_mux_deact);
1084 call_dissector(data_handle,next_tvb,pinfo,vc_tree);
1086 offset += len;
1089 /* add the closing HDLC flag */
1090 if( pdu_tree )
1091 proto_tree_add_item(pdu_tree,hf_h223_mux_hdlc2,tvb,offset,2,ENC_BIG_ENDIAN);
1095 /************************************************************************************
1097 * MUX-PDU delineation and defragmentation
1100 /* attempt to parse the header of a mux pdu */
1101 static gboolean
1102 attempt_mux_level0_header_parse(guint32 nbytes _U_, guint32 hdr _U_, guint32 *minlen _U_)
1104 /* level 0 isn't byte-aligned, so is a complete pain to implement */
1105 DISSECTOR_ASSERT_NOT_REACHED();
1106 return FALSE;
1109 static gboolean
1110 attempt_mux_level1_header_parse(guint32 nbytes, guint32 hdr, guint32 *minlen)
1112 /* this is untested */
1113 DISSECTOR_ASSERT_NOT_REACHED();
1115 if(nbytes < 2)
1116 return FALSE;
1118 hdr &= 0xffff;
1119 /* don't interpret a repeated hdlc as a header */
1120 if(hdr == 0xE14D)
1121 return FALSE;
1123 /* + 1 byte of header and 2 bytes of closing HDLC */
1124 *minlen = (guint8)((hdr >> 12) & 0xff) + 3;
1125 return TRUE;
1128 static gboolean
1129 attempt_mux_level2_3_header_parse(guint32 nbytes, guint32 hdr, guint32 *minlen)
1131 gint32 errors;
1133 if(nbytes < 3)
1134 return FALSE;
1136 /* + 3 bytes of header and 2 bytes of closing HDLC */
1137 *minlen = 5;
1139 /* bah, we get the header in the wrong order */
1140 hdr =
1141 ((hdr & 0xFF0000) >> 16) |
1142 (hdr & 0x00FF00) |
1143 ((hdr & 0x0000FF) << 16);
1145 errors = golay_errors(hdr);
1146 if(errors != -1) {
1147 hdr ^= errors;
1148 *minlen += ((hdr >> 4) & 0xff);
1151 return TRUE;
1154 static gboolean (* const attempt_mux_header_parse[])(guint32 nbytes, guint32 header_buf, guint32 *minlen) = {
1155 attempt_mux_level0_header_parse,
1156 attempt_mux_level1_header_parse,
1157 attempt_mux_level2_3_header_parse,
1158 attempt_mux_level2_3_header_parse
1161 static gboolean
1162 h223_mux_check_hdlc(int h223_level, guint32 nbytes, guint32 tail_buf)
1164 guint32 masked;
1166 switch(h223_level) {
1167 case 0:
1168 /* level 0 isn't byte-aligned, so is a complete pain to implement */
1169 DISSECTOR_ASSERT_NOT_REACHED();
1170 return FALSE;
1172 case 1:
1173 masked = tail_buf & 0xffff;
1174 return nbytes >= 2 && masked == 0xE14D;
1176 case 2: case 3:
1177 masked = tail_buf & 0xffff;
1178 return nbytes >= 2 && (masked == 0xE14D || masked == (0xE14D ^ 0xFFFF));
1180 default:
1181 DISSECTOR_ASSERT_NOT_REACHED();
1182 return FALSE;
1186 /* read a pdu (or the start of a pdu) from the tvb, and dissect it
1188 * returns the number of bytes processed, or the negative of the number of
1189 * extra bytes needed, or zero if we don't know yet
1192 static gint
1193 dissect_mux_pdu_fragment( tvbuff_t *tvb, guint32 start_offset,
1194 packet_info *pinfo, proto_tree *h223_tree,
1195 h223_call_info *call_info)
1197 tvbuff_t *volatile next_tvb;
1198 volatile guint32 offset = start_offset;
1199 gboolean more_frags = TRUE;
1201 gboolean header_parsed = FALSE;
1202 guint32 header_buf = 0, tail_buf = 0;
1203 guint32 pdu_minlen = 0;
1204 void *pd_save;
1207 #ifdef DEBUG_H223_FRAGMENTATION
1208 g_debug("%d: dissecting H.223 PDU, start_offset %u, %u bytes left",
1209 pinfo->fd->num,start_offset, tvb_reported_length_remaining( tvb, start_offset ));
1210 #endif
1212 while( more_frags && offset < tvb_reported_length( tvb )) {
1213 guint8 byte = tvb_get_guint8(tvb, offset++);
1215 /* read a byte into the header buf, if necessary */
1216 if((offset-start_offset) <= 4) {
1217 header_buf <<= 8;
1218 header_buf |= byte;
1221 /* read the byte into the tail buf */
1222 tail_buf <<= 8;
1223 tail_buf |= byte;
1225 /* if we haven't parsed the header yet, attempt to do so now */
1226 if(!header_parsed)
1227 /* this sets current_pdu_header parsed if current_pdu_read == 3 */
1228 header_parsed = (attempt_mux_header_parse[call_info->h223_level])
1229 (offset-start_offset,header_buf,&pdu_minlen);
1231 /* if we have successfully parsed the header, we have sufficient data,
1232 * and we have found the closing hdlc, we are done here */
1233 if(header_parsed && (offset-start_offset) >= pdu_minlen) {
1234 if(h223_mux_check_hdlc(call_info->h223_level,offset-start_offset,tail_buf)) {
1235 more_frags = FALSE;
1240 if( more_frags ) {
1241 if(pdu_minlen <= (offset-start_offset)) {
1242 /* we haven't found the closing hdlc yet, but we don't know how
1243 * much more we need */
1244 #ifdef DEBUG_H223_FRAGMENTATION
1245 g_debug("\tBailing, requesting more bytes");
1246 #endif
1247 return 0;
1248 } else {
1249 guint32 needed = pdu_minlen-(offset-start_offset);
1250 #ifdef DEBUG_H223_FRAGMENTATION
1251 g_debug("\tBailing, requesting %i-%i=%u more bytes", pdu_minlen,(offset-start_offset),needed);
1252 #endif
1253 return - (gint) needed;
1257 /* create a tvb for the fragment */
1258 next_tvb = tvb_new_subset(tvb, start_offset, offset-start_offset,
1259 offset-start_offset);
1262 * Dissect the PDU.
1264 * If it gets an error that means there's no point in dissecting
1265 * any more PDUs, rethrow the exception in question.
1267 * If it gets any other error, report it and continue, as that
1268 * means that PDU got an error, but that doesn't mean we should
1269 * stop dissecting PDUs within this frame or chunk of reassembled
1270 * data.
1272 pd_save = pinfo->private_data;
1273 TRY {
1274 dissect_mux_pdu( next_tvb, pinfo, start_offset, h223_tree, call_info);
1276 CATCH_NONFATAL_ERRORS {
1277 /* Restore the private_data structure in case one of the
1278 * called dissectors modified it (and, due to the exception,
1279 * was unable to restore it).
1281 pinfo->private_data = pd_save;
1282 show_exception(tvb, pinfo, h223_tree, EXCEPT_CODE, GET_MESSAGE);
1285 ENDTRY;
1287 return (offset-start_offset);
1290 /************************************************************************************
1292 * main dissector entry points
1295 /* dissects PDUs from the tvb
1297 * Updates desegment_offset and desegment_len if the end of the data didn't
1298 * line up with the end of a pdu.
1300 static void
1301 dissect_h223 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1303 proto_tree *h223_tree = NULL;
1304 proto_item *h223_item = NULL;
1305 h223_call_info *call_info = NULL;
1306 guint32 offset = 0;
1308 /* set up the protocol and info fields in the summary pane */
1309 col_set_str (pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_H223);
1311 col_clear(pinfo->cinfo, COL_INFO);
1313 /* find or create the call_info for this call */
1314 call_info = find_or_create_call_info(pinfo);
1316 /* add the 'h223' tree to the main tree */
1317 if (tree) {
1318 h223_item = proto_tree_add_item (tree, proto_h223, tvb, 0, -1, ENC_NA);
1319 h223_tree = proto_item_add_subtree (h223_item, ett_h223);
1322 while( offset < tvb_reported_length( tvb )) {
1323 int res = dissect_mux_pdu_fragment( tvb, offset, pinfo,
1324 h223_tree, call_info);
1325 if(res <= 0) {
1326 /* the end of the tvb held the start of a PDU */
1327 pinfo->desegment_offset = offset;
1329 /* if res != 0, we actually know how much more data we need for a
1330 * PDU.
1332 * However, if we return that, it means that we get called twice
1333 * for the next packet; this makes it hard to tell how far throught
1334 * the stream we are and we have to start messing about with
1335 * getting the seqno from the superdissector's private data. So we
1336 * don't do that.
1338 * pinfo->desegment_len = (res == 0 ? DESEGMENT_ONE_MORE_SEGMENT : -res);
1340 pinfo -> desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
1342 if(h223_item) {
1343 /* shrink the h223 protocol item such that it only includes the
1344 * bits we dissected */
1345 proto_item_set_len(h223_item,offset);
1348 if(offset == 0) {
1349 col_set_str(pinfo->cinfo, COL_INFO, "(No complete PDUs)");
1351 return;
1353 offset += res;
1357 /* H.223 specifies that the least-significant bit is transmitted first;
1358 * however this is at odds with IAX which transmits bytes with the
1359 * first-received bit as the MSB.
1361 * This dissector swaps the ordering of the bits in each byte before using the
1362 * normal entry point.
1364 static void
1365 dissect_h223_bitswapped (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1367 tvbuff_t *reversed_tvb;
1368 guint8 *datax;
1369 guint len;
1370 guint i;
1372 len = tvb_length(tvb);
1373 datax = (guint8 *)wmem_alloc(pinfo->pool, len);
1374 for( i=0; i<len; i++)
1375 datax[i]=BIT_SWAP(tvb_get_guint8(tvb,i));
1378 * Add the reversed tvbuff to the list of tvbuffs to which
1379 * the tvbuff we were handed refers, so it'll get
1380 * cleaned up when that tvbuff is cleaned up.
1382 reversed_tvb = tvb_new_child_real_data(tvb, datax,len,tvb_reported_length(tvb));
1384 /* Add the reversed data to the data source list. */
1385 add_new_data_source(pinfo, reversed_tvb, "Bit-swapped H.223 frame" );
1387 dissect_h223(reversed_tvb,pinfo,tree);
1390 /******************************************************************************/
1392 static void
1393 h223_init_protocol (void)
1395 circuit_chain_init();
1399 void proto_register_h223 (void)
1401 /* A header field is something you can search/filter on.
1403 * We create a structure to register our fields. It consists of an
1404 * array of hf_register_info structures, each of which are of the format
1405 * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
1408 static hf_register_info hf[] = {
1409 #if 0
1410 { &hf_h223_non_h223_data,
1411 { "Non-H.223 data", "h223.non-h223", FT_NONE, BASE_NONE, NULL, 0x0,
1412 "Initial data in stream, not a PDU", HFILL }},
1413 #endif
1415 { &hf_h223_mux_stuffing_pdu,
1416 { "H.223 stuffing PDU", "h223.mux.stuffing", FT_NONE, BASE_NONE, NULL, 0x0,
1417 "Empty PDU used for stuffing when no data available", HFILL }},
1419 { &hf_h223_mux_pdu,
1420 { "H.223 MUX-PDU", "h223.mux", FT_NONE, BASE_NONE, NULL, 0x0,
1421 NULL, HFILL }},
1423 { &hf_h223_mux_header,
1424 { "Header", "h223.mux.header", FT_NONE, BASE_NONE, NULL, 0x0,
1425 "H.223 MUX header", HFILL }},
1427 { &hf_h223_mux_rawhdr,
1428 { "Raw value", "h223.mux.rawhdr", FT_UINT24, BASE_HEX, NULL, 0x0,
1429 "Raw header bytes", HFILL }},
1431 { &hf_h223_mux_correctedhdr,
1432 { "Corrected value", "h223.mux.correctedhdr", FT_UINT24, BASE_HEX, NULL, 0x0,
1433 "Corrected header bytes", HFILL }},
1435 { &hf_h223_mux_mc,
1436 { "Multiplex Code", "h223.mux.mc", FT_UINT8, BASE_DEC, NULL, 0x0,
1437 "H.223 MUX multiplex code", HFILL }},
1439 { &hf_h223_mux_mpl,
1440 { "Multiplex Payload Length", "h223.mux.mpl", FT_UINT8, BASE_DEC, NULL, 0x0,
1441 "H.223 MUX multiplex Payload Length", HFILL }},
1443 { &hf_h223_mux_deact,
1444 { "Deactivated multiplex table entry", "h223.mux.deactivated", FT_NONE, BASE_NONE, NULL, 0x0,
1445 "mpl refers to an entry in the multiplex table which is not active", HFILL }},
1447 { &hf_h223_mux_vc,
1448 { "H.223 virtual circuit", "h223.mux.vc", FT_UINT16, BASE_DEC, NULL, 0x0,
1449 NULL, HFILL }},
1451 { &hf_h223_mux_extra,
1452 { "Extraneous data", "h223.mux.extra", FT_NONE, BASE_NONE, NULL, 0x0,
1453 "data beyond mpl", HFILL }},
1455 { &hf_h223_mux_hdlc2,
1456 { "HDLC flag", "h223.mux.hdlc", FT_UINT16, BASE_HEX, NULL, 0x0,
1457 "framing flag", HFILL }},
1459 /* fields for h.223-mux fragments */
1460 { &hf_h223_mux_fragment_overlap,
1461 { "Fragment overlap", "h223.mux.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1462 "Fragment overlaps with other fragments", HFILL }},
1464 { &hf_h223_mux_fragment_overlap_conflict,
1465 { "Conflicting data in fragment overlap", "h223.mux.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1466 "Overlapping fragments contained conflicting data", HFILL }},
1468 { &hf_h223_mux_fragment_multiple_tails,
1469 { "Multiple tail fragments found", "h223.mux.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1470 "Several tails were found when defragmenting the packet", HFILL }},
1472 { &hf_h223_mux_fragment_too_long_fragment,
1473 { "Fragment too long", "h223.mux.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1474 "Fragment contained data past end of packet", HFILL }},
1476 { &hf_h223_mux_fragment_error,
1477 { "Defragmentation error", "h223.mux.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1478 "Defragmentation error due to illegal fragments", HFILL }},
1480 { &hf_h223_mux_fragment_count,
1481 { "Fragment count", "h223.mux.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0,
1482 NULL, HFILL }},
1484 { &hf_h223_mux_fragment,
1485 { "H.223 MUX-PDU Fragment", "h223.mux.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1486 NULL, HFILL }},
1488 { &hf_h223_mux_fragments,
1489 { "H.223 MUX-PDU Fragments", "h223.mux.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
1490 NULL, HFILL }},
1492 { &hf_h223_mux_reassembled_in,
1493 { "MUX-PDU fragment, reassembled in frame", "h223.mux.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1494 "This H.223 MUX-PDU packet is reassembled in this frame", HFILL }},
1496 { &hf_h223_mux_reassembled_length,
1497 { "Reassembled H.223 MUX-PDU length", "h223.mux.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
1498 "The total length of the reassembled payload", HFILL }},
1500 /* fields for h.223-al fragments */
1501 { &hf_h223_al_fragment_overlap,
1502 { "Fragment overlap", "h223.al.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1503 "Fragment overlaps with other fragments", HFILL }},
1505 { &hf_h223_al_fragment_overlap_conflict,
1506 { "Conflicting data in fragment overlap", "h223.al.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1507 "Overlapping fragments contained conflicting data", HFILL }},
1509 { &hf_h223_al_fragment_multiple_tails,
1510 { "Multiple tail fragments found", "h223.al.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1511 "Several tails were found when defragmenting the packet", HFILL }},
1513 { &hf_h223_al_fragment_too_long_fragment,
1514 { "Fragment too long", "h223.al.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1515 "Fragment contained data past end of packet", HFILL }},
1517 { &hf_h223_al_fragment_error,
1518 { "Defragmentation error", "h223.al.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1519 "Defragmentation error due to illegal fragments", HFILL }},
1521 { &hf_h223_al_fragment_count,
1522 { "Fragment count", "h223.al.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0,
1523 NULL, HFILL }},
1525 { &hf_h223_al_fragment,
1526 { "H.223 AL-PDU Fragment", "h223.al.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1527 NULL, HFILL }},
1529 { &hf_h223_al_fragments,
1530 { "H.223 AL-PDU Fragments", "h223.al.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
1531 NULL, HFILL }},
1533 { &hf_h223_al_reassembled_in,
1534 { "AL-PDU fragment, reassembled in frame", "h223.al.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1535 "This H.223 AL-PDU packet is reassembled in this frame", HFILL }},
1537 { &hf_h223_al_reassembled_length,
1538 { "Reassembled H.223 AL-PDU length", "h223.al.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
1539 "The total length of the reassembled payload", HFILL }},
1541 /* h223-als */
1543 { &hf_h223_al1,
1544 { "H.223 AL1", "h223.al1", FT_NONE, BASE_NONE, NULL, 0x0,
1545 "H.223 AL-PDU using AL1", HFILL }},
1547 { &hf_h223_al1_framed,
1548 { "H.223 AL1 framing", "h223.al1.framed", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1549 NULL, HFILL }},
1551 { &hf_h223_al2,
1552 { "H.223 AL2", "h223.al2", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1553 "H.223 AL-PDU using AL2", HFILL }},
1555 { &hf_h223_al2_sequenced,
1556 { "H.223 sequenced AL2", "h223.sequenced_al2", FT_NONE, BASE_NONE, NULL, 0x0,
1557 "H.223 AL-PDU using AL2 with sequence numbers", HFILL }},
1559 { &hf_h223_al2_unsequenced,
1560 { "H.223 unsequenced AL2", "h223.unsequenced_al2", FT_NONE, BASE_NONE, NULL, 0x0,
1561 "H.223 AL-PDU using AL2 without sequence numbers", HFILL }},
1563 { &hf_h223_al2_seqno,
1564 { "Sequence Number", "h223.al2.seqno", FT_UINT8, BASE_DEC, NULL, 0x0,
1565 "H.223 AL2 sequence number", HFILL }},
1567 { &hf_h223_al2_crc,
1568 { "CRC", "h223.al2.crc", FT_UINT8, BASE_HEX, NULL, 0x0,
1569 NULL, HFILL }},
1571 { &hf_h223_al2_crc_bad,
1572 { "Bad CRC","h223.al2.crc_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1573 NULL, HFILL }},
1575 { &hf_h223_al_payload,
1576 { "H.223 AL Payload", "h223.al.payload", FT_NONE, BASE_NONE, NULL, 0x0,
1577 "H.223 AL-PDU Payload", HFILL }},
1581 static gint *ett[] = {
1582 &ett_h223,
1583 &ett_h223_non_h223_data,
1584 &ett_h223_mux_stuffing_pdu,
1585 &ett_h223_mux_pdu,
1586 &ett_h223_mux_header,
1587 &ett_h223_mux_deact,
1588 &ett_h223_mux_vc,
1589 &ett_h223_mux_extra,
1590 &ett_h223_mux_fragments,
1591 &ett_h223_mux_fragment,
1592 &ett_h223_al_fragments,
1593 &ett_h223_al_fragment,
1594 &ett_h223_al1,
1595 &ett_h223_al2,
1596 &ett_h223_al_payload
1599 proto_h223 =
1600 proto_register_protocol ("ITU-T Recommendation H.223", "H.223", "h223");
1602 proto_register_field_array (proto_h223, hf, array_length (hf));
1603 proto_register_subtree_array (ett, array_length (ett));
1604 register_dissector("h223", dissect_h223, proto_h223);
1605 register_dissector("h223_bitswapped", dissect_h223_bitswapped, proto_h223);
1607 /* register our init routine to be called at the start of a capture,
1608 to clear out our hash tables etc */
1609 register_init_routine(&h223_init_protocol);
1611 h245_set_h223_set_mc_handle( &h223_set_mc );
1612 h245_set_h223_add_lc_handle( &h223_add_lc );
1615 void proto_reg_handoff_h223(void)
1617 dissector_handle_t h223_bitswapped = find_dissector("h223_bitswapped");
1618 dissector_handle_t h223 = find_dissector("h223");
1619 data_handle = find_dissector("data");
1620 srp_handle = find_dissector("srp");
1622 dissector_add_handle("tcp.port", h223);
1623 dissector_add_handle("tcp.port", h223_bitswapped);
1624 dissector_add_string("rtp_dyn_payload_type","CLEARMODE", h223_bitswapped);
1625 dissector_add_uint("iax2.dataformat", AST_DATAFORMAT_H223_H245, h223_bitswapped);
1629 * Editor modelines
1631 * Local Variables:
1632 * c-basic-offset: 4
1633 * tab-width: 8
1634 * indent-tabs-mode: nil
1635 * End:
1637 * ex: set shiftwidth=4 tabstop=8 expandtab:
1638 * :indentSize=4:tabSize=8:noTabs=true: