/* Transfers happen in response to broadcasts, they are always TCP and are * used to send the file to the port mentioned in the broadcast. There are * 2 types of transfers: Pushes, which are direct responses to searches, * in which the peer that has the file connects to the peer that doesn't and * sends it, then disconnects. The other type of transfer is a pull, where * the peer that doesn't have the file connects to the peer that does and * requests it be sent. * * Pulls have a file request which identifies the desired file, * while pushes simply send the file. In practice this works because every * file the implementation sends searches for is on a different TCP port * on the searcher's machine. */ static int dissect_ldss_transfer (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { conversation_t *transfer_conv; ldss_transfer_info_t *transfer_info; struct tcpinfo *transfer_tcpinfo; proto_tree *ti, *line_tree = NULL, *ldss_tree = NULL; nstime_t broadcast_response_time; /* Reject the packet if data is NULL */ if (data == NULL) return 0; transfer_tcpinfo = (struct tcpinfo *)data; col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDSS"); /* Look for the transfer conversation; this was created during * earlier broadcast dissection (see prepare_ldss_transfer_conv) */ transfer_conv = find_conversation (pinfo->num, &pinfo->src, &pinfo->dst, PT_TCP, pinfo->srcport, pinfo->destport, 0); DISSECTOR_ASSERT(transfer_conv); transfer_info = (ldss_transfer_info_t *)conversation_get_proto_data(transfer_conv, proto_ldss); DISSECTOR_ASSERT(transfer_info); /* For a pull, the first packet in the TCP connection is the file request. * First packet is identified by relative seq/ack numbers of 1. * File request only appears on a pull (triggered by an offer - see above * about broadcasts) */ if (transfer_tcpinfo->seq == 1 && transfer_tcpinfo->lastackseq == 1 && transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND) { /* LDSS pull transfers look a lot like HTTP. * Sample request: * md5:01234567890123... * Size: 2550 * Start: 0 * Compression: 0 * (remote end sends the file identified by the digest) */ guint offset = 0; gboolean already_dissected = TRUE; col_set_str(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Requesting file - pull)"); if (highest_num_seen == 0 || highest_num_seen < pinfo->num) { already_dissected = FALSE; transfer_info->req = wmem_new0(wmem_file_scope(), ldss_file_request_t); transfer_info->req->file = wmem_new0(wmem_file_scope(), ldss_file_t); highest_num_seen = pinfo->num; } ti = proto_tree_add_item(tree, proto_ldss, tvb, 0, tvb_reported_length(tvb), ENC_NA); ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer); /* Populate digest data into the file struct in the request */ transfer_info->file = transfer_info->req->file; /* Grab each line from the packet, there should be 4 but lets * not walk off the end looking for more. */ while (tvb_offset_exists(tvb, offset)) { gint next_offset; const guint8 *line; int linelen; gboolean is_digest_line; guint digest_type_len; linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* Include new-line in line */ line = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, offset, linelen+1); /* XXX - memory leak? */ line_tree = proto_tree_add_subtree(ldss_tree, tvb, offset, linelen, ett_ldss_transfer_req, NULL, tvb_format_text(tvb, offset, next_offset-offset)); /* Reduce code duplication processing digest lines. * There are too many locals to pass to a function - the signature * looked pretty ugly when I tried! */ is_digest_line = FALSE; if (strncmp(line,"md5:",4)==0) { is_digest_line = TRUE; digest_type_len = 4; transfer_info->file->digest_type = DIGEST_TYPE_MD5; } else if (strncmp(line, "sha1:", 5)==0) { is_digest_line = TRUE; digest_type_len = 5; transfer_info->file->digest_type = DIGEST_TYPE_SHA1; } else if (strncmp(line, "sha256:", 7)==0) { is_digest_line = TRUE; digest_type_len = 7; transfer_info->file->digest_type = DIGEST_TYPE_SHA256; } else if (strncmp(line, "unknown:", 8)==0) { is_digest_line = TRUE; digest_type_len = 8; transfer_info->file->digest_type = DIGEST_TYPE_UNKNOWN; } else if (strncmp(line, "Size: ", 6)==0) { /* Sample size line: * Size: 2550\n */ transfer_info->req->size = g_ascii_strtoull(line+6, NULL, 10); ti = proto_tree_add_uint64(line_tree, hf_ldss_size, tvb, offset+6, linelen-6, transfer_info->req->size); PROTO_ITEM_SET_GENERATED(ti); } else if (strncmp(line, "Start: ", 7)==0) { /* Sample offset line: * Start: 0\n */ transfer_info->req->offset = g_ascii_strtoull(line+7, NULL, 10); ti = proto_tree_add_uint64(line_tree, hf_ldss_offset, tvb, offset+7, linelen-7, transfer_info->req->offset); PROTO_ITEM_SET_GENERATED(ti); } else if (strncmp(line, "Compression: ", 13)==0) { /* Sample compression line: * Compression: 0\n */ transfer_info->req->compression = (gint8)strtol(line+13, NULL, 10); /* XXX - bad cast */ ti = proto_tree_add_uint(line_tree, hf_ldss_compression, tvb, offset+13, linelen-13, transfer_info->req->compression); PROTO_ITEM_SET_GENERATED(ti); } else { proto_tree_add_expert(line_tree, pinfo, &ei_ldss_unrecognized_line, tvb, offset, linelen); } if (is_digest_line) { proto_item *tii = NULL; /* Sample digest-type/digest line: * md5:0123456789ABCDEF\n */ if (!already_dissected) { GByteArray *digest_bytes; digest_bytes = g_byte_array_new(); hex_str_to_bytes( tvb_get_ptr(tvb, offset+digest_type_len, linelen-digest_type_len), digest_bytes, FALSE); if(digest_bytes->len >= DIGEST_LEN) digest_bytes->len = (DIGEST_LEN-1); /* Ensure the digest is zero-padded */ transfer_info->file->digest = (guint8 *)wmem_alloc0(wmem_file_scope(), DIGEST_LEN); memcpy(transfer_info->file->digest, digest_bytes->data, digest_bytes->len); g_byte_array_free(digest_bytes, TRUE); } tii = proto_tree_add_uint(line_tree, hf_ldss_digest_type, tvb, offset, digest_type_len, transfer_info->file->digest_type); PROTO_ITEM_SET_GENERATED(tii); tii = proto_tree_add_bytes(line_tree, hf_ldss_digest, tvb, offset+digest_type_len, MIN(linelen-digest_type_len, DIGEST_LEN), transfer_info->file->digest); PROTO_ITEM_SET_GENERATED(tii); } offset = next_offset; } /* Link forwards to the response for this pull. */ if (transfer_info->resp_num != 0) { ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_in, tvb, 0, 0, transfer_info->resp_num); PROTO_ITEM_SET_GENERATED(ti); } transfer_info->req->num = pinfo->num; transfer_info->req->ts = pinfo->abs_ts; } /* Remaining packets are the file response */ else { guint64 size; guint64 offset; guint8 compression; /* size, digest, compression come from the file request for a pull but * they come from the broadcast for a push. Pushes don't bother * with a file request - they just send the data. We have to get file * info from the offer broadcast which triggered this transfer. * If we cannot find the file request, default to the broadcast. */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL) { transfer_info->file = transfer_info->req->file; size = transfer_info->req->size; offset = transfer_info->req->offset; compression = transfer_info->req->compression; } else { transfer_info->file = transfer_info->broadcast->file; size = transfer_info->broadcast->size; offset = transfer_info->broadcast->offset; compression = transfer_info->broadcast->compression; } /* Remaining data in this TCP connection is all file data. * Always desegment if the size is 0 (ie. unknown) */ if (pinfo->can_desegment) { if (size == 0 || tvb_captured_length(tvb) < size) { pinfo->desegment_offset = 0; pinfo->desegment_len = DESEGMENT_UNTIL_FIN; return -1; } } /* OK. Now we have the whole file that was transferred. */ transfer_info->resp_num = pinfo->num; transfer_info->resp_ts = pinfo->abs_ts; col_add_fstr(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Sending file - %s)", transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND ? "pull" : "push"); ti = proto_tree_add_item(tree, proto_ldss, tvb, 0, tvb_reported_length(tvb), ENC_NA); ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer); proto_tree_add_bytes_format(ldss_tree, hf_ldss_file_data, tvb, 0, tvb_captured_length(tvb), NULL, compression == COMPRESSION_GZIP ? "Gzip compressed data: %d bytes" : "File data: %d bytes", tvb_captured_length(tvb)); #ifdef HAVE_ZLIB /* Be nice and uncompress the file data. */ if (compression == COMPRESSION_GZIP) { tvbuff_t *uncomp_tvb; uncomp_tvb = tvb_child_uncompress(tvb, tvb, 0, tvb_captured_length(tvb)); if (uncomp_tvb != NULL) { /* XXX: Maybe not a good idea to add a data_source for what may very well be a large buffer since then the full uncompressed buffer will be shown in a tab in the hex bytes pane ? However, if we don't, bytes in an unrelated tab will be highlighted. */ add_new_data_source(pinfo, uncomp_tvb, "Uncompressed Data"); proto_tree_add_bytes_format_value(ldss_tree, hf_ldss_file_data, uncomp_tvb, 0, tvb_captured_length(uncomp_tvb), NULL, "Uncompressed data: %d bytes", tvb_captured_length(uncomp_tvb)); } } #endif ti = proto_tree_add_uint(ldss_tree, hf_ldss_digest_type, tvb, 0, 0, transfer_info->file->digest_type); PROTO_ITEM_SET_GENERATED(ti); if (transfer_info->file->digest != NULL) { /* This is ugly. You can't add bytes of nonzero length and have * filtering work correctly unless you give a valid location in * the packet. This hack pretends the first 32 bytes of the packet * are the digest, which they aren't: they're actually the first 32 * bytes of the file that was sent. */ ti = proto_tree_add_bytes(ldss_tree, hf_ldss_digest, tvb, 0, DIGEST_LEN, transfer_info->file->digest); } PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint64(ldss_tree, hf_ldss_size, tvb, 0, 0, size); PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint64(ldss_tree, hf_ldss_offset, tvb, 0, 0, offset); PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint(ldss_tree, hf_ldss_compression, tvb, 0, 0, compression); PROTO_ITEM_SET_GENERATED(ti); /* Link to the request for a pull. */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL && transfer_info->req->num != 0) { ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_to, tvb, 0, 0, transfer_info->req->num); PROTO_ITEM_SET_GENERATED(ti); } } /* Print the pull response time */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL && transfer_info->resp_num != 0) { nstime_t pull_response_time; nstime_delta(&pull_response_time, &transfer_info->resp_ts, &transfer_info->req->ts); ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_response_time, tvb, 0, 0, &pull_response_time); PROTO_ITEM_SET_GENERATED(ti); } /* Link the transfer back to the initiating broadcast. Response time is * calculated as the time from broadcast to completed transfer. */ ti = proto_tree_add_uint(ldss_tree, hf_ldss_initiated_by, tvb, 0, 0, transfer_info->broadcast->num); PROTO_ITEM_SET_GENERATED(ti); if (transfer_info->resp_num != 0) { nstime_delta(&broadcast_response_time, &transfer_info->resp_ts, &transfer_info->broadcast->ts); ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_completed_in, tvb, 0, 0, &broadcast_response_time); PROTO_ITEM_SET_GENERATED(ti); } /* This conv got its addr2/port2 set by the TCP dissector because a TCP * connection was established. Make a new one to handle future connections * to the addr/port mentioned in the broadcast, because that socket is * still open. */ if (transfer_tcpinfo->seq == 1 && transfer_tcpinfo->lastackseq == 1) { prepare_ldss_transfer_conv(transfer_info->broadcast); } return tvb_captured_length(tvb); }
static gint dissect_adb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *arg0_item; proto_tree *arg0_tree; proto_item *arg1_item; proto_tree *arg1_tree; proto_item *magic_item; proto_item *crc_item; proto_tree *crc_tree = NULL; proto_item *sub_item; gint offset = 0; guint32 command; guint32 arg0; guint32 arg1; guint32 data_length = 0; guint32 crc32 = 0; usb_conv_info_t *usb_conv_info = NULL; wmem_tree_key_t key[5]; guint32 interface_id; guint32 bus_id; guint32 device_address; guint32 side_id; guint32 frame_number; gboolean is_command = TRUE; gboolean is_next_fragment = FALSE; gboolean is_service = FALSE; gint proto; gint direction = P2P_DIR_UNKNOWN; wmem_tree_t *wmem_tree; command_data_t *command_data = NULL; service_data_t *service_data = NULL; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ADB"); col_clear(pinfo->cinfo, COL_INFO); main_item = proto_tree_add_item(tree, proto_adb, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_adb); frame_number = pinfo->fd->num; /* XXX: Why? If interface is USB only first try is correct * (and seems strange...), in other cases standard check for * previous protocol is correct */ proto = (gint) GPOINTER_TO_INT(wmem_list_frame_data(/*wmem_list_frame_prev*/(wmem_list_tail(pinfo->layers)))); if (proto != proto_usb) { proto = (gint) GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo->layers)))); } if (proto == proto_usb) { usb_conv_info = (usb_conv_info_t *) data; DISSECTOR_ASSERT(usb_conv_info); direction = usb_conv_info->direction; } else if (proto == proto_tcp) { if (pinfo->destport == ADB_TCP_PORT) direction = P2P_DIR_SENT; else direction = P2P_DIR_RECV; } else { return offset; } if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID) interface_id = pinfo->phdr->interface_id; else interface_id = 0; if (proto == proto_usb) { 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 = 0; key[3].key = NULL; } else { /* tcp */ 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 = 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, frame_number); if (command_data && command_data->completed_in_frame >= frame_number && command_data->command_in_frame <= frame_number) { if (command_data->command_in_frame != frame_number) { is_command = FALSE; is_next_fragment = TRUE; } data_length = command_data->data_length; crc32 = command_data->crc32; 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 if (command_data->command == A_OKAY) { side_id = command_data->arg1; /* IN: remote 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 (service_data && command_data->command == A_OPEN) { is_service = TRUE; } } } } /* Simple heuristics to check if packet is command or data */ if ((command_data && command_data->completed_in_frame <= frame_number) || !command_data) { if (tvb_reported_length(tvb) < 24) { is_command = FALSE; } else if (tvb_reported_length(tvb) >= 24) { command = tvb_get_letohl(tvb, offset); if (command != A_SYNC && command != A_CLSE && command != A_WRTE && command != A_AUTH && command != A_CNXN && command != A_OPEN && command != A_OKAY) is_command = FALSE; else if (command != (0xFFFFFFFF ^ tvb_get_letohl(tvb, offset + 20))) is_command = FALSE; if (is_command) { data_length = tvb_get_letohl(tvb, offset + 12); crc32 = tvb_get_letohl(tvb, offset + 16); } if (command == A_OPEN) is_service = TRUE; } } if (service_data && !(command_data->command == A_OPEN && is_next_fragment)) { sub_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service_data->service); PROTO_ITEM_SET_GENERATED(sub_item); } if (service_data) { sub_item = proto_tree_add_uint(main_tree, hf_service_start_in_frame, tvb, offset, 0, service_data->start_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); if (service_data->close_local_in_frame < max_in_frame) { sub_item = proto_tree_add_uint(main_tree, hf_close_local_in_frame, tvb, offset, 0, service_data->close_local_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } if (service_data->close_remote_in_frame < max_in_frame) { sub_item = proto_tree_add_uint(main_tree, hf_close_remote_in_frame, tvb, offset, 0, service_data->close_remote_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } } if (is_command) { proto_tree_add_item(main_tree, hf_command, tvb, offset, 4, ENC_LITTLE_ENDIAN); command = tvb_get_letohl(tvb, offset); offset += 4; col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(command, command_vals, "Unknown command")); arg0_item = proto_tree_add_item(main_tree, hf_argument_0, tvb, offset, 4, ENC_LITTLE_ENDIAN); arg0_tree = proto_item_add_subtree(arg0_item, ett_adb_arg0); arg0 = tvb_get_letohl(tvb, offset); offset += 4; arg1_item = proto_tree_add_item(main_tree, hf_argument_1, tvb, offset, 4, ENC_LITTLE_ENDIAN); arg1_tree = proto_item_add_subtree(arg1_item, ett_adb_arg1); arg1 = tvb_get_letohl(tvb, offset); offset += 4; switch (command) { case A_CNXN: proto_tree_add_item(arg0_tree, hf_version, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_max_data, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(version=%u.%u.%u, max_data=%u)", tvb_get_guint8(tvb, offset - 5), tvb_get_guint8(tvb, offset - 6), tvb_get_letohs(tvb, offset - 7), tvb_get_letohl(tvb, offset - 4)); break; case A_AUTH: proto_tree_add_item(arg0_tree, hf_auth_type, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_zero, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(type=%s, 0)", val_to_str_const(tvb_get_letohl(tvb, offset - 8), auth_type_vals, "Unknown")); break; case A_OPEN: proto_tree_add_item(arg0_tree, hf_local_id, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_zero, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(local=%u, 0)", tvb_get_letohl(tvb, offset - 8)); break; case A_WRTE: proto_tree_add_item(arg0_tree, hf_zero, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_remote_id, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(0, remote=%u)", tvb_get_letohl(tvb, offset - 4)); break; case A_CLSE: case A_OKAY: proto_tree_add_item(arg0_tree, hf_local_id, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_remote_id, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(local=%u, remote=%u)", tvb_get_letohl(tvb, offset - 8), tvb_get_letohl(tvb, offset - 4)); break; case A_SYNC: proto_tree_add_item(arg0_tree, hf_online, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_sequence, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(online=%s, sequence=%u)", tvb_get_letohl(tvb, offset - 8) ? "Yes": "No", tvb_get_letohl(tvb, offset - 4)); break; } proto_tree_add_item(main_tree, hf_data_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; if (data_length > 0) col_append_fstr(pinfo->cinfo, COL_INFO, " length=%u ", data_length); crc_item = proto_tree_add_item(main_tree, hf_data_crc32, tvb, offset, 4, ENC_LITTLE_ENDIAN); crc_tree = proto_item_add_subtree(crc_item, ett_adb_crc); crc32 = tvb_get_letohl(tvb, offset); offset += 4; magic_item = proto_tree_add_item(main_tree, hf_magic, tvb, offset, 4, ENC_LITTLE_ENDIAN); if ((tvb_get_letohl(tvb, offset) ^ 0xFFFFFFFF) != command) { proto_tree *expert_tree; expert_tree = proto_item_add_subtree(magic_item, ett_adb_magic); proto_tree_add_expert(expert_tree, pinfo, &ei_invalid_magic, tvb, offset, 4); } if (!pinfo->fd->flags.visited) save_command(command, arg0, arg1, data_length, crc32, service_data, proto, data, pinfo, &service_data, &command_data); offset += 4; } if (!pinfo->fd->flags.visited && command_data) { if (command_data->command_in_frame != frame_number) { is_command = FALSE; is_next_fragment = TRUE; } data_length = command_data->data_length; crc32 = command_data->crc32; if ((command_data->command_in_frame != frame_number && tvb_captured_length(tvb) == data_length) || (command_data->command_in_frame == frame_number && tvb_captured_length(tvb) == data_length + 24) ) { command_data->reassemble_data_length = command_data->data_length; command_data->completed_in_frame = frame_number; } } if (is_next_fragment && command_data) { sub_item = proto_tree_add_uint(main_tree, hf_command_in_frame, tvb, offset, 0, command_data->command_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); sub_item = proto_tree_add_uint(main_tree, hf_command, tvb, offset, 0, command_data->command); PROTO_ITEM_SET_GENERATED(sub_item); sub_item = proto_tree_add_uint(main_tree, hf_data_length, tvb, offset, 0, command_data->data_length); PROTO_ITEM_SET_GENERATED(sub_item); crc_item = proto_tree_add_uint(main_tree, hf_data_crc32, tvb, offset, 0, command_data->crc32); crc_tree = proto_item_add_subtree(crc_item, ett_adb_crc); PROTO_ITEM_SET_GENERATED(crc_item); } if (command_data && command_data->completed_in_frame != frame_number) { sub_item = proto_tree_add_uint(main_tree, hf_completed_in_frame, tvb, offset, 0, command_data->completed_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } if (tvb_captured_length_remaining(tvb, offset) > 0 && (!is_command || data_length > 0)) { guint32 crc = 0; guint32 i_offset; if ((!pinfo->fd->flags.visited && command_data && command_data->reassemble_data_length < command_data->data_length) || data_length > (guint32) tvb_captured_length_remaining(tvb, offset)) { /* need reassemble */ if (!pinfo->fd->flags.visited && command_data && command_data->reassemble_data_length < command_data->data_length) { tvb_memcpy(tvb, command_data->reassemble_data + command_data->reassemble_data_length, offset, tvb_captured_length_remaining(tvb, offset)); command_data->reassemble_data_length += tvb_captured_length_remaining(tvb, offset); if (command_data->reassemble_data_length >= command_data->data_length) command_data->completed_in_frame = frame_number; } proto_tree_add_item(main_tree, hf_data_fragment, tvb, offset, -1, ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Data Fragment"); offset = tvb_captured_length(tvb); if (service_data && command_data && command_data->reassemble_data_length >= command_data->data_length && frame_number == command_data->completed_in_frame) { tvbuff_t *next_tvb; adb_service_data_t adb_service_data; next_tvb = tvb_new_child_real_data(tvb, command_data->reassemble_data, command_data->reassemble_data_length, command_data->reassemble_data_length); add_new_data_source(pinfo, next_tvb, "ADB Reassembled Data"); adb_service_data.service = service_data->service; adb_service_data.direction = direction; adb_service_data.session_key_length = 3; adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32)); adb_service_data.session_key[0] = interface_id; if (proto == proto_usb) { adb_service_data.session_key[1] = usb_conv_info->bus_id; adb_service_data.session_key[2] = usb_conv_info->device_address; } else { /* tcp */ if (direction == P2P_DIR_SENT) { adb_service_data.session_key[1] = pinfo->srcport; adb_service_data.session_key[2] = pinfo->destport; } else { adb_service_data.session_key[1] = pinfo->destport; adb_service_data.session_key[2] = pinfo->srcport; } } call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data); } } else { /* full message */ for (i_offset = 0; i_offset < data_length; ++i_offset) crc += tvb_get_guint8(tvb, offset + i_offset); if (crc32 > 0 && crc32 != crc) proto_tree_add_expert(crc_tree, pinfo, &ei_invalid_crc, tvb, offset, -1); if (is_service) { proto_tree_add_item(main_tree, hf_service, tvb, offset, -1, ENC_ASCII | ENC_NA); if (!pinfo->fd->flags.visited && service_data) { service_data->service = tvb_get_stringz_enc(wmem_file_scope(), tvb, offset, NULL, ENC_ASCII); } col_append_fstr(pinfo->cinfo, COL_INFO, "Service: %s", tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, NULL, ENC_ASCII)); offset = tvb_captured_length(tvb); } else if (command_data && command_data->command == A_CNXN) { gchar *info; gint len; info = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &len, ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, "Connection Info: %s", info); proto_tree_add_item(main_tree, hf_connection_info, tvb, offset, len, ENC_ASCII | ENC_NA); offset += len; } else { col_append_str(pinfo->cinfo, COL_INFO, "Data"); /* Decode service payload */ if (service_data) { tvbuff_t *next_tvb; adb_service_data_t adb_service_data; adb_service_data.service = service_data->service; adb_service_data.direction = direction; adb_service_data.session_key_length = 3; adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32)); adb_service_data.session_key[0] = interface_id; if (proto == proto_usb) { adb_service_data.session_key[1] = usb_conv_info->bus_id; adb_service_data.session_key[2] = usb_conv_info->device_address; } else { /* tcp */ if (direction == P2P_DIR_SENT) { adb_service_data.session_key[1] = pinfo->srcport; adb_service_data.session_key[2] = pinfo->destport; } else { adb_service_data.session_key[1] = pinfo->destport; adb_service_data.session_key[2] = pinfo->srcport; } } next_tvb = tvb_new_subset(tvb, offset, tvb_captured_length_remaining(tvb, offset), tvb_captured_length_remaining(tvb, offset)); call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data); } else { proto_item *data_item; gchar *data_str; data_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, data_length, ENC_NA); data_str = tvb_format_text(tvb, offset, data_length); proto_item_append_text(data_item, ": %s", data_str); col_append_fstr(pinfo->cinfo, COL_INFO, " Raw: %s", data_str); } offset = tvb_captured_length(tvb); } } } return offset; }
static void socks_udp_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Conversation dissector called from UDP dissector. Decode and display */ /* the socks header, the pass the rest of the data to the udp port */ /* decode routine to handle the payload. */ int offset = 0; guint32 *ptr; socks_hash_entry_t *hash_info; conversation_t *conversation; proto_tree *socks_tree; proto_item *ti; conversation = find_conversation( pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); DISSECTOR_ASSERT( conversation); /* should always find a conversation */ hash_info = (socks_hash_entry_t *)conversation_get_proto_data(conversation, proto_socks); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Socks"); col_set_str(pinfo->cinfo, COL_INFO, "Version: 5, UDP Associated packet"); if ( tree) { ti = proto_tree_add_protocol_format( tree, proto_socks, tvb, offset, -1, "Socks" ); socks_tree = proto_item_add_subtree(ti, ett_socks); proto_tree_add_item(socks_tree, hf_socks_reserved2, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(socks_tree, hf_socks_fragment_number, tvb, offset, 1, ENC_NA); offset += 1; offset = display_address( tvb, offset, socks_tree); hash_info->udp_remote_port = tvb_get_ntohs(tvb, offset); proto_tree_add_uint( socks_tree, hf_socks_dstport, tvb, offset, 2, hash_info->udp_remote_port); offset += 2; } else { /* no tree, skip past the socks header */ offset += 3; offset = get_address_v5( tvb, offset, 0) + 2; } /* set pi src/dst port and call the udp sub-dissector lookup */ if ( pinfo->srcport == hash_info->port) ptr = &pinfo->destport; else ptr = &pinfo->srcport; *ptr = hash_info->udp_remote_port; decode_udp_ports( tvb, offset, pinfo, tree, pinfo->srcport, pinfo->destport, -1); *ptr = hash_info->udp_port; }
static void gbl_symbols_new(void) { DISSECTOR_ASSERT(gbl_symbols_array == NULL); gbl_symbols_array = g_array_new(TRUE, TRUE, sizeof(value_string)); }
/* Both Source-Active and Source-Active Response have the same format * with one exception. Encapsulated multicast data is not allowed in * SA Response. */ static void dissect_msdp_sa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, int length) { guint8 entries; if (length < 1) return; entries = tvb_get_guint8(tvb, *offset); proto_tree_add_uint(tree, hf_msdp_sa_entry_count, tvb, *offset, 1, entries); *offset += 1; length -= 1; if (length < 4) { *offset += length; return; } proto_tree_add_item(tree, hf_msdp_sa_rp_addr, tvb, *offset, 4, ENC_BIG_ENDIAN); *offset += 4; length -= 4; /* Put each of the (S,G) entries in their own subtree. * This is probably visually better. */ while (entries-- > 0) { proto_item *ei; proto_tree *entry_tree; if (length < 12) { *offset += length; return; } ei = proto_tree_add_text(tree, tvb, *offset, 12, "(S,G) block: %s/%u -> %s", tvb_ip_to_str(tvb, *offset + 8), tvb_get_guint8(tvb, *offset + 3), tvb_ip_to_str(tvb, *offset + 4)); entry_tree = proto_item_add_subtree(ei, ett_msdp_sa_entry); proto_tree_add_item(entry_tree, hf_msdp_sa_reserved, tvb, *offset, 3, ENC_BIG_ENDIAN); *offset += 3; length -= 3; proto_tree_add_item(entry_tree, hf_msdp_sa_sprefix_len, tvb, *offset, 1, ENC_BIG_ENDIAN); *offset += 1; length -= 1; proto_tree_add_item(entry_tree, hf_msdp_sa_group_addr, tvb, *offset, 4, ENC_BIG_ENDIAN); *offset += 4; length -= 4; proto_tree_add_item(entry_tree, hf_msdp_sa_src_addr, tvb, *offset, 4, ENC_BIG_ENDIAN); *offset += 4; length -= 4; } /* * Check if an encapsulated multicast IPv4 packet follows */ if (length > 0) { proto_item *ei; proto_tree *enc_tree; gint available_length, reported_length; tvbuff_t *next_tvb; ei = proto_tree_add_text(tree, tvb, *offset, length, "Encapsulated IPv4 packet: %u bytes", length); enc_tree = proto_item_add_subtree(ei, ett_msdp_sa_enc_data); available_length = tvb_length_remaining(tvb, *offset); reported_length = tvb_reported_length_remaining(tvb, *offset); DISSECTOR_ASSERT(available_length >= 0); DISSECTOR_ASSERT(reported_length >= 0); if (available_length > reported_length) available_length = reported_length; if (available_length > length) available_length = length; if (reported_length > length) reported_length = length; next_tvb = tvb_new_subset(tvb, *offset, available_length, reported_length); /* Set the information columns read-only so that they * reflect the MSDP packet rather than the * encapsulated packet. */ col_set_writable(pinfo->cinfo, FALSE); call_dissector(ip_handle, next_tvb, pinfo, enc_tree); } *offset += length; return; }
fragment_head *stream_get_frag_data( const stream_pdu_fragment_t *frag) { DISSECTOR_ASSERT( frag ); return frag->pdu->fd_head; }
static void dissect_xmpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { xml_frame_t *xml_frame; gboolean out_packet; conversation_t *conversation; xmpp_conv_info_t *xmpp_info; proto_tree *xmpp_tree = NULL; proto_item *xmpp_item = NULL; xmpp_element_t *packet = NULL; /*check if desegment * now it checks that last char is '>', * TODO checks that first element in packet is closed*/ int indx; gchar last_char; if (xmpp_desegment) { indx = tvb_reported_length(tvb) - 1; if (indx >= 0) { last_char = tvb_get_guint8(tvb, indx); while ((last_char <= ' ') && (indx - 1 >= 0)) { indx--; last_char = tvb_get_guint8(tvb, indx); } if ((indx >= 0) && (last_char != '>')) { pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; return; } } } col_set_str(pinfo->cinfo, COL_PROTOCOL, "XMPP"); col_clear(pinfo->cinfo, COL_INFO); conversation = find_or_create_conversation(pinfo); xmpp_info = (xmpp_conv_info_t *)conversation_get_proto_data(conversation, proto_xmpp); if (xmpp_info && xmpp_info->ssl_proceed && xmpp_info->ssl_proceed < pinfo->fd->num) { call_dissector(ssl_handle, tvb, pinfo, tree); return; } /*if tree == NULL then xmpp_item and xmpp_tree will also NULL*/ xmpp_item = proto_tree_add_item(tree, proto_xmpp, tvb, 0, -1, ENC_NA); xmpp_tree = proto_item_add_subtree(xmpp_item, ett_xmpp); call_dissector(xml_handle, tvb, pinfo, xmpp_tree); /* If XML dissector is disabled, we can't do much */ if (!proto_is_protocol_enabled(find_protocol_by_id(dissector_handle_get_protocol_index(xml_handle)))) { col_append_str(pinfo->cinfo, COL_INFO, "(XML dissector disabled, can't dissect XMPP)"); expert_add_info_format(pinfo, xmpp_item, PI_UNDECODED, PI_WARN, "XML dissector disabled, can't dissect XMPP"); return; } /*if stream end occurs then return*/ if(xmpp_stream_close(xmpp_tree,tvb, pinfo)) { if(xmpp_tree) xmpp_proto_tree_hide_first_child(xmpp_tree); return; } if(!pinfo->private_data) return; /*data from XML dissector*/ xml_frame = ((xml_frame_t*)pinfo->private_data)->first_child; if(!xml_frame) return; if (!xmpp_info) { xmpp_info = se_new(xmpp_conv_info_t); xmpp_info->req_resp = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "xmpp_req_resp"); xmpp_info->jingle_sessions = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "xmpp_jingle_sessions"); xmpp_info->ibb_sessions = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "xmpp_ibb_sessions"); xmpp_info->gtalk_sessions = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "xmpp_gtalk_sessions"); xmpp_info->ssl_start = 0; xmpp_info->ssl_proceed = 0; conversation_add_proto_data(conversation, proto_xmpp, (void *) xmpp_info); } if (pinfo->match_uint == pinfo->destport) out_packet = TRUE; else out_packet = FALSE; while(xml_frame) { packet = xmpp_xml_frame_to_element_t(xml_frame, NULL, tvb); DISSECTOR_ASSERT(packet); if (strcmp(packet->name, "iq") == 0) { xmpp_iq_reqresp_track(pinfo, packet, xmpp_info); xmpp_jingle_session_track(pinfo, packet, xmpp_info); xmpp_gtalk_session_track(pinfo, packet, xmpp_info); } if (strcmp(packet->name, "iq") == 0 || strcmp(packet->name, "message") == 0) { xmpp_ibb_session_track(pinfo, packet, xmpp_info); } if (tree) { /* we are being asked for details */ proto_item *outin_item; if (out_packet) outin_item = proto_tree_add_boolean(xmpp_tree, hf_xmpp_out, tvb, 0, 0, TRUE); else outin_item = proto_tree_add_boolean(xmpp_tree, hf_xmpp_in, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(outin_item); /*it hides tree generated by XML dissector*/ xmpp_proto_tree_hide_first_child(xmpp_tree); if (strcmp(packet->name, "iq") == 0) { xmpp_iq(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "presence") == 0) { xmpp_presence(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "message") == 0) { xmpp_message(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "auth") == 0) { xmpp_auth(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "challenge") == 0) { xmpp_challenge_response_success(xmpp_tree, tvb, pinfo, packet, hf_xmpp_challenge, ett_xmpp_challenge, "CHALLENGE"); } else if (strcmp(packet->name, "response") == 0) { xmpp_challenge_response_success(xmpp_tree, tvb, pinfo, packet, hf_xmpp_response, ett_xmpp_response, "RESPONSE"); } else if (strcmp(packet->name, "success") == 0) { xmpp_challenge_response_success(xmpp_tree, tvb, pinfo, packet, hf_xmpp_success, ett_xmpp_success, "SUCCESS"); } else if (strcmp(packet->name, "failure") == 0) { xmpp_failure(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "xml") == 0) { xmpp_xml_header(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "stream") == 0) { xmpp_stream(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "features") == 0) { xmpp_features(xmpp_tree, tvb, pinfo, packet); } else if (strcmp(packet->name, "starttls") == 0) { xmpp_starttls(xmpp_tree, tvb, pinfo, packet, xmpp_info); }else if (strcmp(packet->name, "proceed") == 0) { xmpp_proceed(xmpp_tree, tvb, pinfo, packet, xmpp_info); }else { xmpp_proto_tree_show_first_child(xmpp_tree); expert_add_info_format(pinfo, xmpp_tree, PI_UNDECODED, PI_NOTE, "Unknown packet: %s", packet->name); col_clear(pinfo->cinfo, COL_INFO); col_append_fstr(pinfo->cinfo, COL_INFO, "UNKNOWN PACKET "); } /*appends to COL_INFO information about src or dst*/ if (pinfo->match_uint == pinfo->destport) { xmpp_attr_t *to = xmpp_get_attr(packet, "to"); if (to) col_append_fstr(pinfo->cinfo, COL_INFO, "> %s ", to->value); } else { xmpp_attr_t *from = xmpp_get_attr(packet, "from"); if (from) col_append_fstr(pinfo->cinfo, COL_INFO, "< %s ", from->value); } } xmpp_element_t_tree_free(packet); xml_frame = xml_frame->next_sibling; } }
void asn1_stack_frame_pop(asn1_ctx_t *actx, const gchar *name) { DISSECTOR_ASSERT(actx->stack); DISSECTOR_ASSERT(!strcmp(actx->stack->name, name)); actx->stack = actx->stack->next; }
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; }
gcp_cmd_t* gcp_cmd(gcp_msg_t* m, gcp_trx_t* t, gcp_ctx_t* c, gcp_cmd_type_t type, guint offset, gboolean persistent) { gcp_cmd_t* cmd; gcp_cmd_msg_t* cmdtrx; gcp_cmd_msg_t* cmdctx; if ( !m || !t || !c ) return NULL; if (persistent) { if (m->commited) { DISSECTOR_ASSERT(t->cmds != NULL); for (cmdctx = t->cmds; cmdctx; cmdctx = cmdctx->next) { cmd = cmdctx->cmd; if (cmd->msg == m && cmd->offset == offset) { return cmd; } } DISSECTOR_ASSERT(!"called for a command that does not exist!"); return NULL; } else { cmd = se_alloc(sizeof(gcp_cmd_t)); cmdtrx = se_alloc(sizeof(gcp_cmd_msg_t)); cmdctx = se_alloc(sizeof(gcp_cmd_msg_t)); } } else { cmd = ep_new(gcp_cmd_t); cmdtrx = ep_new(gcp_cmd_msg_t); cmdctx = ep_new(gcp_cmd_msg_t); } cmd->type = type; cmd->offset = offset; cmd->terms.term = NULL; cmd->terms.next = NULL; cmd->terms.last = &(cmd->terms); cmd->str = NULL; cmd->msg = m; cmd->trx = t; cmd->ctx = c; cmd->error = 0; cmdctx->cmd = cmdtrx->cmd = cmd; cmdctx->next = cmdtrx->next = NULL; cmdctx->last = cmdtrx->last = NULL; if (t->cmds) { t->cmds->last->next = cmdtrx; t->cmds->last = cmdtrx; } else { t->cmds = cmdtrx; t->cmds->last = cmdtrx; } if (c->cmds) { c->cmds->last->next = cmdctx; c->cmds->last = cmdctx; } else { c->cmds = cmdctx; c->cmds->last = cmdctx; } return cmd; }
/* Initializes an extended value string. Behaves like a match function to * permit lazy initialization of extended value strings. * - Goes through the value_string array to determine the fastest possible * access method. * - Verifies that the value_string contains no NULL string pointers. * - Verifies that the value_string is terminated by {0, NULL} */ const value_string * _try_val_to_str_ext_init(const guint32 val, const value_string_ext *a_vse) { /* Cast away the constness! * It's better if the prototype for this function matches the other * _try_val_to_str_* functions (so we don't have to cast it when storing it * in _try_val_to_str so the compiler will notice if the prototypes get out * of sync), but the init function is unique in that it does actually * modify the vse. */ value_string_ext *vse = (value_string_ext *)a_vse; const value_string *vs_p = vse->_vs_p; const guint vs_num_entries = vse->_vs_num_entries; /* The matching algorithm used: * VS_SEARCH - slow sequential search (as in a normal value string) * VS_BIN_TREE - log(n)-time binary search, the values must be sorted * VS_INDEX - constant-time index lookup, the values must be contiguous */ enum { VS_SEARCH, VS_BIN_TREE, VS_INDEX } type = VS_INDEX; /* Note: The value_string 'value' is *unsigned*, but we do a little magic * to help with value strings that have negative values. * * { -3, -2, -1, 0, 1, 2 } * will be treated as "ascending ordered" (although it isn't technically), * thus allowing constant-time index search * * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 } * will both be considered as "out-of-order with gaps", thus falling * back to the slow linear search * * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 } * will be considered "ascending ordered with gaps" thus allowing * a log(n)-time 'binary' search * * If you're confused, think of how negative values are represented, or * google two's complement. */ guint32 prev_value; guint first_value; guint i; DISSECTOR_ASSERT((vs_p[vs_num_entries].value == 0) && (vs_p[vs_num_entries].strptr == NULL)); vse->_vs_first_value = vs_p[0].value; first_value = vs_p[0].value; prev_value = first_value; for (i = 0; i < vs_num_entries; i++) { DISSECTOR_ASSERT(vs_p[i].strptr != NULL); if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) { type = VS_BIN_TREE; } /* XXX: Should check for dups ?? */ if (type == VS_BIN_TREE) { if (prev_value > vs_p[i].value) { g_warning("Extended value string %s forced to fall back to linear search: entry %u, value %u < previous entry, value %u", vse->_vs_name, i, vs_p[i].value, prev_value); type = VS_SEARCH; break; } if (first_value > vs_p[i].value) { g_warning("Extended value string %s forced to fall back to linear search: entry %u, value %u < first entry, value %u", vse->_vs_name, i, vs_p[i].value, first_value); type = VS_SEARCH; break; } } prev_value = vs_p[i].value; } switch (type) { case VS_SEARCH: vse->_vs_match2 = _try_val_to_str_linear; break; case VS_BIN_TREE: vse->_vs_match2 = _try_val_to_str_bsearch; break; case VS_INDEX: vse->_vs_match2 = _try_val_to_str_index; break; default: g_assert_not_reached(); break; } return vse->_vs_match2(val, vse); }
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) { emem_tree_key_t ctx_key[] = { {1,&(m->hi_addr)}, {1,&(m->lo_addr)}, {1,&(c_id)}, {0,NULL} }; emem_tree_key_t trx_key[] = { {1,&(m->hi_addr)}, {1,&(m->lo_addr)}, {1,&(t->id)}, {0,NULL} }; if (m->commited) { if (( context = se_tree_lookup32_array(ctxs_by_trx,trx_key) )) { return context; } if ((context_p = se_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 = se_tree_lookup32_array(ctxs_by_trx,trx_key))) { context = se_alloc(sizeof(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; se_tree_insert32_array(ctxs_by_trx,trx_key,context); } } else { if (( context = se_tree_lookup32_array(ctxs_by_trx,trx_key) )) { if (( context_p = se_tree_lookup32_array(ctxs,ctx_key) )) { if (context != *context_p) { if(context->id != CHOOSE_CONTEXT) { context = se_alloc(sizeof(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 = se_alloc(sizeof(void*)); *context_p = context; context->initial = m; context->id = c_id; se_tree_insert32_array(ctxs,ctx_key,context_p); } } else if (! ( context_p = se_tree_lookup32_array(ctxs,ctx_key) )) { context = se_alloc(sizeof(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 = se_alloc(sizeof(void*)); *context_p = context; se_tree_insert32_array(ctxs,ctx_key,context_p); } else { context = *context_p; } } } } else { context = ep_new(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; } return context; }
static gboolean print_field_value(field_info *finfo, int cmd_line_index) { header_field_info *hfinfo; static char *fs_buf = NULL; char *fs_ptr = fs_buf; static GString *label_s = NULL; int fs_buf_len = FIELD_STR_INIT_LEN, fs_len; guint i; string_fmt_t *sf; guint32 uvalue; gint32 svalue; const true_false_string *tfstring = &tfs_true_false; hfinfo = finfo->hfinfo; if (!fs_buf) { fs_buf = g_malloc(fs_buf_len + 1); fs_ptr = fs_buf; } if (!label_s) { label_s = g_string_new(""); } if(finfo->value.ftype->val_to_string_repr) { /* * this field has an associated value, * e.g: ip.hdr_len */ fs_len = fvalue_string_repr_len(&finfo->value, FTREPR_DFILTER); while (fs_buf_len < fs_len) { fs_buf_len *= 2; fs_buf = g_realloc(fs_buf, fs_buf_len + 1); fs_ptr = fs_buf; } fvalue_to_string_repr(&finfo->value, FTREPR_DFILTER, fs_buf); /* String types are quoted. Remove them. */ if ((finfo->value.ftype->ftype == FT_STRING || finfo->value.ftype->ftype == FT_STRINGZ) && fs_len > 2) { fs_buf[fs_len - 1] = '\0'; fs_ptr++; } } if (string_fmts->len > 0 && finfo->hfinfo->strings) { g_string_truncate(label_s, 0); for (i = 0; i < string_fmts->len; i++) { sf = g_ptr_array_index(string_fmts, i); if (sf->plain) { g_string_append(label_s, sf->plain); } else { switch (sf->format) { case SF_NAME: g_string_append(label_s, hfinfo->name); break; case SF_NUMVAL: g_string_append(label_s, fs_ptr); break; case SF_STRVAL: switch(hfinfo->type) { case FT_BOOLEAN: uvalue = fvalue_get_uinteger(&finfo->value); tfstring = (const struct true_false_string*) hfinfo->strings; g_string_append(label_s, uvalue ? tfstring->true_string : tfstring->false_string); break; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: DISSECTOR_ASSERT(!hfinfo->bitmask); svalue = fvalue_get_sinteger(&finfo->value); if (hfinfo->display & BASE_RANGE_STRING) { g_string_append(label_s, rval_to_str(svalue, hfinfo->strings, "Unknown")); } else { g_string_append(label_s, val_to_str(svalue, cVALS(hfinfo->strings), "Unknown")); } case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: uvalue = fvalue_get_uinteger(&finfo->value); if (!hfinfo->bitmask && hfinfo->display & BASE_RANGE_STRING) { g_string_append(label_s, rval_to_str(uvalue, hfinfo->strings, "Unknown")); } else { g_string_append(label_s, val_to_str(uvalue, cVALS(hfinfo->strings), "Unknown")); } break; default: break; } break; default: break; } } } printf(" %u=\"%s\"", cmd_line_index, label_s->str); return TRUE; } if(finfo->value.ftype->val_to_string_repr) { printf(" %u=\"%s\"", cmd_line_index, fs_ptr); return TRUE; } /* * This field doesn't have an associated value, * e.g. http * We return n.a. */ printf(" %u=\"n.a.\"", cmd_line_index); return TRUE; }
static int dissect_pcap_pktdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { gint offset = 0; guint32 *link_type; guint32 length = 0; tvbuff_t *next_tvb; proto_item *pseudoheader_item; proto_tree *pseudoheader_tree = NULL; proto_item *packet_item; proto_tree *packet_tree; DISSECTOR_ASSERT(data); link_type = (guint32 *) data; pinfo->phdr->pkt_encap = wtap_pcap_encap_to_wtap_encap(*link_type); switch (*link_type) { case 139: /* TODO no description for pseudoheader at http://www.tcpdump.org/linktypes.html */ break; case 196: length = 5; break; case 197: /* TODO no description for pseudoheader at http://www.tcpdump.org/linktypes.html */ break; case 201: length = 4; break; case 204: length = 1; break; case 205: length = 1; break; case 206: length = 1; break; case 209: length = 6; break; case 226: length = 24; break; case 227: /* TODO no description for pseudoheader at http://www.tcpdump.org/linktypes.html */ break; case 240: case 241: length = 4; break; case 244: length = 20; break; case 245: length = 20; break; } if (length > 0) { pseudoheader_item = proto_tree_add_item(tree, hf_pcap_pktdata_pseudoheader, tvb, offset, length, ENC_NA); pseudoheader_tree = proto_item_add_subtree(pseudoheader_item, ett_pcap_pktdata_pseudoheader); } switch (*link_type) { case 201: proto_tree_add_item(pseudoheader_tree, hf_pcap_pktdata_pseudoheader_bluetooth_direction, tvb, offset, 4, ENC_BIG_ENDIAN); if (tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN) == 0) pinfo->p2p_dir = P2P_DIR_SENT; else if (tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN) == 1) pinfo->p2p_dir = P2P_DIR_RECV; else pinfo->p2p_dir = P2P_DIR_UNKNOWN; offset += 4; break; default: offset += length; } next_tvb = tvb_new_subset_remaining(tvb, offset); packet_item = proto_tree_add_item(tree, hf_pcap_pktdata_data, tvb, offset, tvb_reported_length(next_tvb), ENC_NA); packet_tree = proto_item_add_subtree(packet_item, ett_pcap_pktdata_data); offset = dissector_try_uint_new(wtap_encap_table, pinfo->phdr->pkt_encap, next_tvb, pinfo, packet_tree, TRUE, NULL); return offset; }
static int dissect_pbb_addressblock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint maxoffset, guint8 addressType, guint8 addressSize) { guint8 addr[MAX_ADDR_SIZE]; guint8 numAddr; guint8 address_flags; guint8 head_length = 0, tail_length = 0; guint block_length = 0, midSize = 0; guint block_index = 0, head_index = 0, tail_index = 0, mid_index = 0, prefix_index = 0; proto_tree *addr_tree = NULL; proto_tree *addrFlags_tree = NULL; proto_tree *addrValue_tree = NULL; proto_item *addr_item = NULL; proto_item *addrFlags_item = NULL; proto_item *addrValue_item = NULL; int i = 0; if (maxoffset - offset < 2) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for minimal addressblock header"); return tvb_reported_length(tvb); } DISSECTOR_ASSERT(addressSize <= MAX_ADDR_SIZE); memset(addr, 0, addressSize); block_length = 2; block_index = offset; midSize = addressSize; numAddr = tvb_get_guint8(tvb, offset++); address_flags = tvb_get_guint8(tvb, offset++); if ((address_flags & ADDR_HASHEAD) != 0) { head_index = offset; if (maxoffset - offset <= 0) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock head"); return tvb_reported_length(tvb); } head_length = tvb_get_guint8(tvb, offset++); if (head_length > addressSize-1) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "address head length is too long"); return tvb_reported_length(tvb); } if (maxoffset - offset < head_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock head"); return tvb_reported_length(tvb); } tvb_memcpy(tvb, addr, offset, head_length); midSize -= head_length; block_length += (head_length+1); offset += head_length; } if ((address_flags & ADDR_HASZEROTAIL) != 0) { tail_index = offset; if (maxoffset - offset <= 0) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock tail"); return tvb_reported_length(tvb); } tail_length = tvb_get_guint8(tvb, offset++); if (tail_length > addressSize-1-head_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "address tail length is too long"); return tvb_reported_length(tvb); } midSize -= tail_length; block_length++; } else if ((address_flags & ADDR_HASFULLTAIL) != 0) { tail_index = offset; if (maxoffset - offset <= 0) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock tail"); return tvb_reported_length(tvb); } tail_length = tvb_get_guint8(tvb, offset++); if (tail_length > addressSize-1-head_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "address tail length is too long"); return tvb_reported_length(tvb); } if (maxoffset - offset < tail_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock tail"); return tvb_reported_length(tvb); } tvb_memcpy(tvb, &addr[addressSize - tail_length], offset, tail_length); midSize -= tail_length; block_length += (tail_length+1); offset += tail_length; } mid_index = offset; block_length += numAddr * midSize; offset += numAddr * midSize; if ((address_flags & ADDR_HASSINGLEPRELEN) != 0) { prefix_index = offset; block_length++; } else if ((address_flags & ADDR_HASMULTIPRELEN) != 0) { prefix_index = offset; block_length += numAddr; } if (maxoffset < block_index + block_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for address block"); return maxoffset; } /* add address tree */ addr_item = proto_tree_add_item(tree, hf_packetbb_addr, tvb, block_index, block_length, ENC_NA); addr_tree = proto_item_add_subtree(addr_item, ett_packetbb_addr); proto_item_append_text(addr_item, " (%d addresses)", numAddr); /* add num-addr */ proto_tree_add_item(addr_tree, hf_packetbb_addr_num, tvb, block_index, 1, ENC_BIG_ENDIAN); /* add flags */ addrFlags_item = proto_tree_add_item(addr_tree, hf_packetbb_addr_flags, tvb, block_index+1, 1, ENC_BIG_ENDIAN); addrFlags_tree = proto_item_add_subtree(addrFlags_item, ett_packetbb_addr_flags); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hashead, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hasfulltail, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_haszerotail, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hassingleprelen, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hasmultiprelen, tvb, block_index+1, 1, ENC_BIG_ENDIAN); if ((address_flags & ADDR_HASHEAD) != 0) { /* add head */ proto_tree_add_item(addr_tree, hf_packetbb_addr_head, tvb, head_index, head_length+1, ENC_NA); } if ((address_flags & ADDR_HASFULLTAIL) != 0) { /* add full tail */ proto_tree_add_item(addr_tree, hf_packetbb_addr_tail, tvb, tail_index, tail_length+1, ENC_NA); } else if ((address_flags & ADDR_HASZEROTAIL) != 0) { /* add zero tail */ proto_tree_add_item(addr_tree, hf_packetbb_addr_tail, tvb, tail_index, 1, ENC_NA); } for (i=0; i<numAddr; i++) { guint32 ipv4 = (addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]; guint8 prefix = addressSize * 8; tvb_memcpy(tvb, &addr[head_length], mid_index + midSize*i, midSize); switch (addressType) { case 0: addrValue_item = proto_tree_add_ipv4(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, ipv4); break; case 1: addrValue_item = proto_tree_add_ipv6(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, (struct e_in6_addr *)addr); break; case 2: addrValue_item = proto_tree_add_ether(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, addr); break; case 3: addrValue_item = proto_tree_add_bytes(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, addr); break; default: break; } addrValue_tree = proto_item_add_subtree(addrValue_item, ett_packetbb_addr_value); proto_tree_add_item(addrValue_tree, hf_packetbb_addr_value_mid, tvb, mid_index + midSize*i, midSize, ENC_NA); if ((address_flags & ADDR_HASSINGLEPRELEN) != 0) { prefix = tvb_get_guint8(tvb, prefix_index); proto_tree_add_item(addrValue_tree, hf_packetbb_addr_value_prefix, tvb, prefix_index, 1, ENC_BIG_ENDIAN); } else if ((address_flags & ADDR_HASMULTIPRELEN) != 0) { prefix = tvb_get_guint8(tvb, prefix_index + i); proto_tree_add_item(addrValue_tree, hf_packetbb_addr_value_prefix, tvb, prefix_index + i, 1, ENC_BIG_ENDIAN); } proto_item_append_text(addrValue_item, "/%d", prefix); } offset = dissect_pbb_tlvblock(tvb, pinfo, addr_tree, block_index + block_length, maxoffset, numAddr); return offset; }
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; } }
guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag) { DISSECTOR_ASSERT( frag ); return frag->len; }
/*--- dissect_q932_ros -----------------------------------------------------*/ static int dissect_q932_ros(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { rose_ctx_tmp = get_rose_ctx(pinfo->private_data); DISSECTOR_ASSERT(rose_ctx_tmp); return dissect_ROS_PDU(tvb, pinfo, tree); }
guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag) { DISSECTOR_ASSERT( frag ); return frag->pdu->pdu_number; }
static void dissect_usb_i1d3_command( tvbuff_t *tvb, packet_info *pinfo, usb_i1d3_conversation_t *conversation, proto_tree *tree) { // Parsing the command code is a bit tricky: if the most significant // byte is non-zero, the command code is the most significant byte, // *and* the next byte is the first byte of the payload. guint32 command_code = tvb_get_ntohs(tvb, 0); guint32 command_code_msb = command_code & 0xff00; gint command_code_length = 2; if (command_code_msb) { command_code = command_code_msb; command_code_length = 1; } proto_item *command_code_item = proto_tree_add_uint( tree, hf_usb_i1d3_command_code, tvb, 0, command_code_length, command_code); usb_i1d3_transaction_t *transaction; if (!PINFO_FD_VISITED(pinfo)) { transaction = usb_i1d3_create_transaction(conversation, pinfo->num); transaction->command_code = command_code; } else { transaction = (usb_i1d3_transaction_t *)wmem_map_lookup( conversation->request_to_transaction, GUINT_TO_POINTER(pinfo->num)); } DISSECTOR_ASSERT(transaction); if (transaction->response != 0) { proto_item *response_item = proto_tree_add_uint( tree, hf_usb_i1d3_response_in, tvb, 0, 0, transaction->response); PROTO_ITEM_SET_GENERATED(response_item); } const gchar *command_code_string = try_val_to_str( command_code, usb_i1d3_command_code_strings); if (command_code_string) { col_set_str(pinfo->cinfo, COL_INFO, command_code_string); } else { expert_add_info(pinfo, command_code_item, &ei_usb_i1d3_unknown_command); col_set_str(pinfo->cinfo, COL_INFO, "Unknown command"); } switch (command_code) { case USB_I1D3_LOCKRESP: { // TODO: verify that the challenge response is correct proto_tree_add_item( tree, hf_usb_i1d3_challenge_response, tvb, 24, 16, ENC_NA); break; } case USB_I1D3_READINTEE: { guint32 offset, length; proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_readintee_offset, tvb, 1, 1, ENC_NA, &offset); proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_readintee_length, tvb, 2, 1, ENC_NA, &length); col_add_fstr(pinfo->cinfo, COL_INFO, "%s (offset: %u, length: %u)", command_code_string, offset, length); if (!PINFO_FD_VISITED(pinfo)) { transaction->offset = offset; transaction->length = length; } break; } case USB_I1D3_READEXTEE: { guint32 offset, length; proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_readextee_offset, tvb, 1, 2, ENC_BIG_ENDIAN, &offset); proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_readextee_length, tvb, 3, 1, ENC_NA, &length); col_add_fstr(pinfo->cinfo, COL_INFO, "%s (offset: %u, length: %u)", command_code_string, offset, length); if (!PINFO_FD_VISITED(pinfo)) { transaction->offset = offset; transaction->length = length; } break; } case USB_I1D3_MEASURE1: { guint32 integration_time; proto_item *integration_time_item = proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_requested_integration_time, tvb, 1, 4, ENC_LITTLE_ENDIAN, &integration_time); double integration_time_seconds = integration_time / USB_I1D3_CLOCK_FREQUENCY; proto_item_append_text( integration_time_item, " [%.6f seconds]", integration_time_seconds); col_add_fstr(pinfo->cinfo, COL_INFO, "Measure for %.6fs", integration_time_seconds); break; } case USB_I1D3_MEASURE2: { proto_item *edge_count_item = proto_tree_add_item( tree, hf_usb_i1d3_requested_edge_count, tvb, 1, 6, ENC_NA); proto_tree *edge_count_tree = proto_item_add_subtree( edge_count_item, ett_usb_i1d3_requested_edge_count); guint32 edge_count_red, edge_count_green, edge_count_blue; proto_tree_add_item_ret_uint( edge_count_tree, hf_usb_i1d3_requested_edge_count_red, tvb, 1, 2, ENC_LITTLE_ENDIAN, &edge_count_red); proto_tree_add_item_ret_uint( edge_count_tree, hf_usb_i1d3_requested_edge_count_green, tvb, 3, 2, ENC_LITTLE_ENDIAN, &edge_count_green); proto_tree_add_item_ret_uint( edge_count_tree, hf_usb_i1d3_requested_edge_count_blue, tvb, 5, 2, ENC_LITTLE_ENDIAN, &edge_count_blue); proto_item_append_text( edge_count_item, ": R%u G%u B%u", edge_count_red, edge_count_green, edge_count_blue); col_add_fstr(pinfo->cinfo, COL_INFO, "Measure R%u G%u B%u edges", edge_count_red, edge_count_green, edge_count_blue); break; } case USB_I1D3_SETLED: { guint32 led_mode, led_offtime, led_ontime, pulse_count; proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_led_mode, tvb, 1, 1, ENC_NA, &led_mode); proto_item *led_offtime_item = proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_led_offtime, tvb, 2, 1, ENC_NA, &led_offtime); double led_offtime_seconds = led_offtime / USB_I1D3_LED_OFFTIME_FACTOR; proto_item_append_text( led_offtime_item, " [%.6f seconds]", led_offtime_seconds); proto_item *led_ontime_item = proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_led_ontime, tvb, 3, 1, ENC_NA, &led_ontime); double led_ontime_seconds = led_ontime / ((led_mode == USB_I1D3_LED_BLINK) ? USB_I1D3_LED_ONTIME_FACTOR : USB_I1D3_LED_ONTIME_FADE_FACTOR); proto_item_append_text( led_ontime_item, " [%.6f seconds]", led_ontime_seconds); proto_item *pulse_count_item = proto_tree_add_item_ret_uint( tree, hf_usb_i1d3_led_pulse_count, tvb, 4, 1, ENC_NA, &pulse_count); if (pulse_count == 0x80) { proto_item_append_text(pulse_count_item, " [infinity]"); col_add_fstr(pinfo->cinfo, COL_INFO, "Pulse LED off (%.6fs) and on (%.6fs%s) " "indefinitely", led_offtime_seconds, led_ontime_seconds, (led_mode == USB_I1D3_LED_BLINK_FADE_ON) ? " fading" : ""); } else { col_add_fstr(pinfo->cinfo, COL_INFO, "Pulse LED off (%.6fs) and on (%.6fs%s) " "%u times", led_offtime_seconds, led_ontime_seconds, (led_mode == USB_I1D3_LED_BLINK_FADE_ON) ? " fading" : "", pulse_count); } } } }
void proto_reg_handoff_gsm_sms_ud(void) { wsp_handle = find_dissector("wsp-cl"); DISSECTOR_ASSERT(wsp_handle); }
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); } }
static void gbl_symbols_array_append(int hash, gchar *symbol) { value_string vs = {hash, symbol}; DISSECTOR_ASSERT(gbl_symbols_array != NULL); g_array_append_val(gbl_symbols_array, vs); }
/* Header */ static void dissect_cpfi_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint32 word1; #if 0 guint32 word2; #endif guint32 tda; guint32 src; guint8 src_instance = 0; guint8 src_board = 0; guint8 src_port = 0; guint32 dst; guint8 dst_instance = 0; guint8 dst_board = 0; guint8 dst_port = 0; proto_tree *extra_tree = NULL; /* add a tree for the header */ if ( tree != NULL) { proto_item *extra_item; extra_item = proto_tree_add_protocol_format(tree, proto_cpfi, tvb, 0, -1, "Header"); extra_tree = proto_item_add_subtree(extra_item, ett_cpfi_header); } /* Extract the common header, and get the bits we need */ word1 = tvb_get_ntohl (tvb, 0); #if 0 word2 = tvb_get_ntohl (tvb, sizeof(word1)); #endif /* Figure out where the frame came from. dstTDA is source of frame! */ tda = (word1 & CPFI_DEST_MASK) >> CPFI_DEST_SHIFT; if ( tda >= FIRST_TIO_CARD_ADDRESS ) { g_strlcpy(src_str, " CPFI", sizeof(src_str)); src = 0; /* Make it smallest */ } else { const guint8 *srcmac; /* Make sure this is an Ethernet address. */ DISSECTOR_ASSERT(pinfo->src.type == AT_ETHER); srcmac = (const guint8 *)pinfo->src.data; src_instance = srcmac[2]-1; src_board = tda >> 4; src_port = tda & 0x0f; src = (1 << 24) + (src_instance << 16) + (src_board << 8) + src_port; g_snprintf(src_str, sizeof(src_str), "%u.%u.%u", src_instance, src_board, src_port); } /* Figure out where the frame is going. srcTDA is destination of frame! */ tda = (word1 & CPFI_SOURCE_MASK) >> CPFI_SOURCE_SHIFT; if ( tda >= FIRST_TIO_CARD_ADDRESS ) { g_strlcpy(dst_str, " CPFI", sizeof(dst_str)); dst = 0; /* Make it smallest */ } else { const guint8 *dstmac; /* Make sure this is an Ethernet address. */ DISSECTOR_ASSERT(pinfo->dst.type == AT_ETHER); dstmac = (const guint8 *)pinfo->dst.data; dst_instance = dstmac[2]-1; dst_board = tda >> 4; dst_port = tda & 0x0f; dst = (1 << 24) + (dst_instance << 16) + (dst_board << 8) + dst_port; g_snprintf(dst_str, sizeof(dst_str), "%u.%u.%u", dst_instance, dst_board, dst_port); } /* Set up the source and destination and arrow per user configuration. */ if ( cpfi_arrow_moves && (dst < src) ) { left = dst_str; arrow = r_to_l_arrow; right = src_str; } else { left = src_str; arrow = l_to_r_arrow; right = dst_str; } if (extra_tree) { proto_item *hidden_item; /* For "real" TDAs (i.e. not for microTDAs), add hidden addresses to allow filtering */ if ( src != 0 ) { hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_instance, tvb, 0, 1, &src_instance); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_src_instance, tvb, 0, 1, &src_instance); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_board, tvb, 0, 1, &src_board); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_src_board, tvb, 0, 1, &src_board); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_port, tvb, 0, 1, &src_port); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_src_port, tvb, 0, 1, &src_port); PROTO_ITEM_SET_HIDDEN(hidden_item); } if ( dst != 0 ) { hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_instance, tvb, 0, 1, &dst_instance); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_dst_instance, tvb, 0, 1, &dst_instance); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_board, tvb, 0, 1, &dst_board); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_dst_board, tvb, 0, 1, &dst_board); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_port, tvb, 0, 1, &dst_port); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_bytes(extra_tree, hf_cpfi_t_dst_port, tvb, 0, 1, &dst_port); PROTO_ITEM_SET_HIDDEN(hidden_item); } /* add word 1 components to the protocol tree */ proto_tree_add_item(extra_tree, hf_cpfi_word_one , tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(extra_tree, hf_cpfi_frame_type, tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(extra_tree, hf_cpfi_source , tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(extra_tree, hf_cpfi_dest , tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(extra_tree, hf_cpfi_SOF_type , tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(extra_tree, hf_cpfi_speed , tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(extra_tree, hf_cpfi_OPM_error , tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(extra_tree, hf_cpfi_from_LCM , tvb, 0, 4, ENC_BIG_ENDIAN); /* add word 2 components to the protocol tree */ proto_tree_add_item(extra_tree, hf_cpfi_word_two , tvb, 4, 4, ENC_BIG_ENDIAN); }; }
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; }
/* Initializes an extended value string. Behaves like a match function to * permit lazy initialization of extended value strings. * - Goes through the val64_string array to determine the fastest possible * access method. * - Verifies that the val64_string contains no NULL string pointers. * - Verifies that the val64_string is terminated by {0, NULL} */ const val64_string * _try_val64_to_str_ext_init(const guint64 val, val64_string_ext *vse) { const val64_string *vs_p = vse->_vs_p; const guint vs_num_entries = vse->_vs_num_entries; /* The matching algorithm used: * VS_SEARCH - slow sequential search (as in a normal value string) * VS_BIN_TREE - log(n)-time binary search, the values must be sorted * VS_INDEX - constant-time index lookup, the values must be contiguous */ enum { VS_SEARCH, VS_BIN_TREE, VS_INDEX } type = VS_INDEX; /* Note: The val64_string 'value' is *unsigned*, but we do a little magic * to help with value strings that have negative values. * * { -3, -2, -1, 0, 1, 2 } * will be treated as "ascending ordered" (although it isn't technically), * thus allowing constant-time index search * * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 } * will both be considered as "out-of-order with gaps", thus falling * back to the slow linear search * * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 } * will be considered "ascending ordered with gaps" thus allowing * a log(n)-time 'binary' search * * If you're confused, think of how negative values are represented, or * google two's complement. */ guint64 prev_value; guint64 first_value; guint i; DISSECTOR_ASSERT((vs_p[vs_num_entries].value == 0) && (vs_p[vs_num_entries].strptr == NULL)); vse->_vs_first_value = vs_p[0].value; first_value = vs_p[0].value; prev_value = first_value; for (i = 0; i < vs_num_entries; i++) { DISSECTOR_ASSERT(vs_p[i].strptr != NULL); if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) { type = VS_BIN_TREE; } /* XXX: Should check for dups ?? */ if (type == VS_BIN_TREE) { if (prev_value > vs_p[i].value) { g_warning("Extended value string '%s' forced to fall back to linear search:\n" " entry %u, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x] < previous entry, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x]", vse->_vs_name, i, vs_p[i].value, vs_p[i].value, prev_value, prev_value); type = VS_SEARCH; break; } if (first_value > vs_p[i].value) { g_warning("Extended value string '%s' forced to fall back to linear search:\n" " entry %u, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x] < first entry, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x]", vse->_vs_name, i, vs_p[i].value, vs_p[i].value, first_value, first_value); type = VS_SEARCH; break; } } prev_value = vs_p[i].value; } switch (type) { case VS_SEARCH: vse->_vs_match2 = _try_val64_to_str_linear; break; case VS_BIN_TREE: vse->_vs_match2 = _try_val64_to_str_bsearch; break; case VS_INDEX: vse->_vs_match2 = _try_val64_to_str_index; break; default: g_assert_not_reached(); break; } return vse->_vs_match2(val, vse); }
static gint dissect_hci_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *ttree = NULL; proto_tree *titem = NULL; proto_item *pitem = NULL; gint offset = 0; usb_conv_info_t *usb_conv_info = (usb_conv_info_t *)data; tvbuff_t *next_tvb = NULL; hci_data_t *hci_data; gint p2p_dir_save; guint32 session_id; fragment_head *reassembled; if (tvb_length_remaining(tvb, offset) <= 0) return 0; titem = proto_tree_add_item(tree, proto_hci_usb, tvb, offset, -1, ENC_NA); ttree = proto_item_add_subtree(titem, ett_hci_usb); col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_USB"); DISSECTOR_ASSERT(usb_conv_info); p2p_dir_save = pinfo->p2p_dir; pinfo->p2p_dir = usb_conv_info->direction; 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; } session_id = usb_conv_info->bus_id << 16 | usb_conv_info->device_address << 8 | ((pinfo->p2p_dir == P2P_DIR_RECV) ? 1 : 0 ) << 7 | usb_conv_info->endpoint; hci_data = (hci_data_t *) wmem_new(wmem_packet_scope(), hci_data_t); hci_data->interface_id = HCI_INTERFACE_USB; hci_data->adapter_id = usb_conv_info->bus_id << 8 | usb_conv_info->device_address; hci_data->chandle_to_bdaddr_table = chandle_to_bdaddr_table; hci_data->bdaddr_to_name_table = bdaddr_to_name_table; hci_data->localhost_bdaddr = localhost_bdaddr; hci_data->localhost_name = localhost_name; pinfo->ptype = PT_BLUETOOTH; next_tvb = tvb_new_subset_remaining(tvb, offset); if (!pinfo->fd->flags.visited && usb_conv_info->endpoint <= 0x02) { fragment_info_t *fragment_info; fragment_info = (fragment_info_t *) wmem_tree_lookup32(fragment_info_table, session_id); if (fragment_info == NULL) { fragment_info = (fragment_info_t *) wmem_new(wmem_file_scope(), fragment_info_t); fragment_info->fragment_id = 0; fragment_info->remaining_length = 0; wmem_tree_insert32(fragment_info_table, session_id, fragment_info); } if (fragment_info->fragment_id == 0) { switch(usb_conv_info->endpoint) { case 0: fragment_info->remaining_length = tvb_get_guint8(tvb, offset + 2) + 3; break; case 1: fragment_info->remaining_length = tvb_get_guint8(tvb, offset + 1) + 2; break; case 2: fragment_info->remaining_length = tvb_get_letohs(tvb, offset + 2) + 4; break; } } fragment_info->remaining_length -= tvb_ensure_length_remaining(tvb, offset); fragment_add_seq_check(&hci_usb_reassembly_table, tvb, offset, pinfo, session_id, NULL, fragment_info->fragment_id, tvb_length_remaining(tvb, offset), (fragment_info->remaining_length == 0) ? FALSE : TRUE); if (fragment_info->remaining_length > 0) fragment_info->fragment_id += 1; else fragment_info->fragment_id = 0; } reassembled = fragment_get_reassembled_id(&hci_usb_reassembly_table, pinfo, session_id); if (reassembled && pinfo->fd->num < reassembled->reassembled_in) { pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_fragment, tvb, offset, -1, ENC_NA); PROTO_ITEM_SET_GENERATED(pitem); col_append_str(pinfo->cinfo, COL_INFO, " Fragment"); } else if (reassembled && pinfo->fd->num == reassembled->reassembled_in) { pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_complete, tvb, offset, -1, ENC_NA); PROTO_ITEM_SET_GENERATED(pitem); if (reassembled->len > tvb_ensure_length_remaining(tvb, offset)) { next_tvb = process_reassembled_data(tvb, 0, pinfo, "Reassembled HCI_USB", reassembled, &hci_usb_msg_frag_items, NULL, ttree); } switch(usb_conv_info->endpoint) { case 0: call_dissector_with_data(bthci_cmd_handle, next_tvb, pinfo, tree, hci_data); break; case 1: call_dissector_with_data(bthci_evt_handle, next_tvb, pinfo, tree, hci_data); break; case 2: call_dissector_with_data(bthci_acl_handle, next_tvb, pinfo, tree, hci_data); break; } } else { pitem = proto_tree_add_item(ttree, hf_bthci_usb_packet_unknown_fragment, tvb, offset, -1, ENC_NA); PROTO_ITEM_SET_GENERATED(pitem); } if (usb_conv_info->endpoint == 0x03) { call_dissector_with_data(bthci_sco_handle, next_tvb, pinfo, tree, hci_data); } else if (usb_conv_info->endpoint > 0x03) { proto_tree_add_item(ttree, hf_bthci_usb_data, tvb, offset, -1, ENC_NA); } offset += tvb_length_remaining(tvb, offset); pinfo->p2p_dir = p2p_dir_save; return offset; }
static int dissect_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *mndp_tree, guint32 offset, guint32 length _U_, const ext_value_string *value_array) { guint32 tlv_type; guint32 tlv_length; proto_item *tlv_item; proto_item *tlv_tree; proto_item *type_item; int type_index; guint32 tlv_end; guint encoding_info; tlv_type = tvb_get_ntohs(tvb, offset); tlv_length = tvb_get_ntohs(tvb, offset + 2); /* DISSECTOR_ASSERT(tlv_length >= 4); */ tlv_item = proto_tree_add_text(mndp_tree, tvb, offset, tlv_length+4, "T %d, L %d: %s", tlv_type, tlv_length, extval_to_str_idx(tlv_type, value_array, NULL, "Unknown")); tlv_tree = proto_item_add_subtree(tlv_item, ett_mndp_tlv_header); type_item = proto_tree_add_item(tlv_tree, hf_mndp_tlv_type, tvb, offset, 2, ENC_BIG_ENDIAN); proto_item_append_text(type_item, " = %s", extval_to_str_idx(tlv_type, value_array, &type_index, "Unknown")); offset += 2; proto_tree_add_item(tlv_tree, hf_mndp_tlv_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* tlv_length -= 4; */ if (tlv_length == 0) return offset; tlv_end = offset + tlv_length; /* Make hf_ handling independent of specialfuncion */ /* FIXME: Properly handle encoding info */ if ( type_index != -1 && !value_array[type_index].specialfunction && value_array[type_index].evs != NULL ) { encoding_info = value_array[type_index].evs ? TRUE : FALSE; } else { encoding_info = FALSE; } if ( type_index != -1 && value_array[type_index].hf_element) { proto_tree_add_item(tlv_tree, *(value_array[type_index].hf_element), tvb, offset, tlv_length, encoding_info); } else { proto_tree_add_item(tlv_tree, hf_mndp_tlv_data, tvb, offset, tlv_length, ENC_NA); } if ( type_index != -1 && value_array[type_index].specialfunction ) { guint32 newoffset; while (offset < tlv_end) { newoffset = value_array[type_index].specialfunction ( tvb, pinfo, tlv_tree, offset, tlv_length, value_array[type_index].evs); DISSECTOR_ASSERT(newoffset > offset); offset = newoffset; } } return tlv_end; }
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->commited) { for ( trxmsg = m->trxs; trxmsg; trxmsg = trxmsg->next) { if (trxmsg->trx && trxmsg->trx->id == t_id) { return trxmsg->trx; } } DISSECTOR_ASSERT_NOT_REACHED(); } else { emem_tree_key_t key[] = { {1,&(m->hi_addr)}, {1,&(m->lo_addr)}, {1,&(t_id)}, {0,NULL} }; trxmsg = se_alloc(sizeof(gcp_trx_msg_t)); t = se_tree_lookup32_array(trxs,key); if (!t) { t = se_alloc(sizeof(gcp_trx_t)); t->initial = m; t->id = t_id; t->type = type; t->pendings = 0; t->error = 0; t->cmds = NULL; se_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 = ep_new(gcp_trx_t); trxmsg = ep_new(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; }
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; }