Example #1
0
/* store a guid to name mapping */
void
guids_add_guid(const e_guid_t *guid, const gchar *name)
{
	wmem_tree_key_t guidkey[2];
	guint32 g[4];

	g[0]=guid->data1;

	g[1]=guid->data2;
	g[1]<<=16;
	g[1]|=guid->data3;

	g[2]=guid->data4[0];
	g[2]<<=8;
	g[2]|=guid->data4[1];
	g[2]<<=8;
	g[2]|=guid->data4[2];
	g[2]<<=8;
	g[2]|=guid->data4[3];

	g[3]=guid->data4[4];
	g[3]<<=8;
	g[3]|=guid->data4[5];
	g[3]<<=8;
	g[3]|=guid->data4[6];
	g[3]<<=8;
	g[3]|=guid->data4[7];

	guidkey[0].key=g;
	guidkey[0].length=4;
	guidkey[1].length=0;

	wmem_tree_insert32_array(guid_to_name_tree, &guidkey[0], (gchar *) name);
}
Example #2
0
void
nvme_add_cmd_cqe_to_done_list(struct nvme_q_ctx *q_ctx,
                              struct nvme_cmd_ctx *cmd_ctx, guint16 cmd_id)
{
    wmem_tree_key_t cmd_key[3];
    guint32 key = cmd_id;
    guint32 frame_num;

    nvme_build_done_cmd_key(cmd_key, &key, &frame_num);

    /* found matchng entry. Add entries to the matched table for both cmd and cqe.
     */
    frame_num = cmd_ctx->cqe_pkt_num;
    wmem_tree_insert32_array(q_ctx->done_cmds, cmd_key, (void*)cmd_ctx);

    frame_num = cmd_ctx->cmd_pkt_num;
    wmem_tree_insert32_array(q_ctx->done_cmds, cmd_key, (void*)cmd_ctx);
}
Example #3
0
void
nvme_add_data_response(struct nvme_q_ctx *q_ctx,
                       struct nvme_cmd_ctx *cmd_ctx, guint32 rkey)
{
    wmem_tree_key_t cmd_key[3];
    guint32 key = rkey;
    guint32 frame_num;

    nvme_build_done_cmd_key(cmd_key, &key, &frame_num);

    /* Found matching data response packet. Add entries to the matched table
     * for cmd and response packets
     */
    frame_num = cmd_ctx->data_req_pkt_num;
    wmem_tree_insert32_array(q_ctx->data_responses, cmd_key, (void*)cmd_ctx);

    frame_num = cmd_ctx->data_resp_pkt_num;
    wmem_tree_insert32_array(q_ctx->data_responses, cmd_key, (void*)cmd_ctx);
}
Example #4
0
void nvme_add_data_request(packet_info *pinfo, struct nvme_q_ctx *q_ctx,
                           struct nvme_cmd_ctx *cmd_ctx, void *ctx)
{
    wmem_tree_key_t cmd_key[3];
    guint32 key = cmd_ctx->remote_key;

    cmd_ctx->data_req_pkt_num = pinfo->num;
    cmd_ctx->data_resp_pkt_num = 0;
    nvme_build_pending_cmd_key(cmd_key, &key);
    wmem_tree_insert32_array(q_ctx->data_requests, cmd_key, (void *)ctx);
}
Example #5
0
void
nvme_add_cmd_to_pending_list(packet_info *pinfo, struct nvme_q_ctx *q_ctx,
                             struct nvme_cmd_ctx *cmd_ctx,
                             void *ctx, guint16 cmd_id)
{
    wmem_tree_key_t cmd_key[3];
    guint32 key = cmd_id;

    cmd_ctx->cmd_pkt_num = pinfo->num;
    cmd_ctx->cqe_pkt_num = 0;
    cmd_ctx->cmd_start_time = pinfo->abs_ts;
    nstime_set_zero(&cmd_ctx->cmd_end_time);
    cmd_ctx->remote_key = 0;

    /* this is a new cmd, create a new command context and map it to the
       unmatched table
     */
    nvme_build_pending_cmd_key(cmd_key, &key);
    wmem_tree_insert32_array(q_ctx->pending_cmds, cmd_key, (void *)ctx);
}
Example #6
0
static gint
dissect_hci_mon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
    proto_tree       *hci_mon_item;
    proto_item       *hci_mon_tree;
    proto_item       *sub_item;
    gint              offset = 0;
    guint16           opcode;
    guint16           adapter_id;
    bluetooth_data_t *bluetooth_data;
    tvbuff_t         *next_tvb;
    guint32          *adapter_disconnect_in_frame;
    wmem_tree_t      *subtree;
    wmem_tree_key_t  key[4];
    guint32          k_interface_id;
    guint32          k_adapter_id;
    guint32          k_frame_number;

    bluetooth_data = (bluetooth_data_t *) data;

    DISSECTOR_ASSERT(bluetooth_data->previous_protocol_data_type == BT_PD_BTMON);
    adapter_id = bluetooth_data->previous_protocol_data.btmon->adapter_id;
    opcode = bluetooth_data->previous_protocol_data.btmon->opcode;

    if (opcode == 0x00 || opcode == 0x01)
        pinfo->p2p_dir = P2P_DIR_RECV;
    else if (opcode % 2)
        pinfo->p2p_dir = P2P_DIR_RECV;
    else
        pinfo->p2p_dir = P2P_DIR_SENT;

    hci_mon_item = proto_tree_add_item(tree, proto_hci_mon, tvb, offset, tvb_captured_length(tvb), ENC_NA);
    hci_mon_tree = proto_item_add_subtree(hci_mon_item, ett_hci_mon);

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_MON");

    if (opcode == 0x00 || opcode == 0x01)
        col_set_str(pinfo->cinfo, COL_INFO, "Info ");
    else switch (pinfo->p2p_dir) {

    case P2P_DIR_SENT:
        col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
        break;

    case P2P_DIR_RECV:
        col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
        break;

    default:
        col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
        break;
    }

    sub_item = proto_tree_add_uint(hci_mon_tree, hf_adapter_id,  tvb, offset, 0, adapter_id);
    PROTO_ITEM_SET_GENERATED(sub_item);

    sub_item = proto_tree_add_uint(hci_mon_tree, hf_opcode, tvb, offset, 0, opcode);
    PROTO_ITEM_SET_GENERATED(sub_item);

    col_append_fstr(pinfo->cinfo, COL_INFO, "Adapter Id: %u, Opcode: %s",
            adapter_id, val_to_str_ext_const(opcode, &hci_mon_opcode_vals_ext, "Unknown"));

    bluetooth_data->adapter_id = adapter_id;

    k_interface_id = bluetooth_data->interface_id;
    k_adapter_id   = adapter_id;
    k_frame_number = pinfo->num;

    key[0].length = 1;
    key[0].key    = &k_interface_id;
    key[1].length = 1;
    key[1].key    = &k_adapter_id;

    if (!pinfo->fd->flags.visited && opcode == 0x01) { /* Delete Index */
        guint32           *disconnect_in_frame;

        key[2].length = 1;
        key[2].key    = &k_frame_number;
        key[3].length = 0;
        key[3].key    = NULL;

        disconnect_in_frame = wmem_new(wmem_file_scope(), guint32);

        if (disconnect_in_frame) {
            *disconnect_in_frame = pinfo->num;

            wmem_tree_insert32_array(adapter_to_disconnect_in_frame, key, disconnect_in_frame);
        }
    }

    key[2].length = 0;
    key[2].key    = NULL;

    subtree = (wmem_tree_t *) wmem_tree_lookup32_array(adapter_to_disconnect_in_frame, key);
    adapter_disconnect_in_frame = (subtree) ? (guint32 *) wmem_tree_lookup32_le(subtree, k_frame_number) : NULL;
    if (adapter_disconnect_in_frame) {
        bluetooth_data->adapter_disconnect_in_frame = adapter_disconnect_in_frame;
    } else {
        bluetooth_data->adapter_disconnect_in_frame = &max_disconnect_in_frame;
    }

    pinfo->ptype = PT_BLUETOOTH;

    next_tvb = tvb_new_subset_remaining(tvb, offset);

    switch(opcode) {
    case 0x00: /* New Index */
        proto_tree_add_item(hci_mon_tree, hf_bus, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;

        proto_tree_add_item(hci_mon_tree, hf_type, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;

        offset = dissect_bd_addr(hf_bd_addr, pinfo, hci_mon_tree, tvb, offset, TRUE, bluetooth_data->interface_id, bluetooth_data->adapter_id, NULL);

        proto_tree_add_item(hci_mon_tree, hf_name, tvb, offset, 8, ENC_NA | ENC_ASCII);
        offset += 8;

        break;
    case 0x01: /* Delete Index */
        /* No parameters */

        break;
    case 0x02: /* HCI Command Packet */
        call_dissector_with_data(bthci_cmd_handle, next_tvb, pinfo, tree, bluetooth_data);
        offset = tvb_reported_length(tvb);

        break;
   case 0x03:  /* HCI Event Packet */
        call_dissector_with_data(bthci_evt_handle, next_tvb, pinfo, tree, bluetooth_data);
        offset = tvb_reported_length(tvb);

        break;
   case 0x04:  /* ACL Tx Packet */
   case 0x05:  /* ACL Rx Packet */
        call_dissector_with_data(bthci_acl_handle, next_tvb, pinfo, tree, bluetooth_data);
        offset = tvb_reported_length(tvb);

        break;
   case 0x06:  /* SCO Tx Packet */
   case 0x07:  /* SCO Rx Packet */
        call_dissector_with_data(bthci_sco_handle, next_tvb, pinfo, tree, bluetooth_data);
        offset = tvb_reported_length(tvb);

        break;
    }

    if (tvb_reported_length_remaining(tvb, offset) > 0) {
        proto_tree_add_expert(hci_mon_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset));
        offset = tvb_reported_length(tvb);
    }

   /* NOTE: Oops... HCI_MON have special packet with length 0, but there is a pseudo-header with certain infos,
            mark it as dissected */
    if (opcode == 0x01)
        return 1;

    return offset;
}
Example #7
0
static void
save_command(guint32 cmd, guint32 arg0, guint32 arg1, guint32 data_length,
        guint32 crc32, service_data_t *service_data, gint proto, void *data,
        packet_info *pinfo, service_data_t **returned_service_data,
        command_data_t **returned_command_data)
{
    wmem_tree_key_t  key[6];
    guint32          interface_id;
    guint32          bus_id;
    guint32          device_address;
    guint32          side_id;
    guint32          frame_number;
    command_data_t  *command_data;
    wmem_tree_t     *wmem_tree;
    gint             direction = P2P_DIR_UNKNOWN;
    usb_conv_info_t *usb_conv_info = (usb_conv_info_t *) data;

    frame_number = pinfo->fd->num;

    if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
        interface_id = pinfo->phdr->interface_id;
    else
        interface_id = 0;

    if (proto == proto_usb) {
        usb_conv_info = (usb_conv_info_t *) data;
        DISSECTOR_ASSERT(usb_conv_info);

        direction = usb_conv_info->direction;

        bus_id             = usb_conv_info->bus_id;
        device_address     = usb_conv_info->device_address;

        key[0].length = 1;
        key[0].key = &interface_id;
        key[1].length = 1;
        key[1].key = &bus_id;
        key[2].length = 1;
        key[2].key = &device_address;
        key[3].length = 1;
        key[3].key = &side_id;
        key[4].length = 1;
        key[4].key = &frame_number;
        key[5].length = 0;
        key[5].key = NULL;
    } else { /* tcp */
        if (pinfo->destport == ADB_TCP_PORT)
            direction = P2P_DIR_SENT;
        else
            direction = P2P_DIR_RECV;

        key[0].length = 1;
        key[0].key = &interface_id;
        key[1].length = 1;
        key[2].length = 1;
        if (direction == P2P_DIR_SENT) {
            key[1].key = &pinfo->srcport;
            key[2].key = &pinfo->destport;
        } else {
            key[1].key = &pinfo->destport;
            key[2].key = &pinfo->srcport;
        }
        key[3].length = 1;
        key[3].key = &side_id;
        key[4].length = 1;
        key[4].key = &frame_number;
        key[5].length = 0;
        key[5].key = NULL;
    }

    if (direction == P2P_DIR_SENT)
        if (cmd == A_CLSE)
            side_id = arg1; /* OUT: local id */
        else
            side_id = arg0; /* OUT: local id */
    else
        side_id = arg1; /* IN: remote id */

    if (cmd == A_OPEN) {
        service_data = wmem_new(wmem_file_scope(), service_data_t);

        service_data->start_in_frame = pinfo->fd->num;
        service_data->close_local_in_frame = max_in_frame;
        service_data->close_remote_in_frame = max_in_frame;

        service_data->local_id = arg0;
        service_data->remote_id = arg1;

        service_data->service = "unknown";

        wmem_tree_insert32_array(service_info, key, service_data);
    }

    command_data = wmem_new(wmem_file_scope(), command_data_t);

    command_data->command = cmd;
    command_data->arg0 = arg0;
    command_data->arg1 = arg1;

    command_data->command_in_frame = pinfo->fd->num;
    command_data->response_in_frame = max_in_frame;

    command_data->crc32 = crc32;
    command_data->data_length = data_length;
    if (data_length == 0)
        command_data->completed_in_frame = pinfo->fd->num;
    else
        command_data->completed_in_frame = max_in_frame;
    command_data->reassemble_data_length = 0;
    command_data->reassemble_data = (guint8 *) wmem_alloc(wmem_file_scope(), command_data->data_length);

    key[3].length = 1;
    key[3].key = &frame_number;
    key[4].length = 0;
    key[4].key = NULL;
    wmem_tree_insert32_array(command_info, key, command_data);

    if (direction == P2P_DIR_SENT)
        if (command_data->command == A_CLSE)
            side_id = command_data->arg1; /* OUT: local id */
        else
            side_id = command_data->arg0; /* OUT: local id */
    else
        side_id = command_data->arg1; /* IN: remote id */

    key[3].length = 1;
    key[3].key = &side_id;
    key[4].length = 0;
    key[4].key = NULL;

    wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(service_info, key);
    if (wmem_tree) {
        service_data = (service_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number);
    }

    if (cmd == A_OKAY) {
        if (!service_data) {
            if (direction == P2P_DIR_SENT)
                side_id = command_data->arg0; /* OUT: local id */
            else
                side_id = command_data->arg1; /* IN: remote id */

            wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(service_info, key);
            if (wmem_tree) {
                service_data = (service_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number);
            }
        }

        if  (service_data && service_data->remote_id == 0 && direction == P2P_DIR_RECV) {
            if (direction == P2P_DIR_SENT) {
                service_data->remote_id = arg1;
            } else {
                service_data->remote_id = arg0;
            }

            side_id = service_data->remote_id;

            key[4].length = 1;
            key[4].key = &frame_number;
            key[5].length = 0;
            key[5].key = NULL;

            wmem_tree_insert32_array(service_info, key, service_data);
        }
    } else if (cmd == A_CLSE) {
        if (service_data) {
            if (direction == P2P_DIR_RECV && service_data->local_id == arg1)
                service_data->close_local_in_frame = pinfo->fd->num;
            else if (direction == P2P_DIR_SENT  && service_data->remote_id == arg1)
                service_data->close_remote_in_frame = pinfo->fd->num;
        }
    }

    DISSECTOR_ASSERT(returned_service_data && returned_command_data);
    *returned_service_data = service_data;
    *returned_command_data = command_data;
}
Example #8
0
gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean keep_persistent_data) {
    gcp_msg_t* m;
    guint32 framenum = (guint32)pinfo->fd->num;
    guint32 offset = (guint32)o;
    address* src = &(pinfo->src);
    address* dst = &(pinfo->dst);
    address* lo_addr;
    address* hi_addr;

    if (keep_persistent_data) {
        wmem_tree_key_t key[3];

        key[0].length = 1;
        key[0].key = &(framenum);
        key[1].length = 1;
        key[1].key = &offset;
        key[2].length = 0;
        key[2].key =NULL;

        if (( m = (gcp_msg_t *)wmem_tree_lookup32_array(msgs,key) )) {
            m->committed = TRUE;
            return m;
        } else {
            m = wmem_new(wmem_file_scope(), gcp_msg_t);
            m->framenum = framenum;
            m->time = pinfo->fd->abs_ts;
            m->trxs = NULL;
            m->committed = FALSE;

            wmem_tree_insert32_array(msgs,key,m);
        }
    } else {
        m = wmem_new0(wmem_packet_scope(), gcp_msg_t);
        m->framenum = framenum;
        m->trxs = NULL;
        m->committed = FALSE;
    }

    if (CMP_ADDRESS(src, dst) < 0)  {
        lo_addr = src;
        hi_addr = dst;
    } else {
        lo_addr = dst;
        hi_addr = src;
    }

    switch(lo_addr->type) {
        case AT_NONE:
            m->lo_addr = 0;
            m->hi_addr = 0;
            break;
        case AT_IPv4:
            memcpy((guint8*)&(m->hi_addr),hi_addr->data,4);
            memcpy((guint8*)&(m->lo_addr),lo_addr->data,4);
            break;
        case AT_SS7PC:
            m->hi_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)hi_addr->data);
            m->lo_addr = mtp3_pc_hash((const mtp3_addr_pc_t *)lo_addr->data);
            break;
        default:
            /* XXX: heuristic and error prone */
            m->hi_addr = g_str_hash(ep_address_to_str(hi_addr));
            m->lo_addr = g_str_hash(ep_address_to_str(lo_addr));
        break;
    }

    return m;
}
Example #9
0
static void
wmem_test_tree(void)
{
    wmem_allocator_t   *allocator, *extra_allocator;
    wmem_tree_t        *tree;
    guint32             i;
    int                 seen_values = 0;
    int                 j;
    gchar              *str_key;
#define WMEM_TREE_MAX_KEY_COUNT 8
#define WMEM_TREE_MAX_KEY_LEN   4
    int                 key_count;
    wmem_tree_key_t     keys[WMEM_TREE_MAX_KEY_COUNT];

    allocator       = wmem_allocator_new(WMEM_ALLOCATOR_STRICT);
    extra_allocator = wmem_allocator_new(WMEM_ALLOCATOR_STRICT);

    tree = wmem_tree_new(allocator);
    g_assert(tree);
    g_assert(wmem_tree_is_empty(tree));

    /* test basic 32-bit key operations */
    for (i=0; i<CONTAINER_ITERS; i++) {
        g_assert(wmem_tree_lookup32(tree, i) == NULL);
        if (i > 0) {
            g_assert(wmem_tree_lookup32_le(tree, i) == GINT_TO_POINTER(i-1));
        }
        wmem_tree_insert32(tree, i, GINT_TO_POINTER(i));
        g_assert(wmem_tree_lookup32(tree, i) == GINT_TO_POINTER(i));
        g_assert(!wmem_tree_is_empty(tree));
    }
    wmem_free_all(allocator);

    tree = wmem_tree_new(allocator);
    for (i=0; i<CONTAINER_ITERS; i++) {
        guint32 rand_int = g_test_rand_int();
        wmem_tree_insert32(tree, rand_int, GINT_TO_POINTER(i));
        g_assert(wmem_tree_lookup32(tree, rand_int) == GINT_TO_POINTER(i));
    }
    wmem_free_all(allocator);

    /* test auto-reset functionality */
    tree = wmem_tree_new_autoreset(allocator, extra_allocator);
    for (i=0; i<CONTAINER_ITERS; i++) {
        g_assert(wmem_tree_lookup32(tree, i) == NULL);
        wmem_tree_insert32(tree, i, GINT_TO_POINTER(i));
        g_assert(wmem_tree_lookup32(tree, i) == GINT_TO_POINTER(i));
    }
    wmem_free_all(extra_allocator);
    for (i=0; i<CONTAINER_ITERS; i++) {
        g_assert(wmem_tree_lookup32(tree, i) == NULL);
        g_assert(wmem_tree_lookup32_le(tree, i) == NULL);
    }
    wmem_free_all(allocator);

    /* test array key functionality */
    tree = wmem_tree_new(allocator);
    key_count = g_random_int_range(1, WMEM_TREE_MAX_KEY_COUNT);
    for (j=0; j<key_count; j++) {
        keys[j].length = g_random_int_range(1, WMEM_TREE_MAX_KEY_LEN);
    }
    keys[key_count].length = 0;
    for (i=0; i<CONTAINER_ITERS; i++) {
        for (j=0; j<key_count; j++) {
            keys[j].key    = (guint32*)wmem_test_rand_string(allocator,
                    (keys[j].length*4), (keys[j].length*4)+1);
        }
        wmem_tree_insert32_array(tree, keys, GINT_TO_POINTER(i));
        g_assert(wmem_tree_lookup32_array(tree, keys) == GINT_TO_POINTER(i));
    }
    wmem_free_all(allocator);

    tree = wmem_tree_new(allocator);
    keys[0].length = 1;
    keys[0].key    = wmem_new(allocator, guint32);
    *(keys[0].key) = 0;
    keys[1].length = 0;
    for (i=0; i<CONTAINER_ITERS; i++) {
        wmem_tree_insert32_array(tree, keys, GINT_TO_POINTER(i));
        *(keys[0].key) += 4;
    }
    *(keys[0].key) = 0;
    for (i=0; i<CONTAINER_ITERS; i++) {
        g_assert(wmem_tree_lookup32_array(tree, keys) == GINT_TO_POINTER(i));
        for (j=0; j<3; j++) {
            (*(keys[0].key)) += 1;
            g_assert(wmem_tree_lookup32_array_le(tree, keys) ==
                    GINT_TO_POINTER(i));
        }
        *(keys[0].key) += 1;
    }
    wmem_free_all(allocator);

    /* test string key functionality */
    tree = wmem_tree_new(allocator);
    for (i=0; i<CONTAINER_ITERS; i++) {
        str_key = wmem_test_rand_string(allocator, 1, 64);
        wmem_tree_insert_string(tree, str_key, GINT_TO_POINTER(i), 0);
        g_assert(wmem_tree_lookup_string(tree, str_key, 0) ==
                GINT_TO_POINTER(i));
    }
    wmem_free_all(allocator);

    tree = wmem_tree_new(allocator);
    for (i=0; i<CONTAINER_ITERS; i++) {
        str_key = wmem_test_rand_string(allocator, 1, 64);
        wmem_tree_insert_string(tree, str_key, GINT_TO_POINTER(i),
                WMEM_TREE_STRING_NOCASE);
        g_assert(wmem_tree_lookup_string(tree, str_key,
                    WMEM_TREE_STRING_NOCASE) == GINT_TO_POINTER(i));
    }
    wmem_free_all(allocator);

    /* test for-each functionality */
    tree = wmem_tree_new(allocator);
    expected_user_data = GINT_TO_POINTER(g_test_rand_int());
    for (i=0; i<CONTAINER_ITERS; i++) {
        gint tmp;
        do {
            tmp = g_test_rand_int();
        } while (wmem_tree_lookup32(tree, tmp));
        value_seen[i] = FALSE;
        wmem_tree_insert32(tree, tmp, GINT_TO_POINTER(i));
    }

    cb_called_count    = 0;
    cb_continue_count  = CONTAINER_ITERS;
    wmem_tree_foreach(tree, wmem_test_foreach_cb, expected_user_data);
    g_assert(cb_called_count   == CONTAINER_ITERS);
    g_assert(cb_continue_count == 0);

    for (i=0; i<CONTAINER_ITERS; i++) {
        g_assert(value_seen[i]);
        value_seen[i] = FALSE;
    }

    cb_called_count    = 0;
    cb_continue_count  = 10;
    wmem_tree_foreach(tree, wmem_test_foreach_cb, expected_user_data);
    g_assert(cb_called_count   == 10);
    g_assert(cb_continue_count == 0);

    for (i=0; i<CONTAINER_ITERS; i++) {
        if (value_seen[i]) {
            seen_values++;
        }
    }
    g_assert(seen_values == 10);

    wmem_destroy_allocator(extra_allocator);
    wmem_destroy_allocator(allocator);
}
Example #10
0
gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent) {
    gcp_ctx_t* context = NULL;
    gcp_ctx_t** context_p = NULL;

    if ( !m || !t ) return NULL;

    if (persistent) {

        wmem_tree_key_t ctx_key[4];
        wmem_tree_key_t trx_key[4];

        ctx_key[0].length = 1;
        ctx_key[0].key = &(m->hi_addr);
        ctx_key[1].length = 1;
        ctx_key[1].key = &(m->lo_addr);
        ctx_key[2].length = 1;
        ctx_key[2].key = &(c_id);
        ctx_key[3].length = 0;
        ctx_key[3].key = NULL;

        trx_key[0].length = 1;
        trx_key[0].key = &(m->hi_addr);
        trx_key[1].length = 1;
        trx_key[1].key = &(m->lo_addr);
        trx_key[2].length = 1;
        trx_key[2].key = &(t->id);
        trx_key[3].length = 0;
        trx_key[3].key = NULL;

        if (m->committed) {
            if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
                return context;
            } if ((context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key))) {
                context = *context_p;

                do {
                    if (context->initial->framenum <= m->framenum) {
                        return context;
                    }
                } while(( context = context->prev ));

                DISSECTOR_ASSERT(! "a context should exist");
            }
        } else {
            if (c_id == CHOOSE_CONTEXT) {
                if (! ( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key))) {
                    context = wmem_new(wmem_file_scope(), gcp_ctx_t);
                    context->initial = m;
                    context->cmds = NULL;
                    context->id = c_id;
                    context->terms.last = &(context->terms);
                    context->terms.next = NULL;
                    context->terms.term = NULL;

                    wmem_tree_insert32_array(ctxs_by_trx,trx_key,context);
                }
            } else {
                if (( context = (gcp_ctx_t *)wmem_tree_lookup32_array(ctxs_by_trx,trx_key) )) {
                    if (( context_p = (gcp_ctx_t **)wmem_tree_lookup32_array(ctxs,ctx_key) )) {
                        if (context != *context_p) {
                            if(context->id != CHOOSE_CONTEXT) {
                                context = wmem_new(wmem_file_scope(), gcp_ctx_t);
                            }
                            context->initial = m;
                            context->id = c_id;
                            context->cmds = NULL;
                            context->terms.last = &(context->terms);
                            context->terms.next = NULL;
                            context->terms.term = NULL;

                            context->prev = *context_p;
                            *context_p = context;
                        }
                    } else {
                        context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
                        *context_p = context;
                        context->initial = m;
                        context->id = c_id;
                        wmem_tree_insert32_array(ctxs,ctx_key,context_p);
                    }
                } else if (! ( context_p = (gcp_ctx_t**)wmem_tree_lookup32_array(ctxs,ctx_key) )) {
                    context = wmem_new(wmem_file_scope(), gcp_ctx_t);
                    context->initial = m;
                    context->id = c_id;
                    context->cmds = NULL;
                    context->terms.last = &(context->terms);
                    context->terms.next = NULL;
                    context->terms.term = NULL;

                    context_p = wmem_new(wmem_file_scope(), gcp_ctx_t*);
                    *context_p = context;
                    wmem_tree_insert32_array(ctxs,ctx_key,context_p);
                } else {
                    context = *context_p;
                }
            }
Example #11
0
gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean keep_persistent_data) {
    gcp_trx_t* t = NULL;
    gcp_trx_msg_t* trxmsg;

    if ( !m ) return NULL;

    if (keep_persistent_data) {
        if (m->committed) {

            for ( trxmsg = m->trxs; trxmsg; trxmsg = trxmsg->next) {
                if (trxmsg->trx && trxmsg->trx->id == t_id) {
                    return trxmsg->trx;
                }
            }
            DISSECTOR_ASSERT_NOT_REACHED();
        } else {
            wmem_tree_key_t key[4];

            key[0].length = 1;
            key[0].key = &(m->hi_addr);
            key[1].length = 1;
            key[1].key = &(m->lo_addr);
            key[2].length = 1;
            key[2].key = &(t_id);
            key[3].length = 0;
            key[3].key = NULL;

            trxmsg = wmem_new(wmem_file_scope(), gcp_trx_msg_t);
            t = (gcp_trx_t *)wmem_tree_lookup32_array(trxs,key);

            if (!t) {
                t = wmem_new(wmem_file_scope(), gcp_trx_t);
                t->initial = m;
                t->id = t_id;
                t->type = type;
                t->pendings = 0;
                t->error = 0;
                t->cmds = NULL;

                wmem_tree_insert32_array(trxs,key,t);
            }

            /* XXX: request, reply and ack + point to frames where they are */
            switch ( type ) {
                case GCP_TRX_PENDING:
                    t->pendings++;
                    break;
                default:
                    break;
            }

        }
    } else {
        t = wmem_new(wmem_packet_scope(), gcp_trx_t);
        trxmsg = wmem_new(wmem_packet_scope(), gcp_trx_msg_t);
        t->initial = NULL;
        t->id = t_id;
        t->type = type;
        t->pendings = 0;
        t->error = 0;
        t->cmds = NULL;
    }

    DISSECTOR_ASSERT(trxmsg);

    trxmsg->trx = t;
    trxmsg->next = NULL;
    trxmsg->last = trxmsg;

    if (m->trxs) {
        m->trxs->last = m->trxs->last->next = trxmsg;
    } else {
        m->trxs = trxmsg;
    }

    return t;
}
Example #12
0
static gint
dissect_acr122(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
    proto_item      *main_item;
    proto_tree      *main_tree;
    proto_item      *p1_item;
    proto_tree      *p1_tree;
    proto_item      *p2_item;
    proto_tree      *p2_tree;
    proto_item      *sub_item;
    proto_item      *sub_tree;
    proto_item      *sw2_item;
    proto_item      *sw2_tree;
    gint             offset = 0;
    guint32          value;
    tvbuff_t        *next_tvb;
    guint8           acr_class;
    guint8           ins;
    guint8           p1;
    guint8           p2;
    guint8           length;
    guint8           command = CMD_UNKNOWN;
    command_data_t  *command_data;
    usb_conv_info_t *usb_conv_info;
    wmem_tree_key_t  key[5];
    guint32          bus_id;
    guint32          device_address;
    guint32          endpoint;
    guint32          k_bus_id;
    guint32          k_device_address;
    guint32          k_endpoint;
    guint32          k_frame_number;

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

    main_item = proto_tree_add_item(tree, proto_acr122, tvb, offset, -1, ENC_NA);
    main_tree = proto_item_add_subtree(main_item, ett_acr122);

    if (!data) return offset;
    usb_conv_info = (usb_conv_info_t *) data;

    bus_id = usb_conv_info->bus_id;
    device_address = usb_conv_info->device_address;
    endpoint = usb_conv_info->endpoint;

    k_bus_id  = bus_id;
    k_device_address  = device_address;
    k_endpoint        = endpoint;
    k_frame_number    = pinfo->fd->num;

    key[0].length = 1;
    key[0].key = &k_bus_id;
    key[1].length = 1;
    key[1].key = &k_device_address;
    key[2].length = 1;
    key[2].key = &k_endpoint;
    key[3].length = 1;
    key[3].key = &k_frame_number;
    key[4].length = 0;
    key[4].key = NULL;


    if (pinfo->p2p_dir == P2P_DIR_SENT) { /* Request */
        acr_class = tvb_get_guint8(tvb, offset);
        ins = tvb_get_guint8(tvb, offset + 1);
        p1 = tvb_get_guint8(tvb, offset + 2);
        p2 = tvb_get_guint8(tvb, offset + 3);
        length = tvb_get_guint8(tvb, offset + 4);

        /* Recognize command by simple heuristic */
        if (acr_class == 0xFF) {
            if (ins == 0xCA && p1 == 0x00 && p2 == 0x00 && length == 0)
                command = CMD_GET_DATA_UID;
            if (ins == 0xCA && p1 == 0x01 && p2 == 0x00 && length == 0)
                command = CMD_GET_DATA_ATS;
            else if (ins == 0x82 && length == 6)
                command = CMD_LOAD_AUTHENTICATION_KEYS;
            else if (ins == 0x88 && p1 == 0x00)
                command = CMD_AUTHENTICATION_OBSOLETE;
            else if (ins == 0x86 && p1 == 0x00 && p2 == 0x00 && length == 5)
                command = CMD_AUTHENTICATION;
            else if (ins == 0xB0 && p1 == 0x00)
                command = CMD_READ_BINARY_BLOCKS;
            else if (ins == 0xD6 && p1 == 0x00)
                command = CMD_UPDATE_BINARY_BLOCKS;
            else if (ins == 0xD7 && p1 == 0x00 && length == 5)
                command = CMD_VALUE_BLOCK_OPERATION;
            else if (ins == 0xB1 && p1 == 0x00 && length == 4)
                command = CMD_READ_VALUE_BLOCK;
            else if (ins == 0xD7 && p1 == 0x00 && length == 2)
                command = CMD_RESTORE_VALUE_BLOCK;
            else if (ins == 0x00 && p1 == 0x00 && p2 == 0x00)
                command = CMD_DIRECT_TRANSMIT;
            else if (ins == 0x00 && p1 == 0x40 && length == 4)
                command = CMD_BI_COLOR_AND_BUZZER_LED_CONTROL;
            else if (ins == 0x00 && p1 == 0x48 && p2 == 0x00)
                command = CMD_GET_FIRMWARE_VERSION;
            else if (ins == 0x00 && p1 == 0x50 && p2 == 0x00)
                command = CMD_GET_PICC_OPERATING_PARAMETER;
            else if (ins == 0x00 && p1 == 0x51 && length == 0)
                command = CMD_SET_PICC_OPERATING_PARAMETER;
            else if (ins == 0x00 && p1 == 0x41 && length == 0)
                command = CMD_SET_TIMEOUT_PARAMETER;
            else if (ins == 0x00 && p1 == 0x52 && length == 0)
                command = CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION;
        }

        sub_item = proto_tree_add_uint(main_tree, hf_command, tvb, offset, 4 + length, command);
        PROTO_ITEM_SET_GENERATED(sub_item);
        if (command == CMD_UNKNOWN)
            proto_tree_add_expert(sub_item, pinfo, &ei_unknown_command_or_invalid_parameters, tvb, offset, 4 + length);

        col_add_fstr(pinfo->cinfo, COL_INFO, "Command: %s", val_to_str_const(command, command_vals, "Unknown"));

        proto_tree_add_item(main_tree, hf_class, tvb, offset, 1, ENC_NA);
        offset += 1;

        proto_tree_add_item(main_tree, hf_ins, tvb, offset, 1, ENC_NA);
        offset += 1;

        p1_item = proto_tree_add_item(main_tree, hf_p1, tvb, offset, 1, ENC_NA);
        offset += 1;

        p2_item = proto_tree_add_item(main_tree, hf_p2, tvb, offset, 1, ENC_NA);
        offset += 1;

        proto_tree_add_item(main_tree, hf_length, tvb, offset, 1, ENC_NA);
        offset += 1;

        switch (command) {
        case CMD_DIRECT_TRANSMIT:
            if (length > 0) {
                next_tvb = tvb_new_subset(tvb, offset, length, length);
                call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info);
                offset += length;
            }
            break;
        case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_led_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_led_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_led_green_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_led_red_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_led_initial_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_led_initial_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_led_final_green_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_led_final_red_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN);

            proto_tree_add_item(main_tree, hf_led_t1_duration, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_led_t2_duration, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_led_number_of_repetition, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_led_link_to_buzzer, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case  CMD_GET_DATA_UID:
        case  CMD_GET_DATA_ATS:
            /* Nothing to decode */
            break;
        case CMD_LOAD_AUTHENTICATION_KEYS:
            p1_tree = proto_item_add_subtree(p1_item, ett_p1_item);
            proto_tree_add_item(p1_tree, hf_key_structure, tvb, offset - 3, 1, ENC_BIG_ENDIAN);

            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_key_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);

            proto_tree_add_item(main_tree, hf_key, tvb, offset, 6, ENC_NA);
            offset += 6;
            break;
        case CMD_AUTHENTICATION_OBSOLETE:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);

            proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case CMD_AUTHENTICATION:
            proto_tree_add_item(main_tree, hf_version, tvb, offset, 2, ENC_BIG_ENDIAN);
            offset += 2;

            proto_tree_add_item(main_tree, hf_block_number, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case CMD_READ_BINARY_BLOCKS:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            break;
        case CMD_UPDATE_BINARY_BLOCKS:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);

            proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA);
            offset += length;
            break;
        case CMD_VALUE_BLOCK_OPERATION:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);

            proto_tree_add_item(main_tree, hf_vb_op, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN);
            offset += 4;
            break;
        case CMD_READ_VALUE_BLOCK:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);

            break;
        case CMD_RESTORE_VALUE_BLOCK:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_source_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN);

            proto_tree_add_item(main_tree, hf_static_byte, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;

            proto_tree_add_item(main_tree, hf_target_block_number, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            break;
        case CMD_SET_PICC_OPERATING_PARAMETER:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_picc_operating_auto_picc_polling, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_picc_operating_auto_ats_generation, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_picc_operating_polling_interval, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_picc_operating_felica_424k, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_picc_operating_felica_212k, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_picc_operating_topaz, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            break;
        case CMD_SET_TIMEOUT_PARAMETER:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_timeout, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            break;
        case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION:
            p2_tree = proto_item_add_subtree(p2_item, ett_p2_item);
            proto_tree_add_item(p2_tree, hf_poll_buzzer_status, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            break;
        case CMD_GET_PICC_OPERATING_PARAMETER:
            /* No parameters */
            break;
        }

        if (!pinfo->fd->flags.visited) {
            command_data = wmem_new(wmem_file_scope(), command_data_t);
            command_data->bus_id = bus_id;
            command_data->device_address = device_address;
            command_data->endpoint = endpoint;

            command_data->command = command;
            command_data->command_frame_number = pinfo->fd->num;
            command_data->response_frame_number = 0;

            wmem_tree_insert32_array(command_info, key, command_data);
        }

    } else { /* Response */
        guint32       command_frame_number = 0;
        gboolean      use_status_word = FALSE;
        wmem_tree_t  *wmem_tree;

        key[3].length = 0;
        key[3].key = NULL;

        wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key);
        if (wmem_tree) {
            command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->fd->num);

            if (command_data && (command_data->response_frame_number == 0 ||
                    command_data->response_frame_number == pinfo->fd->num)) {

                command = command_data->command;
                command_frame_number = command_data->command_frame_number;
                if (!pinfo->fd->flags.visited && command_data->response_frame_number == 0) {
                    command_data->response_frame_number = pinfo->fd->num;
                }
            }
        }

        sub_item = proto_tree_add_uint(main_tree, hf_response, tvb, offset, tvb_length_remaining(tvb, offset), command);
        PROTO_ITEM_SET_GENERATED(sub_item);

        col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s", val_to_str_const(command, command_vals, "Unknown"));

        if (command != CMD_UNKNOWN) {
            sub_item = proto_tree_add_uint(main_tree, hf_response_for, tvb, offset, tvb_length_remaining(tvb, offset), command_frame_number);
            PROTO_ITEM_SET_GENERATED(sub_item);
        }

        switch (command) {
        case CMD_GET_FIRMWARE_VERSION:
            proto_tree_add_item(main_tree, hf_firmware_version, tvb, offset, -1, ENC_NA | ENC_ASCII);
            offset += tvb_length_remaining(tvb, offset);
            break;

        case CMD_DIRECT_TRANSMIT:
            use_status_word = TRUE;

            if (tvb_length_remaining(tvb, offset) > 2) {
                next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset) - 2, tvb_length_remaining(tvb, offset) - 2);
                call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info);
                offset += tvb_length_remaining(tvb, offset) - 2;
            }
            break;


        case CMD_READ_BINARY_BLOCKS:
            use_status_word = TRUE;
            proto_tree_add_item(main_tree, hf_data, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA);
            offset += tvb_length_remaining(tvb, offset) - 2;
            break;

        case CMD_READ_VALUE_BLOCK:
            use_status_word = TRUE;
            proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN);
            break;

        case CMD_GET_DATA_UID:
            use_status_word = TRUE;
            proto_tree_add_item(main_tree, hf_uid, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA);
            offset += tvb_length_remaining(tvb, offset) - 2;
            break;

        case CMD_GET_DATA_ATS:
            use_status_word = TRUE;
            proto_tree_add_item(main_tree, hf_ats, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA);
            offset += tvb_length_remaining(tvb, offset) - 2;
            break;

        case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL:
        case CMD_LOAD_AUTHENTICATION_KEYS:
        case CMD_AUTHENTICATION:
        case CMD_AUTHENTICATION_OBSOLETE:
        case CMD_UPDATE_BINARY_BLOCKS:
        case CMD_VALUE_BLOCK_OPERATION:
        case CMD_RESTORE_VALUE_BLOCK:
        case CMD_SET_TIMEOUT_PARAMETER:
        case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION:
        case CMD_SET_PICC_OPERATING_PARAMETER:
        case CMD_GET_PICC_OPERATING_PARAMETER:
        default:
            use_status_word = TRUE;
            break;
        }

        if (use_status_word) {
            value = tvb_get_ntohs(tvb, offset);
            col_append_fstr(pinfo->cinfo, COL_INFO, " - %s%s",  (((value & 0xFF00) != 0x9000) && (value & 0xFF00) != 0x6100) ? "Error: " : "", rval_to_str(value, status_word_rvals, "Unknown error"));

            if ((value & 0xFF00) == 0x6100)
                col_append_fstr(pinfo->cinfo, COL_INFO, " - Length %u", value & 0x00FF);

            sub_item = proto_tree_add_item(main_tree, hf_status_word, tvb, offset, 2, ENC_BIG_ENDIAN);
            sub_tree = proto_item_add_subtree(sub_item, ett_status_word);
            proto_tree_add_item(sub_tree, hf_status_word_sw1, tvb, offset, 1, ENC_BIG_ENDIAN);
            offset += 1;
            sw2_item = proto_tree_add_item(sub_tree, hf_status_word_sw2, tvb, offset, 1, ENC_BIG_ENDIAN);

            if (command == CMD_BI_COLOR_AND_BUZZER_LED_CONTROL) {
                sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2);

                col_append_fstr(pinfo->cinfo, COL_INFO, " - Red LED: %s, Green LED: %s", (value & 0x02) ? "On" : "Off", (value & 0x01) ? "On" : "Off");

                proto_tree_add_item(sw2_tree, hf_status_word_led_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_status_word_led_green, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_status_word_led_red, tvb, offset, 1, ENC_BIG_ENDIAN);
            } else if (command == CMD_SET_PICC_OPERATING_PARAMETER || command == CMD_GET_PICC_OPERATING_PARAMETER) {
                sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2);
                proto_tree_add_item(sw2_tree, hf_picc_operating_auto_picc_polling, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_picc_operating_auto_ats_generation, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_picc_operating_polling_interval, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_picc_operating_felica_424k, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_picc_operating_felica_212k, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_picc_operating_topaz, tvb, offset, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
                proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
            }
            offset += 1;
        }
    }

    return offset;
}
static gint
dissect_adb_service(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
    proto_item          *main_item;
    proto_tree          *main_tree;
    proto_item          *sub_item;
    proto_tree          *sub_tree;
    gint                 offset = 0;
    adb_service_data_t  *adb_service_data = (adb_service_data_t *) data;
    const guint8        *service;
    wmem_tree_key_t      key[5];
    wmem_tree_t         *subtree;
    guint32              i_key;

    main_item = proto_tree_add_item(tree, proto_adb_service, tvb, offset, -1, ENC_NA);
    main_tree = proto_item_add_subtree(main_item, ett_adb_service);

    DISSECTOR_ASSERT(adb_service_data);

    service = adb_service_data->service;

    sub_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service);
    PROTO_ITEM_SET_GENERATED(sub_item);

        if (g_strcmp0(service, "host:version") == 0) {
            guint32               version;
            guint32               data_length;
            continuation_data_t  *continuation_data;

            DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small");
            for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) {
                key[i_key].length = 1;
                key[i_key].key = &adb_service_data->session_key[i_key];
            }
            key[i_key].length = 0;
            key[i_key].key = NULL;

            subtree = (wmem_tree_t *) wmem_tree_lookup32_array(continuation_infos, key);
            continuation_data = (subtree) ? (continuation_data_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
            if (continuation_data && continuation_data->completed_in_frame < pinfo->num)
                continuation_data = NULL;

            if (!continuation_data || (continuation_data && continuation_data->length_in_frame == pinfo->num))
                offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length);

            if (!pinfo->fd->flags.visited && !continuation_data && tvb_reported_length_remaining(tvb, offset) < 4) {
                key[i_key].length = 1;
                key[i_key++].key = &pinfo->num;
                key[i_key].length = 0;
                key[i_key].key = NULL;

                continuation_data = wmem_new(wmem_file_scope(), continuation_data_t);
                continuation_data->length_in_frame = pinfo->num;
                continuation_data->completed_in_frame = G_MAXUINT32;
                continuation_data->length = data_length;

                wmem_tree_insert32_array(continuation_infos, key, continuation_data);
                continuation_data = NULL;
            }

            if (tvb_reported_length_remaining(tvb, offset) >= 4 ||
                        (continuation_data && continuation_data->completed_in_frame == pinfo->num)) {
                if (!pinfo->fd->flags.visited && continuation_data) {
                    continuation_data->completed_in_frame = pinfo->num;
                }
                offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_version, ett_version, hf_version, tvb, offset, &version);

                col_append_fstr(pinfo->cinfo, COL_INFO, " Version=%u", version);
            }

        } else if (g_strcmp0(service, "host:devices") == 0 ||
                g_strcmp0(service, "host:devices-l") == 0 ||
                g_strcmp0(service, "host:track-devices") == 0) {
            guint32  data_length;

            offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length);

            sub_item = proto_tree_add_item(main_tree, hf_devices, tvb, offset, -1, ENC_NA | ENC_ASCII);
            if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) {
                expert_add_info(pinfo, sub_item, &ei_incomplete_message);
            }
        } else if (g_strcmp0(service, "host:get-state") == 0 ||
                g_strcmp0(service, "host:get-serialno") == 0 ||
                g_strcmp0(service, "host:get-devpath") == 0 ||
                g_str_has_prefix(service, "connect:") ||
                g_str_has_prefix(service, "disconnect:")) {
            guint32  data_length;

            offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length);

            sub_item = proto_tree_add_item(main_tree, hf_result, tvb, offset, -1, ENC_NA | ENC_ASCII);
            if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) {
                expert_add_info(pinfo, sub_item, &ei_incomplete_message);
            }
        } else if (g_str_has_prefix(service, "framebuffer:")) {
            framebuffer_data_t  *framebuffer_data = NULL;

            DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small");
            for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) {
                key[i_key].length = 1;
                key[i_key].key = &adb_service_data->session_key[i_key];
            }
            key[i_key].length = 0;
            key[i_key].key = NULL;

            subtree = (wmem_tree_t *) wmem_tree_lookup32_array(framebuffer_infos, key);
            framebuffer_data = (subtree) ? (framebuffer_data_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL;
            if (framebuffer_data && framebuffer_data->completed_in_frame < pinfo->num)
                framebuffer_data = NULL;

            if (!pinfo->fd->flags.visited && !framebuffer_data) {
                key[i_key].length = 1;
                key[i_key++].key = &pinfo->num;
                key[i_key].length = 0;
                key[i_key].key = NULL;

                framebuffer_data = wmem_new(wmem_file_scope(), framebuffer_data_t);
                framebuffer_data->data_in      = pinfo->num;
                framebuffer_data->current_size = 0;
                framebuffer_data->completed_in_frame = G_MAXUINT32;
                framebuffer_data->size         = tvb_get_letohl(tvb, offset + 4 * 2);
                framebuffer_data->red_offset   = tvb_get_letohl(tvb, offset + 4 * 5);
                framebuffer_data->red_length   = tvb_get_letohl(tvb, offset + 4 * 6);
                framebuffer_data->green_offset = tvb_get_letohl(tvb, offset + 4 * 7);
                framebuffer_data->green_length = tvb_get_letohl(tvb, offset + 4 * 8);
                framebuffer_data->blue_offset  = tvb_get_letohl(tvb, offset + 4 * 9);
                framebuffer_data->blue_length  = tvb_get_letohl(tvb, offset + 4 * 10);
                framebuffer_data->alpha_offset = tvb_get_letohl(tvb, offset + 4 * 11);
                framebuffer_data->alpha_length = tvb_get_letohl(tvb, offset + 4 * 12);

                wmem_tree_insert32_array(framebuffer_infos, key, framebuffer_data);
            }

            if (framebuffer_data && framebuffer_data->data_in == pinfo->num) {
                proto_tree_add_item(main_tree, hf_framebuffer_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_depth, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_width, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_height, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_red_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_red_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_blue_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_blue_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_green_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_green_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_alpha_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;

                proto_tree_add_item(main_tree, hf_framebuffer_alpha_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                offset += 4;
            }

            if (tvb_reported_length_remaining(tvb, offset) > 0) {
                sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
                sub_tree = proto_item_add_subtree(sub_item, ett_data);

                if (!pinfo->fd->flags.visited && framebuffer_data) {
                    framebuffer_data->current_size += tvb_captured_length_remaining(tvb, offset);
                    if (framebuffer_data->current_size >= framebuffer_data->size)
                        framebuffer_data->completed_in_frame = pinfo->num;
                }

                if (pref_dissect_more_detail_framebuffer) {
                    proto_item  *pixel_item;
                    proto_tree  *pixel_tree;

                    if (framebuffer_data &&
                        framebuffer_data->red_length == 5 &&
                        framebuffer_data->green_length == 6 &&
                        framebuffer_data->blue_length == 5 &&
                        framebuffer_data->red_offset == 11 &&
                        framebuffer_data->green_offset == 5 &&
                        framebuffer_data->blue_offset == 0) {
                        while (tvb_reported_length_remaining(tvb, offset) > 0) {
                            if (tvb_reported_length_remaining(tvb, offset) < 2) {
                                proto_tree_add_item(main_tree, hf_fragment, tvb, offset, -1, ENC_NA);
                                offset += 1;
                            }

                            pixel_item = proto_tree_add_item(sub_tree, hf_framebuffer_pixel, tvb, offset, 2, ENC_NA);
                            pixel_tree = proto_item_add_subtree(pixel_item, ett_pixel);

                            proto_tree_add_item(pixel_tree, hf_framebuffer_blue_5, tvb, offset, 2, ENC_LITTLE_ENDIAN);
                            proto_tree_add_item(pixel_tree, hf_framebuffer_green_6, tvb, offset, 2, ENC_LITTLE_ENDIAN);
                            proto_tree_add_item(pixel_tree, hf_framebuffer_red_5, tvb, offset, 2, ENC_LITTLE_ENDIAN);
                            offset += 2;
                        }
                    } else if (framebuffer_data &&
                            framebuffer_data->red_length == 8 &&
                            framebuffer_data->green_length == 8 &&
                            framebuffer_data->blue_length == 8 &&
                            (framebuffer_data->alpha_length == 0 ||
                            framebuffer_data->alpha_length == 8)) {
                        while (tvb_reported_length_remaining(tvb, offset) > 0) {
                            if (tvb_reported_length_remaining(tvb, offset) < 3 || (tvb_reported_length_remaining(tvb, offset) < 4 && framebuffer_data->alpha_offset > 0)) {
                                proto_tree_add_item(main_tree, hf_fragment, tvb, offset, -1, ENC_NA);
                                offset = tvb_captured_length(tvb);
                                break;
                            }

                            pixel_item = proto_tree_add_item(sub_tree, hf_framebuffer_pixel, tvb, offset, 3, ENC_NA);
                            pixel_tree = proto_item_add_subtree(pixel_item, ett_pixel);

                            proto_tree_add_item(pixel_tree, hf_framebuffer_red, tvb, offset + framebuffer_data->red_offset / 8, 1, ENC_LITTLE_ENDIAN);
                            proto_tree_add_item(pixel_tree, hf_framebuffer_green, tvb, offset + framebuffer_data->green_offset / 8, 1, ENC_LITTLE_ENDIAN);
                            proto_tree_add_item(pixel_tree, hf_framebuffer_blue, tvb, offset + framebuffer_data->blue_offset / 8, 1, ENC_LITTLE_ENDIAN);

                            if (framebuffer_data->alpha_offset > 0) {
                                if (framebuffer_data->alpha_length == 0)
                                    proto_tree_add_item(pixel_tree, hf_framebuffer_unused, tvb, offset + framebuffer_data->alpha_offset / 8, 1, ENC_LITTLE_ENDIAN);
                                else
                                    proto_tree_add_item(pixel_tree, hf_framebuffer_alpha, tvb, offset + framebuffer_data->alpha_offset / 8, 1, ENC_LITTLE_ENDIAN);
                                offset += 1;
                                proto_item_set_len(pixel_item, 4);
                            }
                            offset += 3;
                        }
                    } else {
                        offset = tvb_captured_length(tvb);
                    }
                } else {
                    offset = tvb_captured_length(tvb);
                }
            }
        } else if (g_strcmp0(service, "track-jdwp") == 0) {
            guint32  data_length;

            offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length);

            if (tvb_reported_length_remaining(tvb, offset) > 0) {
                sub_item = proto_tree_add_item(main_tree, hf_pids, tvb, offset, -1, ENC_NA | ENC_ASCII);
                if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) {
                    expert_add_info(pinfo, sub_item, &ei_incomplete_message);
                }
            }
            offset = tvb_captured_length(tvb);
        } else if ((g_strcmp0(service, "shell:export ANDROID_LOG_TAGS=\"\" ; exec logcat -B") == 0) ||
                (g_strcmp0(service, "shell:logcat -B") == 0)) {
            tvbuff_t    *next_tvb;
            tvbuff_t    *new_tvb;
            guint8      *buffer = NULL;
            gint         size = 0;
            gint         i_offset = offset;
            gint         old_offset;
            gint         i_char = 0;
            guint8       c1;
            guint8       c2 = '\0';
            guint16      payload_length;
            guint16      try_header_size;
            gint         logcat_length = 0;
            fragment_t  *fragment;

            DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small");
            for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) {
                key[i_key].length = 1;
                key[i_key].key = &adb_service_data->session_key[i_key];
            }
            key[i_key].length = 0;
            key[i_key].key = NULL;

            subtree = (wmem_tree_t *) wmem_tree_lookup32_array(fragments, key);
            fragment = (subtree) ? (fragment_t *) wmem_tree_lookup32_le(subtree, pinfo->num - 1) : NULL;
            if (fragment) {
                if (!pinfo->fd->flags.visited && fragment->reassembled_in_frame == -1)
                    fragment->reassembled_in_frame = pinfo->num;

                if (fragment->reassembled_in_frame == pinfo->num) {
                    size += fragment->length;
                    i_char += fragment->length;
                }
            }

            size += tvb_reported_length_remaining(tvb, i_offset);
            if (size > 0) {
                buffer = (guint8 *) wmem_alloc(pinfo->pool, size);
                if (fragment && i_char > 0)
                    memcpy(buffer, fragment->data, i_char);

                if (i_char >= 1 && buffer[i_char - 1] == '\r' && tvb_get_guint8(tvb, i_offset) == '\n') {
                    buffer[i_char - 1] = '\n';
                    i_offset += 1;
                }

                c1 = tvb_get_guint8(tvb, i_offset);
                i_offset += 1;
                old_offset = i_offset;

                while (tvb_reported_length_remaining(tvb, i_offset) > 0) {
                    c2 = tvb_get_guint8(tvb, i_offset);

                    if (c1 == '\r' && c2 == '\n') {
                        buffer[i_char] = c2;
                        if (tvb_reported_length_remaining(tvb, i_offset) > 1) {
                            c1 = tvb_get_guint8(tvb, i_offset + 1);
                            i_offset += 2;
                            i_char += 1;
                        } else {
                            i_offset += 1;
                        }

                        continue;
                    }

                    buffer[i_char] = c1;
                    c1 = c2;
                    i_char += 1;
                    i_offset += 1;
                }

                if (tvb_reported_length_remaining(tvb, old_offset) == 0) {
                    buffer[i_char] = c1;
                    i_char += 1;
                } else if (tvb_reported_length_remaining(tvb, old_offset) > 0) {
                    buffer[i_char] = c2;
                    i_char += 1;
                }

                next_tvb = tvb_new_child_real_data(tvb, buffer, i_char, i_char);
                add_new_data_source(pinfo, next_tvb, "Logcat");

                i_offset = 0;
                while (tvb_reported_length_remaining(next_tvb, i_offset) > 0) {
                    if (tvb_reported_length_remaining(next_tvb, i_offset) >= 4) {
                        payload_length = tvb_get_letohs(next_tvb, i_offset);
                        try_header_size = tvb_get_letohs(next_tvb, i_offset + 2);

                        if (try_header_size != 24)
                            logcat_length = payload_length + 20;
                        else
                            logcat_length = payload_length + 24;
                    }

                    if (tvb_reported_length_remaining(next_tvb, i_offset) >= 4 && tvb_reported_length_remaining(next_tvb, i_offset) >= logcat_length) {
                        new_tvb = tvb_new_subset_length(next_tvb, i_offset, logcat_length);

                        call_dissector(logcat_handle, new_tvb, pinfo, main_tree);
                        i_offset += logcat_length;
                    } else {

                        if (!pinfo->fd->flags.visited) {
                            DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 2 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small");
                            for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) {
                                key[i_key].length = 1;
                                key[i_key].key = &adb_service_data->session_key[i_key];
                            }
                            key[i_key].length = 1;
                            key[i_key++].key = &pinfo->num;
                            key[i_key].length = 0;
                            key[i_key].key = NULL;

                            fragment = wmem_new(wmem_file_scope(), fragment_t);

                            fragment->length = tvb_captured_length_remaining(next_tvb, i_offset);
                            fragment->data = (guint8 *) wmem_alloc(wmem_file_scope(), fragment->length);
                            tvb_memcpy(next_tvb, fragment->data, i_offset, fragment->length);
                            fragment->reassembled_in_frame = -1;

                            wmem_tree_insert32_array(fragments, key, fragment);
                        }

                        proto_tree_add_item(main_tree, hf_fragment, next_tvb, i_offset, -1, ENC_NA);
                        i_offset = tvb_captured_length(next_tvb);
                    }
                }
            }

            offset = tvb_captured_length(tvb);
        } else if (g_str_has_prefix(service, "shell:")) {
            if (adb_service_data->direction == P2P_DIR_SENT) {
                proto_tree_add_item(main_tree, hf_stdin, tvb, offset, -1, ENC_NA | ENC_ASCII);
                col_append_fstr(pinfo->cinfo, COL_INFO, " Stdin=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset)));

            } else {
                proto_tree_add_item(main_tree, hf_stdout, tvb, offset, -1, ENC_NA | ENC_ASCII);
                col_append_fstr(pinfo->cinfo, COL_INFO, " Stdout=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset)));
            }
            offset = tvb_captured_length(tvb);
        } else if (g_str_has_prefix(service, "jdwp:")) {
/* TODO */
            proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
            offset = tvb_captured_length(tvb);
        } else if (g_str_has_prefix(service, "sync:")) {
/* TODO */
            proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
            offset = tvb_captured_length(tvb);
        } else if (g_strcmp0(service, "host:list-forward") == 0 ||
                g_str_has_prefix(service, "root:") ||
                g_str_has_prefix(service, "remount:")  ||
                g_str_has_prefix(service, "tcpip:")  ||
                g_str_has_prefix(service, "usb:")) {
            if (tvb_reported_length_remaining(tvb, offset)) {
                proto_tree_add_item(main_tree, hf_result, tvb, offset, -1, ENC_NA | ENC_ASCII);
                col_append_fstr(pinfo->cinfo, COL_INFO, " Result=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset)));

                offset = tvb_captured_length(tvb);
            }
        } else {
            proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
            offset = tvb_captured_length(tvb);
        }

    return offset;
}
Example #14
0
static gint
dissect_usb_dfu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
    proto_item       *main_item;
    proto_tree       *main_tree;
    proto_item       *command_item;
    proto_item       *sub_item;
    proto_tree       *command_tree;
    gint              offset = 0;
    gint              p2p_dir_save;
    guint8            command;
    gint16            command_response = -1;
    command_data_t   *command_data = NULL;
    wmem_tree_t      *wmem_tree;
    wmem_tree_key_t   key[5];
    guint32           bus_id;
    guint32           device_address;
    guint32           k_bus_id;
    guint32           k_device_address;
    guint32           k_frame_number;
    gint32            block_number = -1;
    usb_conv_info_t  *usb_conv_info = (usb_conv_info_t *)data;

    if (!usb_conv_info) return offset;

    bus_id         = usb_conv_info->bus_id;
    device_address = usb_conv_info->device_address;

    k_bus_id          = bus_id;
    k_device_address  = device_address;
    k_frame_number    = pinfo->fd->num;

    key[0].length = 1;
    key[0].key = &k_bus_id;
    key[1].length = 1;
    key[1].key = &k_device_address;

    main_item = proto_tree_add_item(tree, proto_usb_dfu, tvb, offset, -1, ENC_NA);
    main_tree = proto_item_add_subtree(main_item, ett_usb_dfu);

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "USB DFU");

    p2p_dir_save = pinfo->p2p_dir;
    pinfo->p2p_dir = (usb_conv_info->is_request) ? P2P_DIR_SENT : P2P_DIR_RECV;

    switch (pinfo->p2p_dir) {

    case P2P_DIR_SENT:
        col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
        break;

    case P2P_DIR_RECV:
        col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
        break;

    default:
        col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction ");
        break;
    }

    if (usb_conv_info->is_setup) {
        guint16  interface;

        command_item = proto_tree_add_item(main_tree, hf_setup_command, tvb, offset, 1, ENC_NA);
        command = tvb_get_guint8(tvb, offset);

        if (!((usb_conv_info->setup_requesttype == 0x21 && (command == 0x00 || command == 0x01 || command == 0x04 || command == 0x06)) ||
            (usb_conv_info->setup_requesttype == 0xa1 && (command == 0x02 || command == 0x03 || command == 0x05))))
            expert_add_info(pinfo, command_item, &ei_invalid_command_for_request_type);
        offset += 1;

        col_append_fstr(pinfo->cinfo, COL_INFO, "Command: %s",
                val_to_str_ext_const(command, &command_vals_ext, "Unknown"));

        if (command == 0x00) { /* Detach */
            proto_tree_add_item(main_tree, hf_setup_timeout, tvb, offset, 2, ENC_LITTLE_ENDIAN);
            col_append_fstr(pinfo->cinfo, COL_INFO, " Timeout=%u", tvb_get_letohs(tvb, offset));
        } else if (command == 0x01 || command == 0x02) { /* Download || Upload */
            proto_tree_add_item(main_tree, hf_setup_block_number, tvb, offset, 2, ENC_LITTLE_ENDIAN);
            col_append_fstr(pinfo->cinfo, COL_INFO, " Block Number=%u", tvb_get_letohs(tvb, offset));
            block_number = tvb_get_letohs(tvb, offset);
        } else {
            proto_tree_add_item(main_tree, hf_setup_unused, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        }
        offset += 2;

        proto_tree_add_item(main_tree, hf_setup_interface, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        interface = tvb_get_letohs(tvb, offset);
        offset += 2;

        proto_tree_add_item(main_tree, hf_setup_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
        offset += 2;

        if (command == 0x01) { /* Download */
            proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
            offset = tvb_length(tvb);
        }

        if (tvb_length_remaining(tvb, offset) > 0) {
            proto_tree_add_expert(main_tree, pinfo, &ei_unexpected_data, tvb, offset, tvb_length_remaining(tvb, offset));
            offset = tvb_length(tvb);
        }

        /* Save request info (command_data) */
        if (!pinfo->fd->flags.visited && command != 21) {
            key[2].length = 1;
            key[2].key = &k_frame_number;
            key[3].length = 0;
            key[3].key = NULL;

            command_data = wmem_new(wmem_file_scope(), command_data_t);
            command_data->bus_id = bus_id;
            command_data->device_address = device_address;

            command_data->command = command;
            command_data->interface = interface;
            command_data->command_frame_number = pinfo->fd->num;
            command_data->block_number = block_number;

            wmem_tree_insert32_array(command_info, key, command_data);
        }

        pinfo->p2p_dir = p2p_dir_save;

        return offset;
    }

    /* Get request info (command_data) */
    key[2].length = 0;
    key[2].key = NULL;

    wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key);
    if (wmem_tree) {
        command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->fd->num);
        if (command_data) {
            command_response = command_data->command;
            block_number = command_data->block_number;
        }
    }

    if (!command_data) {
        col_append_str(pinfo->cinfo, COL_INFO, "Response: Unknown");

        proto_tree_add_expert(main_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_length_remaining(tvb, offset));

        pinfo->p2p_dir = p2p_dir_save;

        return tvb_length(tvb);
    }

    col_append_fstr(pinfo->cinfo, COL_INFO, "Response: %s",
            val_to_str_ext_const(command_response, &command_vals_ext, "Unknown"));

    command_item = proto_tree_add_uint(main_tree, hf_response, tvb, offset, 0, command_response);
    command_tree = proto_item_add_subtree(command_item, ett_command);
    PROTO_ITEM_SET_GENERATED(command_item);

    if (command_data) {
        command_item = proto_tree_add_uint(main_tree, hf_setup_interface, tvb, offset, 0, command_data->interface);
        PROTO_ITEM_SET_GENERATED(command_item);

        command_item = proto_tree_add_uint(main_tree, hf_command_in_frame, tvb, offset, 0, command_data->command_frame_number);
        PROTO_ITEM_SET_GENERATED(command_item);
    }

    switch (command_response) {
    case 0x02: /* Upload */
        if (block_number != -1) {
            sub_item = proto_tree_add_uint(main_tree, hf_setup_block_number, tvb, offset, 0, block_number);
            PROTO_ITEM_SET_GENERATED(sub_item);
            col_append_fstr(pinfo->cinfo, COL_INFO, " Block Number=%u", block_number);
        }

        proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA);
        offset = tvb_length(tvb);

        break;
    case 0x03: /* Get Status */
        col_append_fstr(pinfo->cinfo, COL_INFO, " = Status: %s, PollTimeout: %u ms, State: %s",
                val_to_str_ext_const(tvb_get_guint8(tvb, offset), &status_vals_ext, "Unknown"),
                tvb_get_letoh24(tvb, offset + 1),
                val_to_str_ext_const(tvb_get_guint8(tvb, offset + 4), &state_vals_ext, "Unknown"));

        proto_tree_add_item(main_tree, hf_status, tvb, offset, 1, ENC_NA);
        offset += 1;

        proto_tree_add_item(main_tree, hf_poll_timeout, tvb, offset, 3, ENC_LITTLE_ENDIAN);
        offset += 3;

        proto_tree_add_item(main_tree, hf_state, tvb, offset, 1, ENC_NA);
        offset += 1;

        proto_tree_add_item(main_tree, hf_iString, tvb, offset, 1, ENC_NA);
        offset += 1;

        break;
    case 0x05: /* Get State */
        proto_tree_add_item(main_tree, hf_state, tvb, offset, 1, ENC_NA);

        col_append_fstr(pinfo->cinfo, COL_INFO, " = %s",
                val_to_str_ext_const(tvb_get_guint8(tvb, offset), &state_vals_ext, "Unknown"));

        offset += 1;

        break;
    case 0x00: /* Detach */
    case 0x01: /* Download */
    case 0x04: /* Clear Status */
    case 0x06: /* Abort */
    default:
        proto_tree_add_expert(command_tree, pinfo, &ei_unexpected_response, tvb, offset, 0);
        if (tvb_length_remaining(tvb, offset) > 0) {
            proto_tree_add_expert(main_tree, pinfo, &ei_unknown_data, tvb, offset, -1);
            offset = tvb_length(tvb);
        }
    }

    pinfo->p2p_dir = p2p_dir_save;

    return offset;
}