Wireshark-dev: [Wireshark-dev] H.223 over rtp
From: Richard van der Hoff <richardv@xxxxxxxxxxxxx>
Date: Tue, 20 Feb 2007 12:29:45 +0000
This patch registers H.223 as a dissector for RTP CLEARMODE payloads - and makes some other modifications to the H.223 dissector to make this work correctly.

It assumes that both my earlier patches to the H.223 dissector ('H.223 dissector - separate "bitswapping" into separate dissector' and 'h.223 robustness fixes') have been applied; it also depends on my 'defragmentation over RTP' patch (submitted on 16/2/2007) for correct operation.

I've added some sample captures to the wiki.
Index: plugins/h223/packet-h223.c
===================================================================
--- plugins/h223/packet-h223.c	(revision 11941)
+++ plugins/h223/packet-h223.c	(working copy)
@@ -388,103 +388,168 @@
     return vc_info;
 }
 
-static void init_logical_channel( packet_info* pinfo, h223_call_info* call_info, int vc, int direction, h223_lc_params* params )
+static void init_logical_channel( guint32 start_frame, h223_call_info* call_info, int vc, int direction, h223_lc_params* params )
 {
     guint32 circuit_id = circuit_chain_lookup(call_info, vc);
     circuit_t *subcircuit;
     h223_vc_info *vc_info;
-    subcircuit = find_circuit( CT_H223, circuit_id, pinfo->fd->num );
+    subcircuit = find_circuit( CT_H223, circuit_id, start_frame );
 
     if( subcircuit == NULL ) {
-        subcircuit = circuit_new( CT_H223, circuit_id, pinfo->fd->num );
+        subcircuit = circuit_new( CT_H223, circuit_id, start_frame );
 #ifdef DEBUG_H223
-        g_debug("%d: Created new circuit %d for call %p VC %d", pinfo->fd->num, circuit_id, call_info, vc);
+        g_debug("%d: Created new circuit %d for call %p VC %d", start_frame, circuit_id, call_info, vc);
 #endif
         vc_info = h223_vc_info_new( call_info );
         circuit_add_proto_data( subcircuit, proto_h223, vc_info );
     } else {
         vc_info = circuit_get_proto_data( subcircuit, proto_h223 );
     }
-    add_h223_lc_params( vc_info, direction, params, pinfo->fd->num );
+    add_h223_lc_params( vc_info, direction, params, start_frame );
 }
 
-static void init_control_channels( packet_info* pinfo, h223_call_info* call_info )
+/* create a brand-new h223_call_info structure */
+static h223_call_info *create_call_info( guint32 start_frame )
 {
-    h223_lc_params *vc0_params = se_alloc(sizeof(h223_lc_params));
+    h223_call_info *data;
+    h223_lc_params *vc0_params;
+
+    data = se_alloc(sizeof(h223_call_info));
+
+    /* initialise the call info */
+    init_direction_data(&data -> direction_data[0]);
+    init_direction_data(&data -> direction_data[1]);
+        
+    /* FIXME shouldn't this be figured out dynamically? */
+    data -> h223_level = 2;
+
+    vc0_params = se_alloc(sizeof(h223_lc_params));
     vc0_params->al_type = al1Framed;
     vc0_params->al_params = NULL;
     vc0_params->segmentable = TRUE;
     vc0_params->subdissector = srp_handle;
-    init_logical_channel( pinfo, call_info, 0, P2P_DIR_SENT, vc0_params );
-    init_logical_channel( pinfo, call_info, 0, P2P_DIR_RECV, vc0_params );
+    init_logical_channel( start_frame, data, 0, P2P_DIR_SENT, vc0_params );
+    init_logical_channel( start_frame, data, 0, P2P_DIR_RECV, vc0_params );
+    return data;
 }
 
-static h223_call_info *find_or_create_call_info ( packet_info * pinfo )
+/* find or create call_info struct for calls over circuits (eg, IAX) */
+static h223_call_info *find_or_create_call_info_circ(packet_info * pinfo)
 {
-    circuit_t *circ;
-    conversation_t *conv = NULL;
     h223_call_info *data;
+    circuit_t *circ = NULL;
 
-    /* look for a circuit (eg, IAX call) first */
-    circ = find_circuit( pinfo->ctype, pinfo->circuit_id, pinfo->fd->num );
-    if( circ == NULL ) {
-	/* assume we're running atop TCP; use the converstion support */
-	conv = find_conversation( pinfo->fd->num,
-                                  &pinfo->src,&pinfo->dst,
-				  pinfo->ptype,
-				  pinfo->srcport,pinfo->destport, 0 );
-	if( conv == NULL ) {
-	    conv = conversation_new( pinfo->fd->num,
-                                     &pinfo->src,&pinfo->dst,
-				     pinfo->ptype,
-				     pinfo->srcport,pinfo->destport, 0 );
-	}
-	
+    if(pinfo->ctype != CT_NONE)
+        circ = find_circuit( pinfo->ctype, pinfo->circuit_id, pinfo->fd->num );
+    if(circ == NULL)
+        return NULL;
+
+    data = (h223_call_info *)circuit_get_proto_data(circ, proto_h223);
+    
+    if( data == NULL ) {
+        data = create_call_info(pinfo->fd->num);
+
+#ifdef DEBUG_H223
+        g_debug("%u: Created new call %p for circuit %p ctype %d, id %u",
+                pinfo->fd->num, data, circ, pinfo->ctype, pinfo->circuit_id);
+#endif
+        circuit_add_proto_data(circ, proto_h223, data);
     }
+    
+    /* work out what direction we're really going in */
+    if( pinfo->p2p_dir < 0 || pinfo->p2p_dir > 1)
+        pinfo->p2p_dir = P2P_DIR_SENT;
+    
+    return data;
+}
 
-    if( circ )
-	data = (h223_call_info *)circuit_get_proto_data(circ, proto_h223);
-    else
-	data = (h223_call_info *)conversation_get_proto_data(conv, proto_h223);
+/* find or create call_info struct for calls over conversations (eg, RTP) */
+static h223_call_info *find_or_create_call_info_conv(packet_info * pinfo)
+{
+    h223_call_info *data;
+    conversation_t *conv;
 
-    if( data == NULL ) {
-	data = se_alloc(sizeof(h223_call_info));
+    /* assume we're running atop TCP or RTP; use the conversation support */
+    conv = find_conversation( pinfo->fd->num,
+                              &pinfo->src,&pinfo->dst,
+                              pinfo->ptype,
+                              pinfo->srcport,pinfo->destport, 0 );
 
-	if( circ ) {
-	    circuit_add_proto_data(circ, proto_h223, data);
-	} else {
-	    conversation_add_proto_data(conv, proto_h223, data);
-	    /* add the source details so we can distinguish directions
-	     * in future */
-	    COPY_ADDRESS(&(data -> srcaddress), &(pinfo->src));
-	    data -> srcport = pinfo->srcport;
-	}
+    /* both RTP and TCP track their conversations, so just assert here if
+     * we can't find one */
+    DISSECTOR_ASSERT(conv);
 
-	/* initialise the call info */
-        init_direction_data(&data -> direction_data[0]);
-        init_direction_data(&data -> direction_data[1]);
+    data = (h223_call_info *)conversation_get_proto_data(conv, proto_h223);
+
+    if(data == NULL && pinfo->ptype == PT_UDP ) {
+        conversation_t *conv2;
         
-	/* FIXME shouldn't this be figured out dynamically? */
-	data -> h223_level = 2;
+        /* RTP tracks the two sides of the conversation totally separately;
+         * this messes us up totally.
+         *
+         * Look for another converstation, going in the opposite direction.
+         */
+        conv2 = find_conversation( pinfo->fd->num,
+                                  &pinfo->dst,&pinfo->src,
+                                  pinfo->ptype,
+                                  pinfo->destport,pinfo->srcport, 0 );
+        if(conv2 != NULL)
+            data = (h223_call_info *)conversation_get_proto_data(conv2, proto_h223);
 
-        init_control_channels( pinfo, data );
+        if(data != NULL) {
+#ifdef DEBUG_H223
+            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",
+                    pinfo->fd->num, conv, conv2, data, pinfo->ptype,
+                    pinfo->dst.data[0], pinfo->dst.data[1], pinfo->dst.data[2], pinfo->dst.data[3],
+                    pinfo->destport,
+                    pinfo->src.data[0], pinfo->src.data[1], pinfo->src.data[2], pinfo->src.data[3],
+                    pinfo->srcport);
+#endif
+            conversation_add_proto_data(conv, proto_h223, data);
+        }
     }
 
-    /* work out what direction we're really going in */
-    if( circ ) {
-        if( pinfo->p2p_dir < 0 || pinfo->p2p_dir > 1)
-            pinfo->p2p_dir = P2P_DIR_SENT;
-    } else {
-	if( ADDRESSES_EQUAL( &(pinfo->src), &(data->srcaddress))
-	    && pinfo->srcport == data->srcport )
-	    pinfo->p2p_dir = P2P_DIR_SENT;
-	else
-	    pinfo->p2p_dir = P2P_DIR_RECV;
+    /* we still haven't found any call data - create a new one for this
+     * conversation */
+    if(data == NULL) {
+        data = create_call_info(pinfo->fd->num);
+
+#ifdef DEBUG_H223
+        g_debug("%u: Created new call %p for conv %p type=%u src=%u.%u.%u.%u:%u dst=%u.%u.%u.%u:%u",
+                pinfo->fd->num, data, conv, pinfo->ptype,
+                pinfo->src.data[0], pinfo->src.data[1], pinfo->src.data[2], pinfo->src.data[3],
+                pinfo->srcport,
+                pinfo->dst.data[0], pinfo->dst.data[1], pinfo->dst.data[2], pinfo->dst.data[3],
+                pinfo->destport);
+#endif
+            
+        conversation_add_proto_data(conv, proto_h223, data);
+        /* add the source details so we can distinguish directions
+         * in future */
+        COPY_ADDRESS(&(data -> srcaddress), &(pinfo->src));
+        data -> srcport = pinfo->srcport;
     }
 
+    /* work out what direction we're really going in */
+    if( ADDRESSES_EQUAL( &(pinfo->src), &(data->srcaddress))
+        && pinfo->srcport == data->srcport )
+        pinfo->p2p_dir = P2P_DIR_SENT;
+    else 
+        pinfo->p2p_dir = P2P_DIR_RECV;
+
     return data;
 }
 
+static h223_call_info *find_or_create_call_info ( packet_info * pinfo )
+{
+    h223_call_info *data;
+
+    data = find_or_create_call_info_circ(pinfo);
+    if(data == NULL)
+        data = find_or_create_call_info_conv(pinfo);
+    return data;
+}
+
 /* called from the h245 dissector to handle a MultiplexEntrySend message */
 static void h223_set_mc( packet_info* pinfo, guint8 mc, h223_mux_element* me )
 {
@@ -509,7 +574,7 @@
      * the new channel */
     if(circ) {
         vc_info = circuit_get_proto_data(circ, proto_h223);
-        init_logical_channel( pinfo, vc_info->call_info, lc, pinfo->p2p_dir, params );
+        init_logical_channel( pinfo->fd->num, vc_info->call_info, lc, pinfo->p2p_dir, params );
     }
 }
 
@@ -1512,6 +1577,7 @@
 
     dissector_add_handle("tcp.port", h223);
     dissector_add_handle("tcp.port", h223_bitswapped);
+    dissector_add_string("rtp_dyn_payload_type","CLEARMODE", h223_bitswapped);
     dissector_add("iax2.dataformat", AST_DATAFORMAT_H223_H245, h223_bitswapped);
 }
 /* vim:set ts=8 et: */