cleaning up bits and pieces
[obnox/wireshark/wip.git] / epan / dissectors / packet-fc.c
index b4b3bceba6d0a12029445ce7f31311e2771914c0..77e92c284e07f5387f061de94911937700d839e6 100644 (file)
@@ -134,6 +134,11 @@ static dissector_handle_t data_handle;
 
 static int fc_tap = -1;
 
+typedef struct _fc_conv_data_t {
+    se_tree_t *exchanges;
+} fc_conv_data_t;
+
+
 /* Reassembly stuff */
 static gboolean fc_reassemble = TRUE;
 static guint32  fc_max_frame_size = 1024;
@@ -149,9 +154,6 @@ typedef struct _fcseq_conv_data {
 
 GHashTable *fcseq_req_hash = NULL;
 
-static GHashTable *fc_exchange_unmatched = NULL;
-static GHashTable *fc_exchange_matched = NULL;
-
 /*
  * Hash Functions
  */
@@ -175,87 +177,9 @@ fcseq_hash (gconstpointer v)
     return val;
 }
 
-static guint
-fc_exchange_hash_unmatched(gconstpointer v)
-{
-    const fc_exchange_data *fced=(const fc_exchange_data *)v;
-
-    return fced->oxid;
-}
-static gint
-fc_exchange_equal_unmatched(gconstpointer v1, gconstpointer v2)
-{
-    const fc_exchange_data *fced1=(const fc_exchange_data *)v1;
-    const fc_exchange_data *fced2=(const fc_exchange_data *)v2;
-
-    /* oxid must match */
-    if(fced1->oxid!=fced2->oxid){
-        return 0;
-    }
-    /* compare s_id, d_id and treat the fc address
-       s_id==00.00.00 as a wildcard matching anything */
-    if( ((fced1->s_id.data[0]!=0)||(fced1->s_id.data[1]!=0)||(fced1->s_id.data[2]!=0)) && CMP_ADDRESS(&fced1->s_id, &fced2->s_id) ){
-        return 0;
-    }
-    if(CMP_ADDRESS(&fced1->d_id, &fced2->d_id)){
-        return 0;
-    }
-
-    return 1;
-}
-
-static guint
-fc_exchange_hash_matched(gconstpointer v)
-{
-    const fc_exchange_data *fced=(const fc_exchange_data *)v;
-
-    return fced->oxid;
-}
-static gint
-fc_exchange_equal_matched(gconstpointer v1, gconstpointer v2)
-{
-    const fc_exchange_data *fced1=(const fc_exchange_data *)v1;
-    const fc_exchange_data *fced2=(const fc_exchange_data *)v2;
-    guint32 fef1, fef2, lef1, lef2;
-
-    /* oxid must match */
-    if(fced1->oxid!=fced2->oxid){
-        return 0;
-    }
-    fef1=fced1->first_exchange_frame;
-    fef2=fced2->first_exchange_frame;
-    lef1=fced1->last_exchange_frame;
-    lef2=fced2->last_exchange_frame;
-    if(!fef1)fef1=fef2;
-    if(!fef2)fef2=fef1;
-    if(!lef1)lef1=lef2;
-    if(!lef2)lef2=lef1;
-
-    if(fef1!=fef2){
-        return 0;
-    }
-    if(lef1!=lef2){
-        return 0;
-    }
-
-    return 1;
-}
-
 static void
 fc_exchange_init_protocol(void)
 {
-    if(fc_exchange_unmatched){
-        g_hash_table_destroy(fc_exchange_unmatched);
-        fc_exchange_unmatched=NULL;
-    }
-    if(fc_exchange_matched){
-        g_hash_table_destroy(fc_exchange_matched);
-        fc_exchange_matched=NULL;
-    }
-
-    fc_exchange_unmatched=g_hash_table_new(fc_exchange_hash_unmatched, fc_exchange_equal_unmatched);
-    fc_exchange_matched=g_hash_table_new(fc_exchange_hash_matched, fc_exchange_equal_matched);
-
     fragment_table_init(&fc_fragment_table);
 
     if (fcseq_req_hash)
@@ -522,20 +446,22 @@ static const true_false_string tfs_fc_fctl_rel_offset = {
 
 /* code to dissect the  F_CTL bitmask */
 static void
-dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, guint32 fctl)
+dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset)
 {
-       proto_item *item;
-       proto_tree *tree;
+       proto_item *item=NULL;
+       proto_tree *tree=NULL;
        guint32 flags;
 
-        item=proto_tree_add_uint(parent_tree, hf_fc_fctl, tvb, offset, 3, fctl);
-       tree=proto_item_add_subtree(item, ett_fctl);
-
        flags = tvb_get_guint8 (tvb, offset);
        flags = (flags<<8) | tvb_get_guint8 (tvb, offset+1);
        flags = (flags<<8) | tvb_get_guint8 (tvb, offset+2);
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_exchange_responder, tvb, offset, 3, fctl);
+       if(parent_tree){
+               item=proto_tree_add_uint(parent_tree, hf_fc_fctl, tvb, offset, 3, flags);
+               tree=proto_item_add_subtree(item, ett_fctl);
+       }
+
+       proto_tree_add_boolean(tree, hf_fc_fctl_exchange_responder, tvb, offset, 3, flags);
        if (flags&FC_FCTL_EXCHANGE_RESPONDER){
                proto_item_append_text(item, " Exchange Responder");
                if (flags & (~( FC_FCTL_EXCHANGE_RESPONDER )))
@@ -547,7 +473,7 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_EXCHANGE_RESPONDER ));
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_seq_recipient, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_seq_recipient, tvb, offset, 3, flags);
        if (flags&FC_FCTL_SEQ_RECIPIENT){
                proto_item_append_text(item, " Seq Recipient");
                if (flags & (~( FC_FCTL_SEQ_RECIPIENT )))
@@ -559,7 +485,7 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_SEQ_RECIPIENT ));
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_exchange_first, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_exchange_first, tvb, offset, 3, flags);
        if (flags&FC_FCTL_EXCHANGE_FIRST){
                proto_item_append_text(item, " Exchg First");
                if (flags & (~( FC_FCTL_EXCHANGE_FIRST )))
@@ -567,7 +493,7 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_EXCHANGE_FIRST ));
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_exchange_last, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_exchange_last, tvb, offset, 3, flags);
        if (flags&FC_FCTL_EXCHANGE_LAST){
                proto_item_append_text(item, " Exchg Last");
                if (flags & (~( FC_FCTL_EXCHANGE_LAST )))
@@ -575,7 +501,7 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_EXCHANGE_LAST ));
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_seq_last, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_seq_last, tvb, offset, 3, flags);
        if (flags&FC_FCTL_SEQ_LAST){
                proto_item_append_text(item, " Seq Last");
                if (flags & (~( FC_FCTL_SEQ_LAST )))
@@ -583,7 +509,7 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_SEQ_LAST ));
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_priority, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_priority, tvb, offset, 3, flags);
        if (flags&FC_FCTL_PRIORITY){
                proto_item_append_text(item, " Priority");
                if (flags & (~( FC_FCTL_PRIORITY )))
@@ -595,7 +521,7 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_PRIORITY ));
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_transfer_seq_initiative, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_transfer_seq_initiative, tvb, offset, 3, flags);
        if (flags&FC_FCTL_TRANSFER_SEQ_INITIATIVE){
                proto_item_append_text(item, " Transfer Seq Initiative");
                if (flags & (~( FC_FCTL_TRANSFER_SEQ_INITIATIVE )))
@@ -603,11 +529,11 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_TRANSFER_SEQ_INITIATIVE ));
 
-       proto_tree_add_uint(tree, hf_fc_fctl_last_data_frame, tvb, offset, 3, fctl);
+       proto_tree_add_uint(tree, hf_fc_fctl_last_data_frame, tvb, offset, 3, flags);
 
-       proto_tree_add_uint(tree, hf_fc_fctl_ack_0_1, tvb, offset, 3, fctl);
+       proto_tree_add_uint(tree, hf_fc_fctl_ack_0_1, tvb, offset, 3, flags);
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_rexmitted_seq, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_rexmitted_seq, tvb, offset, 3, flags);
        if (flags&FC_FCTL_REXMITTED_SEQ){
                proto_item_append_text(item, " Rexmitted Seq");
                if (flags & (~( FC_FCTL_REXMITTED_SEQ )))
@@ -615,9 +541,9 @@ dissect_fc_fctl(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb,
        }
        flags&=(~( FC_FCTL_REXMITTED_SEQ ));
 
-       proto_tree_add_uint(tree, hf_fc_fctl_abts_ack, tvb, offset, 3, fctl);
+       proto_tree_add_uint(tree, hf_fc_fctl_abts_ack, tvb, offset, 3, flags);
 
-       proto_tree_add_boolean(tree, hf_fc_fctl_rel_offset, tvb, offset, 3, fctl);
+       proto_tree_add_boolean(tree, hf_fc_fctl_rel_offset, tvb, offset, 3, flags);
        if (flags&FC_FCTL_REL_OFFSET){
                proto_item_append_text(item, " Rel Offset");
                if (flags & (~( FC_FCTL_REL_OFFSET )))
@@ -667,6 +593,7 @@ dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean
 
     static fc_hdr fchdr;
     fc_exchange_data *fc_ex=NULL;
+    fc_conv_data_t *fc_conv_data=NULL;
 
     conversation_t *conversation;
     fcseq_conv_data_t *cdata;
@@ -703,8 +630,8 @@ dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean
        pinfo->srcport=0;
        pinfo->destport=0;
     }
-    SET_ADDRESS (&fchdr.d_id, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
-    SET_ADDRESS (&fchdr.s_id, pinfo->src.type, pinfo->src.len, pinfo->src.data);
+    SET_ADDRESS(&fchdr.d_id, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
+    SET_ADDRESS(&fchdr.s_id, pinfo->src.type, pinfo->src.len, pinfo->src.data);
 
     fchdr.cs_ctl = tvb_get_guint8 (tvb, offset+4);
     fchdr.type  = tvb_get_guint8 (tvb, offset+8);
@@ -720,6 +647,76 @@ dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean
     pinfo->ptype = PT_EXCHG;
     pinfo->r_ctl = fchdr.r_ctl;
 
+    /* set up a conversation and conversation data */
+    /* TODO treat the fc address  s_id==00.00.00 as a wildcard matching anything */
+    conversation=find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+                                   pinfo->ptype, pinfo->srcport,
+                                   pinfo->destport, 0);
+    if(!conversation){
+        conversation=conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst,
+                                      pinfo->ptype, pinfo->srcport,
+                                      pinfo->destport, 0);
+    }        
+    fc_conv_data=conversation_get_proto_data(conversation, proto_fc);
+    if(!fc_conv_data){
+        fc_conv_data=se_alloc(sizeof(fc_conv_data_t));
+        fc_conv_data->exchanges=se_tree_create_non_persistent(SE_TREE_TYPE_RED_BLACK, "FC Exchanges");
+        conversation_add_proto_data(conversation, proto_fc, fc_conv_data);
+    }
+
+    /* set up the exchange data */
+    /* XXX we should come up with a way to handle when the 16bit oxid wraps
+     * so that large traces will work
+     */
+    fc_ex=(fc_exchange_data *)se_tree_lookup32(fc_conv_data->exchanges, fchdr.oxid);
+    if(!fc_ex){
+        fc_ex=se_alloc(sizeof(fc_exchange_data));
+        fc_ex->first_exchange_frame=0;
+        fc_ex->last_exchange_frame=0;
+        fc_ex->fc_time=pinfo->fd->abs_ts;
+       se_tree_insert32(fc_conv_data->exchanges, fchdr.oxid, fc_ex);
+    }
+    /* populate the exchange struct */
+    if(!pinfo->fd->flags.visited){
+        if(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST){
+           fc_ex->first_exchange_frame=pinfo->fd->num;
+            fc_ex->fc_time = pinfo->fd->abs_ts;
+        }
+        if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
+            fc_ex->last_exchange_frame=pinfo->fd->num;
+        }
+    }
+
+
+    /* In the interest of speed, if "tree" is NULL, don't do any work not
+       necessary to generate protocol tree items. */
+    if (tree) {
+        ti = proto_tree_add_protocol_format (tree, proto_fc, tvb, offset,
+                                             FC_HEADER_SIZE, "Fibre Channel");
+        fc_tree = proto_item_add_subtree (ti, ett_fc);
+    }
+
+
+    /* put some nice exchange data in the tree */
+    if(!(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST)){
+        proto_item *it;
+        it=proto_tree_add_uint(fc_tree, hf_fc_exchange_first_frame, tvb, 0, 0, fc_ex->first_exchange_frame);
+        PROTO_ITEM_SET_GENERATED(it);
+        if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
+            nstime_t delta_ts;
+            nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &fc_ex->fc_time);
+            it=proto_tree_add_time(ti, hf_fc_time, tvb, 0, 0, &delta_ts);
+            PROTO_ITEM_SET_GENERATED(it);
+        }
+    }
+    if(!(fchdr.fctl&FC_FCTL_EXCHANGE_LAST)){
+        proto_item *it;
+        it=proto_tree_add_uint(fc_tree, hf_fc_exchange_last_frame, tvb, 0, 0, fc_ex->last_exchange_frame);
+        PROTO_ITEM_SET_GENERATED(it);
+    }
+
+    fchdr.fced=fc_ex;
+
     is_ack = ((fchdr.r_ctl == 0xC0) || (fchdr.r_ctl == 0xC1));
 
     /* There are two ways to determine if this is the first frame of a
@@ -749,86 +746,11 @@ dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean
                                           "LCTL 0x%x"));
     }
     
-    /* In the interest of speed, if "tree" is NULL, don't do any work not
-       necessary to generate protocol tree items. */
-    if (tree) {
-        ti = proto_tree_add_protocol_format (tree, proto_fc, tvb, offset,
-                                             FC_HEADER_SIZE, "Fibre Channel");
-        fc_tree = proto_item_add_subtree (ti, ett_fc);
-    }
-
     /* Highlight EISL header, if present */
     if (eisl_offset != -1) {
         proto_tree_add_item (fc_tree, hf_fc_eisl, tvb, eisl_offset, 8, 0);
     }
 
-    /* match first exchange with last exchange */
-    if(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST){
-        if(!pinfo->fd->flags.visited){
-            fc_exchange_data fced, *old_fced;
-
-            /* first check if we already have seen this exchange and it
-               is still open/unmatched. 
-            */
-            fced.oxid=fchdr.oxid;
-            SET_ADDRESS(&fced.s_id, fchdr.s_id.type, fchdr.s_id.len, fchdr.s_id.data);
-            SET_ADDRESS(&fced.d_id, fchdr.d_id.type, fchdr.d_id.len, fchdr.d_id.data);
-            old_fced=g_hash_table_lookup(fc_exchange_unmatched, &fced);
-            if(old_fced){
-                g_hash_table_remove(fc_exchange_unmatched, old_fced);
-            }
-            old_fced=se_alloc(sizeof(fc_exchange_data));
-            old_fced->oxid=fchdr.oxid;
-            COPY_ADDRESS(&old_fced->s_id, &fchdr.s_id);
-            COPY_ADDRESS(&old_fced->d_id, &fchdr.d_id);
-           old_fced->first_exchange_frame=pinfo->fd->num;
-            old_fced->fc_time = pinfo->fd->abs_ts;
-            g_hash_table_insert(fc_exchange_unmatched, old_fced, old_fced);
-            fc_ex=old_fced;
-        } else {
-            fc_exchange_data fced, *old_fced;
-            fced.oxid=fchdr.oxid;
-            fced.first_exchange_frame=pinfo->fd->num;
-            fced.last_exchange_frame=0;
-            old_fced=g_hash_table_lookup(fc_exchange_matched, &fced);
-            fc_ex=old_fced;
-        }
-    }
-    if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
-        if(!pinfo->fd->flags.visited){
-            fc_exchange_data fced, *old_fced;
-
-            fced.oxid=fchdr.oxid;
-            SET_ADDRESS(&fced.s_id, fchdr.d_id.type, fchdr.d_id.len, fchdr.d_id.data);
-            SET_ADDRESS(&fced.d_id, fchdr.s_id.type, fchdr.s_id.len, fchdr.s_id.data);
-            old_fced=g_hash_table_lookup(fc_exchange_unmatched, &fced);
-            if(old_fced){
-                g_hash_table_remove(fc_exchange_unmatched, old_fced);
-                old_fced->last_exchange_frame=pinfo->fd->num;
-                g_hash_table_insert(fc_exchange_matched, old_fced, old_fced);
-            }
-            fc_ex=old_fced;
-        } else {
-            fc_exchange_data fced, *old_fced;
-            fced.oxid=fchdr.oxid;
-            fced.first_exchange_frame=0;
-            fced.last_exchange_frame=pinfo->fd->num;
-            old_fced=g_hash_table_lookup(fc_exchange_matched, &fced);
-            fc_ex=old_fced;
-        }
-    }
-    if(fc_ex){
-        if(fchdr.fctl&FC_FCTL_EXCHANGE_FIRST){
-            proto_tree_add_uint(fc_tree, hf_fc_exchange_last_frame, tvb, 0, 0, fc_ex->last_exchange_frame);
-        }
-        if(fchdr.fctl&FC_FCTL_EXCHANGE_LAST){
-            nstime_t delta_ts;
-            proto_tree_add_uint(fc_tree, hf_fc_exchange_first_frame, tvb, 0, 0, fc_ex->first_exchange_frame);
-            nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &fc_ex->fc_time);
-            proto_tree_add_time(ti, hf_fc_time, tvb, 0, 0, &delta_ts);
-        }
-    }
-    fchdr.fced=fc_ex;
 
     switch (fchdr.r_ctl & 0xF0) {
 
@@ -959,7 +881,7 @@ dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean
     }
 
 
-    dissect_fc_fctl(pinfo, fc_tree, tvb, offset+9, fchdr.fctl);
+    dissect_fc_fctl(pinfo, fc_tree, tvb, offset+9);
 
 
     proto_tree_add_item (fc_tree, hf_fc_seqid, tvb, offset+12, 1, FALSE);
@@ -1077,15 +999,6 @@ dissect_fc_helper (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean
          * SEQ_CNT of the first frame in sequence and use this value to
          * determine the actual offset into a frame.
          */
-        conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                          pinfo->ptype, pinfo->oxid,
-                                          pinfo->rxid, NO_PORT2);
-        if (!conversation) {
-            conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                             pinfo->ptype, pinfo->oxid,
-                                             pinfo->rxid, NO_PORT2);
-        }
-        
         ckey.conv_idx = conversation->index;
         
         cdata = (fcseq_conv_data_t *)g_hash_table_lookup (fcseq_req_hash,