Exemplo n.º 1
0
static void
wmem_test_map(void)
{
    wmem_allocator_t *allocator;
    wmem_map_t       *map;
    gchar            *str_key;
    unsigned int      i;
    void             *ret;

    allocator = wmem_allocator_new(WMEM_ALLOCATOR_STRICT);

    /* insertion, lookup and removal of simple integer keys */
    map = wmem_map_new(allocator, g_direct_hash, g_direct_equal);
    g_assert(map);

    for (i=0; i<CONTAINER_ITERS; i++) {
        ret = wmem_map_insert(map, GINT_TO_POINTER(i), GINT_TO_POINTER(777777));
        g_assert(ret == NULL);
        ret = wmem_map_insert(map, GINT_TO_POINTER(i), GINT_TO_POINTER(i));
        g_assert(ret == GINT_TO_POINTER(777777));
        ret = wmem_map_insert(map, GINT_TO_POINTER(i), GINT_TO_POINTER(i));
        g_assert(ret == GINT_TO_POINTER(i));
    }
    for (i=0; i<CONTAINER_ITERS; i++) {
        ret = wmem_map_lookup(map, GINT_TO_POINTER(i));
        g_assert(ret == GINT_TO_POINTER(i));
        ret = wmem_map_remove(map, GINT_TO_POINTER(i));
        g_assert(ret == GINT_TO_POINTER(i));
        ret = wmem_map_lookup(map, GINT_TO_POINTER(i));
        g_assert(ret == NULL);
        ret = wmem_map_remove(map, GINT_TO_POINTER(i));
        g_assert(ret == NULL);
    }
    wmem_free_all(allocator);

    map = wmem_map_new(allocator, wmem_str_hash, g_str_equal);
    g_assert(map);

    /* string keys and for-each */
    for (i=0; i<CONTAINER_ITERS; i++) {
        str_key = wmem_test_rand_string(allocator, 1, 64);
        wmem_map_insert(map, str_key, GINT_TO_POINTER(i));
        ret = wmem_map_lookup(map, str_key);
        g_assert(ret == GINT_TO_POINTER(i));
    }

    wmem_destroy_allocator(allocator);
}
Exemplo n.º 2
0
void
register_ros_protocol_info(const char *oid, const ros_info_t *rinfo, int proto _U_, const char *name, gboolean uses_rtse)
{
	wmem_map_insert(protocol_table, (gpointer)oid, (gpointer)rinfo);

	if(!uses_rtse)
	  /* if we are not using RTSE, then we must register ROS with BER (ACSE) */
	  register_ber_oid_dissector_handle(oid, ros_handle, proto, name);
}
Exemplo n.º 3
0
static usb_i1d3_transaction_t *usb_i1d3_create_transaction(
        usb_i1d3_conversation_t *conversation, guint32 request) {
    usb_i1d3_transaction_t *transaction = wmem_new0(
            wmem_file_scope(), usb_i1d3_transaction_t);
    transaction->request = request;
    wmem_map_insert(
            conversation->request_to_transaction,
            GUINT_TO_POINTER(transaction->request), (void *)transaction);
    return transaction;
}
Exemplo n.º 4
0
/*
 * Add an entry for a new OUI.
 */
void
llc_add_oui(guint32 oui, const char *table_name, const char *table_ui_name,
	    hf_register_info *hf_item, const int proto)
{
	oui_info_t *new_info;

	new_info = wmem_new(wmem_epan_scope(), oui_info_t);
	new_info->table = register_dissector_table(table_name,
	    table_ui_name, proto, FT_UINT16, BASE_HEX);
	new_info->field_info = hf_item;

	/*
	 * Create the hash table for OUI information, if it doesn't
	 * already exist.
	 */
	if (oui_info_table == NULL) {
		oui_info_table = wmem_map_new(wmem_epan_scope(), g_direct_hash,
		    g_direct_equal);
	}
	wmem_map_insert(oui_info_table, GUINT_TO_POINTER(oui), new_info);
}
Exemplo n.º 5
0
// Finds out whether this is the first blip frame in the blip message (which can consist of a series of frames).
// If it is, updates the conversation_entry_ptr->blip_requests hash to record the pinfo->num (wireshark packet number)
static gboolean
is_first_frame_in_msg(blip_conversation_entry_t *conversation_entry_ptr, packet_info *pinfo,
					  guint64 value_frame_flags, guint64 value_message_num) {

	gboolean first_frame_in_msg = TRUE;

	// Temporary pool for the lookup hash_key.	Will get duplicated on the file_scope() pool if needed to be
	// stored in the hashtable.
	gchar *hash_key = message_hash_key_convo(pinfo, value_frame_flags, value_message_num);
	guint* first_frame_number_for_msg = (guint*)wmem_map_lookup(conversation_entry_ptr->blip_requests, (void *) hash_key);

	if (first_frame_number_for_msg != NULL) {
		if (GPOINTER_TO_UINT(first_frame_number_for_msg) != pinfo->num) {
			first_frame_in_msg = FALSE;
		}
	} else {
		// If storing the key in the hashmap, re-allocate it with the file_scope() allocator
		gchar *hash_key_copy = wmem_strdup(wmem_file_scope(), hash_key);

		wmem_map_insert(conversation_entry_ptr->blip_requests, (void *) hash_key_copy, GUINT_TO_POINTER(pinfo->num));
	}

	return first_frame_in_msg;
}
Exemplo n.º 6
0
static void
dissect_fcp_cmnd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, proto_tree *tree, conversation_t *conversation, fc_hdr *fchdr, fcp_conv_data_t *fcp_conv_data)
{
    int          offset  = 0;
    int          add_len = 0;
    guint8       flags, rwflags, lun0;
    guint16      lun     = 0xffff;
    tvbuff_t    *cdb_tvb;
    int          tvb_len;
    fcp_request_data_t *request_data = NULL;
    itl_nexus_t itl;
    fcp_proto_data_t *proto_data;

    /* Determine the length of the FCP part of the packet */
    flags = tvb_get_guint8(tvb, offset+10);
    if (flags) {
        add_len = tvb_get_guint8(tvb, offset+11) & 0x7C;
        add_len = add_len >> 2;
    }

    lun0 = tvb_get_guint8(tvb, offset);

    /* Display single-level LUNs in decimal for clarity */
    /* I'm taking a shortcut here by assuming that if the first byte of the
     * LUN field is 0, it is a single-level LUN. This is not true. For a
     * real single-level LUN, all 8 bytes except byte 1 must be 0.
     */
    if (lun0) {
      proto_tree_add_item(tree, hf_fcp_multilun, tvb, offset, 8, ENC_NA);
      lun = tvb_get_guint8(tvb, offset) & 0x3f;
      lun <<= 8;
      lun |= tvb_get_guint8(tvb, offset+1);
    } else {
      proto_tree_add_item(tree, hf_fcp_singlelun, tvb, offset+1,
                          1, ENC_BIG_ENDIAN);
      lun = tvb_get_guint8(tvb, offset+1);
    }

    if (!pinfo->fd->flags.visited) {
        proto_data = wmem_new(wmem_file_scope(), fcp_proto_data_t);
        proto_data->lun = lun;
        p_add_proto_data(wmem_file_scope(), pinfo, proto_fcp, 0, proto_data);
    }

    request_data = (fcp_request_data_t*)wmem_map_lookup(fcp_conv_data->luns, GUINT_TO_POINTER((guint)lun));
    if (!request_data) {
        request_data = wmem_new(wmem_file_scope(), fcp_request_data_t);
        request_data->request_frame = pinfo->num;
        request_data->response_frame = 0;
        request_data->request_time = pinfo->abs_ts;

        request_data->itlq = wmem_new(wmem_file_scope(), itlq_nexus_t);
        request_data->itlq->first_exchange_frame=0;
        request_data->itlq->last_exchange_frame=0;
        request_data->itlq->lun=lun;
        request_data->itlq->scsi_opcode=0xffff;
        request_data->itlq->task_flags=0;
        request_data->itlq->data_length=0;
        request_data->itlq->bidir_data_length=0;
        request_data->itlq->fc_time=pinfo->abs_ts;
        request_data->itlq->flags=0;
        request_data->itlq->alloc_len=0;
        request_data->itlq->extra_data=NULL;

        wmem_map_insert(fcp_conv_data->luns, GUINT_TO_POINTER((guint)lun), request_data);
    }

    /* populate the exchange struct */
    if(!pinfo->fd->flags.visited){
        if(fchdr->fctl&FC_FCTL_EXCHANGE_FIRST){
            request_data->itlq->first_exchange_frame=pinfo->num;
            request_data->itlq->fc_time = pinfo->abs_ts;
        }
        if(fchdr->fctl&FC_FCTL_EXCHANGE_LAST){
            request_data->itlq->last_exchange_frame=pinfo->num;
        }
    }

    if (request_data->itlq)
        request_data->itlq->lun = lun;

    fchdr->lun = lun;

    proto_tree_add_item(tree, hf_fcp_crn, tvb, offset+8, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_fcp_taskattr, tvb, offset+9, 1, ENC_BIG_ENDIAN);
    dissect_task_mgmt_flags(pinfo, tree, tvb, offset+10);
    proto_tree_add_item(tree, hf_fcp_addlcdblen, tvb, offset+11, 1, ENC_BIG_ENDIAN);
    rwflags = tvb_get_guint8(tvb, offset+11);
    if (request_data->itlq) {
        if (rwflags & 0x02) {
            request_data->itlq->task_flags |= SCSI_DATA_READ;
        }
        if (rwflags & 0x01) {
            request_data->itlq->task_flags |= SCSI_DATA_WRITE;
        }
    }
    proto_tree_add_item(tree, hf_fcp_rddata, tvb, offset+11, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(tree, hf_fcp_wrdata, tvb, offset+11, 1, ENC_BIG_ENDIAN);

    tvb_len = tvb_captured_length_remaining(tvb, offset+12);
    if (tvb_len > (16 + add_len))
      tvb_len = 16 + add_len;

    itl.cmdset = 0xff;
    itl.conversation = conversation;

    cdb_tvb = tvb_new_subset_length(tvb, offset+12, tvb_len);
    dissect_scsi_cdb(cdb_tvb, pinfo, parent_tree, SCSI_DEV_UNKNOWN, request_data->itlq, &itl);

    proto_tree_add_item(tree, hf_fcp_dl, tvb, offset+12+16+add_len,
                        4, ENC_BIG_ENDIAN);
    if (request_data->itlq) {
        request_data->itlq->data_length = tvb_get_ntohl(tvb, offset+12+16+add_len);
    }

    if ( ((rwflags & 0x03) == 0x03)
    &&  tvb_reported_length_remaining(tvb, offset+12+16+add_len+4) >= 4) {
        proto_tree_add_item(tree, hf_fcp_bidir_dl, tvb, offset+12+16+add_len+4,
                            4, ENC_BIG_ENDIAN);
        if (request_data->itlq) {
            request_data->itlq->bidir_data_length = tvb_get_ntohl(tvb, offset+12+16+add_len+4);
        }

    }

}
Exemplo n.º 7
0
/*
 * Function for the PANA PDU dissector.
 */
static void
dissect_pana_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

        proto_tree        *pana_tree = NULL;
        guint16            flags;
        guint16            msg_type;
        guint32            msg_length;
        guint32            avp_length;
        guint32            seq_num;
        conversation_t     *conversation;
        pana_conv_info_t   *pana_info;
        pana_transaction_t *pana_trans;
        int offset = 0;

        col_set_str(pinfo->cinfo, COL_PROTOCOL, "PANA");
        col_clear(pinfo->cinfo,   COL_INFO);

        /* Get message length, type and flags */
        msg_length = tvb_get_ntohs(tvb, 2);
        flags      = tvb_get_ntohs(tvb, 4);
        msg_type   = tvb_get_ntohs(tvb, 6);
        seq_num    = tvb_get_ntohl(tvb, 12);
        avp_length = msg_length - 16;

        col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s-%s",
                     val_to_str(msg_type, msg_type_names, "Unknown (%d)"),
                     val_to_str(flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)"));

        /* Make the protocol tree */
        if (tree) {
                proto_item *ti;
                ti = proto_tree_add_item(tree, proto_pana, tvb, 0, -1, ENC_NA);
                pana_tree = proto_item_add_subtree(ti, ett_pana);
        }


        /*
         * We need to track some state for this protocol on a per conversation
         * basis so we can do neat things like request/response tracking
         */
        conversation = find_or_create_conversation(pinfo);

        /*
         * Do we already have a state structure for this conv
         */
        pana_info = (pana_conv_info_t *)conversation_get_proto_data(conversation, proto_pana);
        if (!pana_info) {
                /* No.  Attach that information to the conversation, and add
                 * it to the list of information structures.
                 */
                pana_info = wmem_new(wmem_file_scope(), pana_conv_info_t);
                pana_info->pdus=wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);

                conversation_add_proto_data(conversation, proto_pana, pana_info);
        }

        if(!pinfo->fd->flags.visited){
                if(flags&PANA_FLAG_R){
                        /* This is a request */
                        pana_trans=wmem_new(wmem_file_scope(), pana_transaction_t);
                        pana_trans->req_frame=pinfo->num;
                        pana_trans->rep_frame=0;
                        pana_trans->req_time=pinfo->abs_ts;
                        wmem_map_insert(pana_info->pdus, GUINT_TO_POINTER(seq_num), (void *)pana_trans);
                } else {
                        pana_trans=(pana_transaction_t *)wmem_map_lookup(pana_info->pdus, GUINT_TO_POINTER(seq_num));
                        if(pana_trans){
                                pana_trans->rep_frame=pinfo->num;
                        }
                }
        } else {
                pana_trans=(pana_transaction_t *)wmem_map_lookup(pana_info->pdus, GUINT_TO_POINTER(seq_num));
        }

        if(!pana_trans){
                /* create a "fake" pana_trans structure */
                pana_trans=wmem_new(wmem_packet_scope(), pana_transaction_t);
                pana_trans->req_frame=0;
                pana_trans->rep_frame=0;
                pana_trans->req_time=pinfo->abs_ts;
        }

        /* print state tracking in the tree */
        if(flags&PANA_FLAG_R){
                /* This is a request */
                if(pana_trans->rep_frame){
                        proto_item *it;

                        it=proto_tree_add_uint(pana_tree, hf_pana_response_in, tvb, 0, 0, pana_trans->rep_frame);
                        PROTO_ITEM_SET_GENERATED(it);
                }
        } else {
                /* This is a reply */
                if(pana_trans->req_frame){
                        proto_item *it;
                        nstime_t ns;

                        it=proto_tree_add_uint(pana_tree, hf_pana_response_to, tvb, 0, 0, pana_trans->req_frame);
                        PROTO_ITEM_SET_GENERATED(it);

                        nstime_delta(&ns, &pinfo->abs_ts, &pana_trans->req_time);
                        it=proto_tree_add_time(pana_tree, hf_pana_response_time, tvb, 0, 0, &ns);
                        PROTO_ITEM_SET_GENERATED(it);
                }
        }

        /* Reserved field */
        proto_tree_add_item(pana_tree, hf_pana_reserved_type, tvb, offset, 2, ENC_NA);
        offset += 2;

        /* Length */
        proto_tree_add_item(pana_tree, hf_pana_length_type, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;

        /* Flags */
        dissect_pana_flags(pana_tree, tvb, offset, flags);
        offset += 2;

        /* Message Type */
        proto_tree_add_uint_format_value(pana_tree, hf_pana_msg_type, tvb,
                                         offset, 2, msg_type, "%s-%s (%d)",
                                         val_to_str(msg_type, msg_type_names, "Unknown (%d)"),
                                         val_to_str(flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)"),
                                         msg_type);
        offset += 2;

        /* Session ID */
        proto_tree_add_item(pana_tree, hf_pana_session_id, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;

        /* Sequence Number */
        proto_tree_add_item(pana_tree, hf_pana_seqnumber, tvb, offset, 4, ENC_BIG_ENDIAN);
        offset += 4;

        /* AVPs */
        if(avp_length != 0){
                tvbuff_t   *avp_tvb;
                proto_tree *avp_tree;
                avp_tvb  = tvb_new_subset_length(tvb, offset, avp_length);
                avp_tree = proto_tree_add_subtree(pana_tree, tvb, offset, avp_length, ett_pana_avp, NULL, "Attribute Value Pairs");

                dissect_avps(avp_tvb, pinfo, avp_tree);
        }

}
Exemplo n.º 8
0
static void dissect_usb_i1d3_response(
        tvbuff_t *tvb, packet_info *pinfo,
        usb_i1d3_conversation_t *conversation, proto_tree *tree) {
    // The response packet does not contain any information about the command
    // it is a response to, so we need to reconstruct this information using the
    // previous packet that we saw.
    //
    // Note: currently, for simplicity's sake, this assumes that there is only
    // one inflight request at any given time - in other words, that there is no
    // pipelining going on. It is not clear if the device would even be able to
    // service more than one request at the same time in the first place.
    usb_i1d3_transaction_t *transaction;
    if (!PINFO_FD_VISITED(pinfo)) {
        transaction = (usb_i1d3_transaction_t *)wmem_map_lookup(
                conversation->request_to_transaction,
                GUINT_TO_POINTER(conversation->previous_packet));
        if (transaction) {
            DISSECTOR_ASSERT(transaction->response == 0);
            transaction->response = pinfo->num;
            wmem_map_insert(
                    conversation->response_to_transaction,
                    GUINT_TO_POINTER(transaction->response),
                    (void *)transaction);
        }
    } else {
        // After the first pass, we can't use previous_packet anymore since
        // there is no guarantee the dissector is called in order, so we use
        // the reverse mapping that we populated above.
        transaction = (usb_i1d3_transaction_t *)wmem_map_lookup(
                conversation->response_to_transaction,
                GUINT_TO_POINTER(pinfo->num));
    }
    if (transaction) {
        DISSECTOR_ASSERT(transaction->response == pinfo->num);
        DISSECTOR_ASSERT(transaction->request != 0);
    }

    proto_item *request_item = proto_tree_add_uint(
            tree, hf_usb_i1d3_request_in, tvb, 0, 0,
            transaction ? transaction->request : 0);
    PROTO_ITEM_SET_GENERATED(request_item);
    if (!transaction) {
        expert_add_info(pinfo, request_item, &ei_usb_i1d3_unexpected_response);
    } else {
        proto_item *command_code_item = proto_tree_add_uint(
                tree, hf_usb_i1d3_command_code, tvb, 0, 0,
                transaction->command_code);
        PROTO_ITEM_SET_GENERATED(command_code_item);
    }

    const gchar *command_string = transaction ? try_val_to_str(
            transaction->command_code, usb_i1d3_command_code_strings) : NULL;
    if (!command_string) command_string = "unknown";

    guint32 response_code;
    proto_item *response_code_item = proto_tree_add_item_ret_uint(
            tree, hf_usb_i1d3_response_code, tvb, 0, 1, ENC_NA, &response_code);
    proto_item_append_text(
            response_code_item, " (%s)", (response_code == 0) ? "OK" : "error");
    if (response_code != 0) {
        col_add_fstr(
                pinfo->cinfo, COL_INFO, "Error code %u (%s)",
                response_code, command_string);
        expert_add_info(pinfo, response_code_item, &ei_usb_i1d3_error);
        return;
    }

    col_add_fstr(pinfo->cinfo, COL_INFO, "OK (%s)", command_string);

    if (!transaction) return;

    // As mentioned in ArgyllCMS spectro/i1d3.c, the second byte is usually the
    // first byte of the command code, except for GET_DIFF.
    if (transaction->command_code != USB_I1D3_GET_DIFF) {
        guint32 echoed_command_code;
        proto_item *echoed_command_code_item = proto_tree_add_item_ret_uint(
                tree, hf_usb_i1d3_echoed_command_code, tvb, 1, 1, ENC_NA,
                &echoed_command_code);
        guint8 expected_command_code = transaction->command_code >> 8;
        proto_item_append_text(
                echoed_command_code_item, " [expected 0x%02x]",
                expected_command_code);
        if (echoed_command_code != expected_command_code) {
            expert_add_info(
                    pinfo, echoed_command_code_item,
                    &ei_usb_i1d3_echoed_command_code_mismatch);
        }
    }
Exemplo n.º 9
0
static ros_call_response_t *
ros_match_call_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint invokeId, gboolean isInvoke)
{
  ros_call_response_t rcr, *rcrp=NULL;
  ros_conv_info_t *ros_info;
  conversation_t *conversation;

  /* first see if we have already matched this */
  conversation = find_conversation_pinfo(pinfo, 0);
  if (conversation == NULL)
    return NULL;

  ros_info = (ros_conv_info_t *)conversation_get_proto_data(conversation, proto_ros);
  if (ros_info == NULL)
    return NULL;

  rcr.invokeId=invokeId;
  rcr.is_request = isInvoke;

  if(isInvoke) {
    rcr.req_frame=pinfo->num;
    rcr.rep_frame=0;
  } else {
    rcr.req_frame=0;
    rcr.rep_frame=pinfo->num;
  }

  rcrp=(ros_call_response_t *)wmem_map_lookup(ros_info->matched, &rcr);

  if(rcrp) {
    /* we have found a match */
    rcrp->is_request=rcr.is_request;

  } else {

    /* we haven't found a match - try and match it up */

    if(isInvoke) {
      /* this a a request - add it to the unmatched list */

      /* check that we don't already have one of those in the
	 unmatched list and if so remove it */

      rcr.invokeId=invokeId;

      rcrp=(ros_call_response_t *)wmem_map_lookup(ros_info->unmatched, &rcr);

      if(rcrp){
	wmem_map_remove(ros_info->unmatched, rcrp);
      }

      /* if we can't reuse the old one, grab a new chunk */
      if(!rcrp){
	rcrp=wmem_new(wmem_file_scope(), ros_call_response_t);
      }
      rcrp->invokeId=invokeId;
      rcrp->req_frame=pinfo->num;
      rcrp->req_time=pinfo->abs_ts;
      rcrp->rep_frame=0;
      rcrp->is_request=TRUE;
      wmem_map_insert(ros_info->unmatched, rcrp, rcrp);
      return NULL;

    } else {

      /* this is a result - it should be in our unmatched list */

      rcr.invokeId=invokeId;
      rcrp=(ros_call_response_t *)wmem_map_lookup(ros_info->unmatched, &rcr);

      if(rcrp){

	if(!rcrp->rep_frame){
	  wmem_map_remove(ros_info->unmatched, rcrp);
	  rcrp->rep_frame=pinfo->num;
	  rcrp->is_request=FALSE;
	  wmem_map_insert(ros_info->matched, rcrp, rcrp);
	}
      }
    }
  }

  if(rcrp){ /* we have found a match */
    proto_item *item = NULL;

    if(rcrp->is_request){
      item=proto_tree_add_uint(tree, hf_ros_response_in, tvb, 0, 0, rcrp->rep_frame);
      PROTO_ITEM_SET_GENERATED (item);
    } else {
      nstime_t ns;
      item=proto_tree_add_uint(tree, hf_ros_response_to, tvb, 0, 0, rcrp->req_frame);
      PROTO_ITEM_SET_GENERATED (item);
      nstime_delta(&ns, &pinfo->abs_ts, &rcrp->req_time);
      item=proto_tree_add_time(tree, hf_ros_time, tvb, 0, 0, &ns);
      PROTO_ITEM_SET_GENERATED (item);
    }
  }

  return rcrp;
}
Exemplo n.º 10
0
static void
request_response_handling(tvbuff_t *tvb, packet_info *pinfo, proto_tree *djiuav_tree,
                          guint32 offset)
{
    conversation_t		*conversation;
    djiuav_conv_info_t	*djiuav_info;
    djiuav_transaction_t	*djiuav_trans;

    guint16			seq_no;
    gboolean		is_cmd;
    guint8			packet_type;

    is_cmd = (pinfo->match_uint == pinfo->destport);
    seq_no = tvb_get_letohs(tvb, offset + 4);
    packet_type = tvb_get_guint8(tvb, offset + 6);

    conversation = find_or_create_conversation(pinfo);
    djiuav_info = (djiuav_conv_info_t *)conversation_get_proto_data(conversation, proto_djiuav);
    if (!djiuav_info) {
        djiuav_info = wmem_new(wmem_file_scope(), djiuav_conv_info_t);
        djiuav_info->pdus=wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);

        conversation_add_proto_data(conversation, proto_djiuav, djiuav_info);
    }
    if (!pinfo->fd->flags.visited) {
        if (is_cmd) {
            djiuav_trans=wmem_new(wmem_file_scope(), djiuav_transaction_t);
            djiuav_trans->request_frame=pinfo->fd->num;
            djiuav_trans->reply_frame=0;
            djiuav_trans->request_time=pinfo->fd->abs_ts;
            djiuav_trans->seqno=seq_no;
            djiuav_trans->command=packet_type;
            wmem_map_insert(djiuav_info->pdus, GUINT_TO_POINTER((guint)seq_no), (void *)djiuav_trans);
        } else {
            djiuav_trans=(djiuav_transaction_t *)wmem_map_lookup(djiuav_info->pdus, GUINT_TO_POINTER((guint)seq_no));
            if (djiuav_trans) {
                /* Special case: djiuav seems to send 0x24 replies with seqno 0 and without a request */
                if (djiuav_trans->reply_frame == 0)
                    djiuav_trans->reply_frame=pinfo->fd->num;
            }
        }
    } else {
        djiuav_trans=(djiuav_transaction_t *)wmem_map_lookup(djiuav_info->pdus, GUINT_TO_POINTER((guint)seq_no));
    }

    /* djiuav_trans may be 0 in case it's a reply without a matching request */

    if (djiuav_tree && djiuav_trans) {
        if (is_cmd) {
            if (djiuav_trans->reply_frame) {
                proto_item *it;

                it = proto_tree_add_uint(djiuav_tree, hf_djiuav_response_in,
                                         tvb, 0, 0, djiuav_trans->reply_frame);
                PROTO_ITEM_SET_GENERATED(it);
            }
        } else {
            if (djiuav_trans->request_frame) {
                proto_item *it;
                nstime_t ns;

                it = proto_tree_add_uint(djiuav_tree, hf_djiuav_response_to,
                                         tvb, 0, 0, djiuav_trans->request_frame);
                PROTO_ITEM_SET_GENERATED(it);

                nstime_delta(&ns, &pinfo->fd->abs_ts, &djiuav_trans->request_time);
                it = proto_tree_add_time(djiuav_tree, hf_djiuav_response_time, tvb, 0, 0, &ns);
                PROTO_ITEM_SET_GENERATED(it);
            }
        }
    }
}