static void dissect_sap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; int sap_version, is_ipv6, is_del, is_enc, is_comp, addr_len; guint8 vers_flags; guint8 auth_len; guint8 auth_flags; tvbuff_t *next_tvb; proto_item *si, *sif; proto_tree *sap_tree = NULL, *sap_flags_tree; col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAP"); col_clear(pinfo->cinfo, COL_INFO); vers_flags = tvb_get_guint8(tvb, offset); is_ipv6 = vers_flags&MCAST_SAP_BIT_A; is_del = vers_flags&MCAST_SAP_BIT_T; is_enc = vers_flags&MCAST_SAP_BIT_E; is_comp = vers_flags&MCAST_SAP_BIT_C; sap_version = (vers_flags&MCAST_SAP_VERSION_MASK)>>MCAST_SAP_VERSION_SHIFT; addr_len = (is_ipv6) ? (int)sizeof(struct e_in6_addr) : 4; col_add_fstr(pinfo->cinfo, COL_INFO, "%s (v%u)", (is_del) ? "Deletion" : "Announcement", sap_version); if (tree) { si = proto_tree_add_item(tree, proto_sap, tvb, offset, -1, ENC_NA); sap_tree = proto_item_add_subtree(si, ett_sap); sif = proto_tree_add_item(sap_tree, hf_sap_flags, tvb, offset, 1, ENC_NA); sap_flags_tree = proto_item_add_subtree(sif, ett_sap_flags); proto_tree_add_item(sap_flags_tree, hf_sap_flags_v, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_a, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_r, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_t, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_e, tvb, offset, 1, ENC_NA); proto_tree_add_item(sap_flags_tree, hf_sap_flags_c, tvb, offset, 1, ENC_NA); } offset++; auth_len = tvb_get_guint8(tvb, offset); proto_tree_add_item(sap_tree, hf_sap_auth_len, tvb, offset, 1, ENC_NA); offset++; proto_tree_add_item(sap_tree, hf_sap_message_identifier_hash, tvb, offset, 2, ENC_BIG_ENDIAN); offset +=2; if (is_ipv6) proto_tree_add_item(sap_tree, hf_sap_originating_source_ipv6, tvb, offset, addr_len, ENC_NA); else proto_tree_add_item(sap_tree, hf_sap_originating_source_ipv4, tvb, offset, addr_len, ENC_BIG_ENDIAN); offset += addr_len; /* Authentication data lives in its own subtree */ if (auth_len > 0) { guint32 auth_data_len; proto_item *sdi, *sai; proto_tree *sa_tree, *saf_tree; int has_pad; guint8 pad_len = 0; auth_data_len = (guint32)(auth_len * sizeof(guint32)); sdi = proto_tree_add_item(sap_tree, hf_auth_data, tvb, offset, auth_data_len, ENC_NA); sa_tree = proto_item_add_subtree(sdi, ett_sap_auth); auth_flags = tvb_get_guint8(tvb, offset); sai = proto_tree_add_item(sa_tree, hf_auth_flags, tvb, offset, 1, ENC_NA); saf_tree = proto_item_add_subtree(sai, ett_sap_authf); proto_tree_add_item(saf_tree, hf_auth_flags_v, tvb, offset, 1, ENC_NA); proto_tree_add_item(saf_tree, hf_auth_flags_p, tvb, offset, 1, ENC_NA); proto_tree_add_item(saf_tree, hf_auth_flags_t, tvb, offset, 1, ENC_NA); has_pad = auth_flags&MCAST_SAP_AUTH_BIT_P; if (has_pad) { pad_len = tvb_get_guint8(tvb, offset+auth_data_len-1); } if ((int) auth_data_len - pad_len - 1 < 0) { expert_add_info_format(pinfo, sai, &ei_sap_bogus_authentication_or_pad_length, "Bogus authentication length (%d) or pad length (%d)", auth_len, pad_len); return; } proto_tree_add_item(sa_tree, hf_sap_auth_subheader, tvb, offset+1, auth_data_len-pad_len-1, ENC_NA); if (has_pad) { proto_tree_add_item(sa_tree, hf_sap_auth_data_padding_len, tvb, offset+auth_data_len-1, 1, ENC_NA); proto_tree_add_item(sa_tree, hf_sap_auth_data_padding, tvb, offset+auth_data_len-pad_len, pad_len, ENC_NA); } offset += auth_data_len; } if (is_enc || is_comp) { expert_field *mangle; if (is_enc && is_comp) mangle = &ei_sap_compressed_and_encrypted; else if (is_enc) mangle = &ei_sap_encrypted; else mangle = &ei_sap_compressed; proto_tree_add_expert(sap_tree, pinfo, mangle, tvb, offset, -1); return; } if (tree) { /* Do we have the optional payload type aka. MIME content specifier */ if (tvb_strneql(tvb, offset, "v=", strlen("v="))) { gint remaining_len; guint32 pt_len; int pt_string_len; guint8* pt_str; remaining_len = tvb_captured_length_remaining(tvb, offset); if (remaining_len == 0) { /* * "tvb_strneql()" failed because there was no * data left in the packet. * * Set the remaining length to 1, so that * we throw the appropriate exception in * "tvb_get_ptr()", rather than displaying * the payload type. */ remaining_len = 1; } pt_string_len = tvb_strnlen(tvb, offset, remaining_len); if (pt_string_len == -1) { /* * We didn't find a terminating '\0'; run to the * end of the buffer. */ pt_string_len = remaining_len; pt_len = pt_string_len; } else { /* * Include the '\0' in the total item length. */ pt_len = pt_string_len + 1; } pt_str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, pt_string_len, ENC_ASCII); proto_tree_add_string_format_value(sap_tree, hf_sap_payload_type, tvb, offset, pt_len, pt_str, "%.*s", pt_string_len, pt_str); offset += pt_len; } } /* Done with SAP */ next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(sdp_handle, next_tvb, pinfo, tree); }
static guint dissect_eiss_descriptors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { proto_item *pi; proto_tree *sub_tree; guint tag; tag = tvb_get_guint8(tvb, offset); if (0xe0 == tag) { guint total_length; total_length = tvb_get_guint8(tvb, offset+1); pi = proto_tree_add_text(tree, tvb, offset, (2+total_length), "ETV Application Information Descriptor"); sub_tree = proto_item_add_subtree(pi, ett_eiss_desc); proto_tree_add_item(sub_tree, hf_eiss_descriptor_tag, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_descriptor_length, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_aid_app_control_code, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_aid_app_version_major, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_aid_app_version_minor, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_aid_max_proto_version_major, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_aid_max_proto_version_minor, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_aid_test_flag, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_aid_reserved, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; proto_tree_add_item(sub_tree, hf_eiss_aid_priority, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_irl_type, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_eiss_irl_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(sub_tree, hf_eiss_irl_string, tvb, offset, 2, ENC_ASCII|ENC_NA); return (2+total_length); } else if (0xe1 == tag) { pi = proto_tree_add_text(tree, tvb, offset, 6, "ETV Media Time Descriptor"); sub_tree = proto_item_add_subtree(pi, ett_eiss_desc); proto_tree_add_item(sub_tree, hf_eiss_descriptor_tag, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_descriptor_length, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_mtd_time_value, tvb, offset, 4, ENC_BIG_ENDIAN); return 6; } else if (0xe2 == tag) { guint tmp; tvbuff_t *payload; tmp = tvb_get_ntohs(tvb, offset+1); pi = proto_tree_add_text(tree, tvb, offset, (3+tmp), "ETV Stream Event Descriptor"); sub_tree = proto_item_add_subtree(pi, ett_eiss_desc); proto_tree_add_item(sub_tree, hf_eiss_descriptor_tag, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(sub_tree, hf_eiss_sed_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_eiss_sed_descriptor_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(sub_tree, hf_eiss_sed_time_value, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; payload = tvb_new_subset(tvb, offset, tmp-4, tmp-4); call_dissector(data_handle, payload, pinfo, sub_tree); return (3+tmp); } else { proto_tree_add_expert(tree, pinfo, &ei_eiss_unknown_descriptor, tvb, offset, -1); /* skip the rest of the section... for now */ return 1000; } }
static void dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request; proto_tree *ftp_tree; proto_tree *reqresp_tree; proto_item *ti, *hidden_item; gint offset; const guchar *line; guint32 code; gchar code_str[4]; gboolean is_port_request = FALSE; gboolean is_eprt_request = FALSE; gboolean is_pasv_response = FALSE; gboolean is_epasv_response = FALSE; gint next_offset; int linelen; int tokenlen = 0; const guchar *next_token; guint32 pasv_ip; guint32 pasv_offset; guint32 ftp_ip; guint32 ftp_ip_len; guint32 eprt_offset; guint32 eprt_af = 0; guint32 eprt_ip; guint16 eprt_ipv6[8]; guint32 eprt_ip_len = 0; guint16 ftp_port; guint32 ftp_port_len; address ftp_ip_address; gboolean ftp_nat; conversation_t *conversation; ftp_ip_address = pinfo->src; if (pinfo->match_uint == pinfo->destport) is_request = TRUE; else is_request = FALSE; col_set_str(pinfo->cinfo, COL_PROTOCOL, "FTP"); /* * Find the end of the first line. * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, 0, linelen); /* * Put the first line from the buffer into the summary * (but leave out the line terminator). */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "Request" : "Response", format_text(line, linelen)); ti = proto_tree_add_item(tree, proto_ftp, tvb, 0, -1, ENC_NA); ftp_tree = proto_item_add_subtree(ti, ett_ftp); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, is_request); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, is_request == FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); /* Put the line into the protocol tree. */ ti = proto_tree_add_format_text(ftp_tree, tvb, 0, next_offset); reqresp_tree = proto_item_add_subtree(ti, ett_ftp_reqresp); if (is_request) { /* * Extract the first token, and, if there is a first * token, add it as the request. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { proto_tree_add_item(reqresp_tree, hf_ftp_request_command, tvb, 0, tokenlen, ENC_ASCII|ENC_NA); if (strncmp(line, "PORT", tokenlen) == 0) is_port_request = TRUE; /* * EPRT request command, as per RFC 2428 */ else if (strncmp(line, "EPRT", tokenlen) == 0) is_eprt_request = TRUE; } } else { /* * This is a response; the response code is 3 digits, * followed by a space or hyphen, possibly followed by * text. * * If the line doesn't start with 3 digits, it's part of * a continuation. * * XXX - keep track of state in the first pass, and * treat non-continuation lines not beginning with digits * as errors? */ if (linelen >= 3 && g_ascii_isdigit(line[0]) && g_ascii_isdigit(line[1]) && g_ascii_isdigit(line[2])) { /* * One-line reply, or first or last line * of a multi-line reply. */ tvb_get_nstringz0(tvb, 0, sizeof(code_str), code_str); code = (guint32)strtoul(code_str, NULL, 10); proto_tree_add_uint(reqresp_tree, hf_ftp_response_code, tvb, 0, 3, code); /* * See if it's a passive-mode response. * * XXX - does anybody do FOOBAR, as per RFC * 1639, or has that been supplanted by RFC 2428? */ if (code == 227) is_pasv_response = TRUE; /* * Responses to EPSV command, as per RFC 2428 */ if (code == 229) is_epasv_response = TRUE; /* * Skip the 3 digits and, if present, the * space or hyphen. */ if (linelen >= 4) next_token = line + 4; else next_token = line + linelen; } else { /* * Line doesn't start with 3 digits; assume it's * a line in the middle of a multi-line reply. */ next_token = line; } } offset = (gint) (next_token - line); linelen -= (int) (next_token - line); line = next_token; /* * Add the rest of the first line as request or * reply data. */ if (linelen != 0) { if (is_request) { proto_tree_add_item(reqresp_tree, hf_ftp_request_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } else { proto_tree_add_item(reqresp_tree, hf_ftp_response_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } } offset = next_offset; /* * If this is a PORT request or a PASV response, handle it. */ if (is_port_request) { if (parse_port_pasv(line, linelen, &ftp_ip, &ftp_port, &pasv_offset, &ftp_ip_len, &ftp_port_len)) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_active_ip, tvb, pasv_offset + (tokenlen+1) , ftp_ip_len, ftp_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_active_port, tvb, pasv_offset + 1 + (tokenlen+1) + ftp_ip_len, ftp_port_len, ftp_port); set_address(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&ftp_ip); ftp_nat = !addresses_equal(&pinfo->src, &ftp_ip_address); if (ftp_nat) { proto_tree_add_boolean(reqresp_tree, hf_ftp_active_nat, tvb, 0, 0, ftp_nat); } } } if (is_pasv_response) { if (linelen != 0) { /* * This frame contains a PASV response; set up a * conversation for the data. */ if (parse_port_pasv(line, linelen, &pasv_ip, &ftp_port, &pasv_offset, &ftp_ip_len, &ftp_port_len)) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_pasv_ip, tvb, pasv_offset + 4, ftp_ip_len, pasv_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, pasv_offset + 4 + 1 + ftp_ip_len, ftp_port_len, ftp_port); set_address(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&pasv_ip); ftp_nat = !addresses_equal(&pinfo->src, &ftp_ip_address); if (ftp_nat) { proto_tree_add_boolean(reqresp_tree, hf_ftp_pasv_nat, tvb, 0, 0, ftp_nat); } /* * We use "ftp_ip_address", so that if * we're NAT'd we look for the un-NAT'd * connection. * * XXX - should this call to * "find_conversation()" just use * "ftp_ip_address" and "server_port", and * wildcard everything else? */ conversation = find_conversation(pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { /* * XXX - should this call to "conversation_new()" * just use "ftp_ip_address" and "server_port", * and wildcard everything else? * * XXX - what if we did find a conversation? As * we create it only on the first pass through the * packets, if we find one, it's presumably an * unrelated conversation. Should we remove the * old one from the hash table and put this one in * its place? Can the conversation code handle * conversations not in the hash table? Or should * we make conversations support start and end * frames, as circuits do, and treat this as an * indication that one conversation was closed and * a new one was opened? */ conversation = conversation_new( pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } } } if (is_eprt_request) { /* * RFC2428 - sect. 2 * This frame contains a EPRT request; let's dissect it and set up a * conversation for the data connection. */ if (parse_eprt_request(line, linelen, &eprt_af, &eprt_ip, eprt_ipv6, &ftp_port, &eprt_ip_len, &ftp_port_len)) { /* since parse_eprt_request() returned TRUE, we know that we have a valid address family */ eprt_offset = tokenlen + 1 + 1; /* token, space, 1st delimiter */ proto_tree_add_uint(reqresp_tree, hf_ftp_eprt_af, tvb, eprt_offset, 1, eprt_af); eprt_offset += 1 + 1; /* addr family, 2nd delimiter */ if (eprt_af == EPRT_AF_IPv4) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_eprt_ip, tvb, eprt_offset, eprt_ip_len, eprt_ip); set_address(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&eprt_ip); } else if (eprt_af == EPRT_AF_IPv6) { proto_tree_add_ipv6(reqresp_tree, hf_ftp_eprt_ipv6, tvb, eprt_offset, eprt_ip_len, (const struct e_in6_addr *)eprt_ipv6); set_address(&ftp_ip_address, AT_IPv6, 16, eprt_ipv6); } eprt_offset += eprt_ip_len + 1; /* addr, 3rd delimiter */ proto_tree_add_uint(reqresp_tree, hf_ftp_eprt_port, tvb, eprt_offset, ftp_port_len, ftp_port); /* Find/create conversation for data */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &ftp_ip_address, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new( pinfo->fd->num, &pinfo->src, &ftp_ip_address, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } else { proto_tree_add_expert(reqresp_tree, pinfo, &ei_ftp_eprt_args_invalid, tvb, offset - linelen - 1, linelen); } } if (is_epasv_response) { if (linelen != 0) { proto_item *addr_it; /* * RFC2428 - sect. 3 * This frame contains an EPSV response; set up a * conversation for the data. */ if (parse_extended_pasv_response(line, linelen, &ftp_port, &pasv_offset, &ftp_port_len)) { /* Add IP address and port number to tree */ if (ftp_ip_address.type == AT_IPv4) { guint32 addr; memcpy(&addr, ftp_ip_address.data, 4); addr_it = proto_tree_add_ipv4(reqresp_tree, hf_ftp_epsv_ip, tvb, 0, 0, addr); PROTO_ITEM_SET_GENERATED(addr_it); } else if (ftp_ip_address.type == AT_IPv6) { addr_it = proto_tree_add_ipv6(reqresp_tree, hf_ftp_epsv_ipv6, tvb, 0, 0, (const struct e_in6_addr *)ftp_ip_address.data); PROTO_ITEM_SET_GENERATED(addr_it); } proto_tree_add_uint(reqresp_tree, hf_ftp_epsv_port, tvb, pasv_offset + 4, ftp_port_len, ftp_port); /* Find/create conversation for data */ conversation = find_conversation(pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new( pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } else { proto_tree_add_expert(reqresp_tree, pinfo, &ei_ftp_epsv_args_invalid, tvb, offset - linelen - 1, linelen); } } } /* * Show the rest of the request or response as text, * a line at a time. * XXX - only if there's a continuation indicator? */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_format_text(ftp_tree, tvb, offset, next_offset - offset); offset = next_offset; } }
static void dissect_pktap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *pktap_tree = NULL; proto_item *ti = NULL; tvbuff_t *next_tvb; int offset = 0; guint32 pkt_len, rectype, dlt; col_set_str(pinfo->cinfo, COL_PROTOCOL, "PKTAP"); col_clear(pinfo->cinfo, COL_INFO); pkt_len = tvb_get_letohl(tvb, offset); col_add_fstr(pinfo->cinfo, COL_INFO, "PKTAP, %u byte header", pkt_len); /* Dissect the packet */ ti = proto_tree_add_item(tree, proto_pktap, tvb, offset, pkt_len, ENC_NA); pktap_tree = proto_item_add_subtree(ti, ett_pktap); proto_tree_add_item(pktap_tree, hf_pktap_hdrlen, tvb, offset, 4, ENC_LITTLE_ENDIAN); if (pkt_len < MIN_PKTAP_HDR_LEN) { proto_tree_add_expert(tree, pinfo, &ei_pktap_hdrlen_too_short, tvb, offset, 4); return; } offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_rectype, tvb, offset, 4, ENC_LITTLE_ENDIAN); rectype = tvb_get_letohl(tvb, offset); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_dlt, tvb, offset, 4, ENC_LITTLE_ENDIAN); dlt = tvb_get_letohl(tvb, offset); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_ifname, tvb, offset, 24, ENC_ASCII|ENC_NA); offset += 24; proto_tree_add_item(pktap_tree, hf_pktap_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_pfamily, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_llhdrlen, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_lltrlrlen, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_pid, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_cmdname, tvb, offset, 20, ENC_UTF_8|ENC_NA); offset += 20; proto_tree_add_item(pktap_tree, hf_pktap_svc_class, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_iftype, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(pktap_tree, hf_pktap_ifunit, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(pktap_tree, hf_pktap_epid, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(pktap_tree, hf_pktap_ecmdname, tvb, offset, 20, ENC_UTF_8|ENC_NA); /*offset += 20;*/ if (rectype == PKT_REC_PACKET) { next_tvb = tvb_new_subset_remaining(tvb, pkt_len); dissector_try_uint(wtap_encap_dissector_table, wtap_pcap_encap_to_wtap_encap(dlt), next_tvb, pinfo, tree); } }
/* * Dissect DISP PDUs inside a ROS PDUs */ static int dissect_disp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data) { int offset = 0; int old_offset; proto_item *item; proto_tree *tree; struct SESSION_DATA_STRUCTURE* session; int (*disp_dissector)(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_) = NULL; const char *disp_op_name; asn1_ctx_t asn1_ctx; /* do we have operation information from the ROS dissector */ if (data == NULL) return 0; session = (struct SESSION_DATA_STRUCTURE*)data; asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo); asn1_ctx.private_data = session; item = proto_tree_add_item(parent_tree, proto_disp, tvb, 0, -1, ENC_NA); tree = proto_item_add_subtree(item, ett_disp); col_set_str(pinfo->cinfo, COL_PROTOCOL, "DISP"); col_clear(pinfo->cinfo, COL_INFO); switch(session->ros_op & ROS_OP_MASK) { case (ROS_OP_BIND | ROS_OP_ARGUMENT): /* BindInvoke */ disp_dissector = dissect_disp_DSAShadowBindArgument; disp_op_name = "Shadow-Bind-Argument"; break; case (ROS_OP_BIND | ROS_OP_RESULT): /* BindResult */ disp_dissector = dissect_disp_DSAShadowBindResult; disp_op_name = "Shadow-Bind-Result"; break; case (ROS_OP_BIND | ROS_OP_ERROR): /* BindError */ disp_dissector = dissect_disp_DSAShadowBindError; disp_op_name = "Shadow-Bind-Error"; break; case (ROS_OP_INVOKE | ROS_OP_ARGUMENT): /* Invoke Argument */ switch(session->ros_op & ROS_OP_OPCODE_MASK) { case 1: /* requestShadowUpdate */ disp_dissector = dissect_disp_RequestShadowUpdateArgument; disp_op_name = "Request-Shadow-Update-Argument"; break; case 2: /* updateShadow*/ disp_dissector = dissect_disp_UpdateShadowArgument; disp_op_name = "Update-Shadow-Argument"; break; case 3: /* coordinateShadowUpdate */ disp_dissector = dissect_disp_CoordinateShadowUpdateArgument; disp_op_name = "Coordinate-Shadow-Update-Argument"; break; default: proto_tree_add_expert_format(tree, pinfo, &ei_disp_unsupported_opcode, tvb, offset, -1, "Unsupported DISP opcode (%d)", session->ros_op & ROS_OP_OPCODE_MASK); break; } break; case (ROS_OP_INVOKE | ROS_OP_RESULT): /* Return Result */ switch(session->ros_op & ROS_OP_OPCODE_MASK) { case 1: /* requestShadowUpdate */ disp_dissector = dissect_disp_RequestShadowUpdateResult; disp_op_name = "Request-Shadow-Result"; break; case 2: /* updateShadow */ disp_dissector = dissect_disp_UpdateShadowResult; disp_op_name = "Update-Shadow-Result"; break; case 3: /* coordinateShadowUpdate */ disp_dissector = dissect_disp_CoordinateShadowUpdateResult; disp_op_name = "Coordinate-Shadow-Update-Result"; break; default: proto_tree_add_expert_format(tree, pinfo, &ei_disp_unsupported_opcode, tvb, offset, -1, "Unsupported DISP opcode (%d)", session->ros_op & ROS_OP_OPCODE_MASK); break; } break; case (ROS_OP_INVOKE | ROS_OP_ERROR): /* Return Error */ switch(session->ros_op & ROS_OP_OPCODE_MASK) { case 1: /* shadowError */ disp_dissector = dissect_disp_ShadowError; disp_op_name = "Shadow-Error"; break; default: proto_tree_add_expert_format(tree, pinfo, &ei_disp_unsupported_errcode, tvb, offset, -1, "Unsupported DISP errcode (%d)", session->ros_op & ROS_OP_OPCODE_MASK); break; } break; default: proto_tree_add_expert(tree, pinfo, &ei_disp_unsupported_pdu, tvb, offset, -1); return tvb_captured_length(tvb); } if(disp_dissector) { col_set_str(pinfo->cinfo, COL_INFO, disp_op_name); while (tvb_reported_length_remaining(tvb, offset) > 0){ old_offset=offset; offset=(*disp_dissector)(FALSE, tvb, offset, &asn1_ctx, tree, -1); if(offset == old_offset){ proto_tree_add_expert(tree, pinfo, &ei_disp_zero_pdu, tvb, offset, -1); break; } } } return tvb_captured_length(tvb); }
static void dissect_icep_batch_request(tvbuff_t *tvb, guint32 offset, packet_info *pinfo, proto_tree *icep_tree, proto_item* icep_item) { /* p. 613, chapter 23.3.3 * A batch request msg is a "sequence" of batch request * Sequence is Size + elements * * struct BatchRequestData { * Ice::Identity id; * Ice::StringSeq facet; * string operation; * byte mode; * Ice::Context context; * Encapsulation params; * } * * NOTE!!!: * The only real implementation of the Ice protocol puts a 32bit count in front * of a Batch Request, *not* an Ice::Sequence (as the standard says). Basically the * same people wrote both code and standard so I'll follow the code. */ proto_item *ti = NULL; proto_tree *icep_sub_tree = NULL; guint32 num_reqs = 0; guint32 i = 0; gint32 consumed = 0; DBG0("dissect batch request\n"); /* check for first 4 byte */ if ( !tvb_bytes_exist(tvb, offset, 4) ) { expert_add_info_format(pinfo, icep_item, &ei_icep_length, "counter of batch requests missing"); col_append_str(pinfo->cinfo, COL_INFO, " (counter of batch requests missing)"); return; } num_reqs = tvb_get_letohl(tvb, offset); offset += 4; DBG1("batch_requests.count --> %d\n", num_reqs); if ( num_reqs > icep_max_batch_requests ) { expert_add_info_format(pinfo, icep_item, &ei_icep_batch_requests, "too many batch requests (%d)", num_reqs); col_append_fstr(pinfo->cinfo, COL_INFO, " (too many batch requests, %d)", num_reqs); return; } if ( num_reqs == 0 ) { proto_tree_add_expert(icep_tree, pinfo, &ei_icep_empty_batch, tvb, offset, -1); col_append_str(pinfo->cinfo, COL_INFO, " (empty batch requests sequence)"); return; } col_append_str(pinfo->cinfo, COL_INFO, ":"); /* * process requests */ for ( i = 0; i < num_reqs; i++ ) { DBG1("looping through sequence of batch requests, loop #%d\n", i); /* create display subtree for this message type */ icep_sub_tree = proto_tree_add_subtree_format(icep_tree, tvb, offset, -1, ett_icep_msg, &ti, "Batch Request Message Body: #%d", i); if (i != 0) { col_append_str(pinfo->cinfo, COL_INFO, ","); } dissect_icep_request_common(tvb, offset, pinfo, icep_sub_tree, ti, &consumed); if ( consumed == -1 ) return; if ( icep_tree && ti ) proto_item_set_len(ti, consumed); offset += consumed; DBG1("consumed --> %d\n", consumed); } }
static int dissect_pktc_app_specific_data(packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *tvb, int offset, guint8 doi, guint8 kmmid) { int old_offset=offset; proto_tree *tree; proto_tree *engineid_tree = NULL; proto_item *item; proto_item *engineid_item = NULL; guint8 len; item = proto_tree_add_item(parent_tree, hf_pktc_app_spec_data, tvb, offset, -1, ENC_NA); tree = proto_item_add_subtree(item, ett_pktc_app_spec_data); switch(doi){ case DOI_SNMPv3: switch(kmmid){ /* we don't distinguish between manager and agent engineid. feel free to add separation for this if it is imporant enough for you. */ case KMMID_AP_REQUEST: case KMMID_AP_REPLY: /* snmpEngineID Length */ len=tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_pktc_snmpEngineID_len, tvb, offset, 1, len); offset+=1; /* snmpEngineID */ engineid_item = proto_tree_add_item(tree, hf_pktc_snmpEngineID, tvb, offset, len, ENC_NA); engineid_tree = proto_item_add_subtree(engineid_item, ett_pktc_engineid); dissect_snmp_engineid(engineid_tree, pinfo, tvb, offset, len); offset+=len; /* boots */ proto_tree_add_item(tree, hf_pktc_snmpEngineBoots, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; /* time */ proto_tree_add_item(tree, hf_pktc_snmpEngineTime, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; /* usmUserName Length */ len=tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_pktc_usmUserName_len, tvb, offset, 1, len); offset+=1; /* usmUserName */ proto_tree_add_item(tree, hf_pktc_usmUserName, tvb, offset, len, ENC_ASCII|ENC_NA); offset+=len; break; default: proto_tree_add_expert(tree, pinfo, &ei_pktc_unknown_kmmid, tvb, offset, 1); }; break; case DOI_IPSEC: switch(kmmid){ /* we don't distinguish between SPIs for inbound Security Associations of the client (AP-REQ) vs. server (AP-REP, REKEY). Feel free to add separation for this if it is imporant enough for you. */ case KMMID_AP_REQUEST: case KMMID_AP_REPLY: case KMMID_REKEY: /* Security Parameter Index (SPI) */ proto_tree_add_item(tree, hf_pktc_ipsec_spi, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; break; default: proto_tree_add_expert(tree, pinfo, &ei_pktc_unknown_kmmid, tvb, offset, 1); }; break; default: proto_tree_add_expert(tree, pinfo, &ei_pktc_unknown_doi, tvb, offset, 1); } proto_item_set_len(item, offset-old_offset); return offset; }
/* * Dissect X518 PDUs inside a ROS PDUs */ static int dissect_dsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data) { int offset = 0; int old_offset; proto_item *item; proto_tree *tree; struct SESSION_DATA_STRUCTURE* session; int (*dsp_dissector)(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_) = NULL; const char *dsp_op_name; asn1_ctx_t asn1_ctx; /* do we have operation information from the ROS dissector? */ if (data == NULL) return 0; session = (struct SESSION_DATA_STRUCTURE*)data; asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo); item = proto_tree_add_item(parent_tree, proto_dsp, tvb, 0, -1, ENC_NA); tree = proto_item_add_subtree(item, ett_dsp); col_set_str(pinfo->cinfo, COL_PROTOCOL, "DAP"); col_clear(pinfo->cinfo, COL_INFO); asn1_ctx.private_data = session; switch(session->ros_op & ROS_OP_MASK) { case (ROS_OP_BIND | ROS_OP_ARGUMENT): /* BindInvoke */ dsp_dissector = dissect_dsp_DSASystemBindArgument; dsp_op_name = "System-Bind-Argument"; break; case (ROS_OP_BIND | ROS_OP_RESULT): /* BindResult */ dsp_dissector = dissect_dsp_DSASystemBindResult; dsp_op_name = "System-Bind-Result"; break; case (ROS_OP_BIND | ROS_OP_ERROR): /* BindError */ dsp_dissector = dissect_dsp_DSASystemBindError; dsp_op_name = "System-Bind-Error"; break; case (ROS_OP_INVOKE | ROS_OP_ARGUMENT): /* Invoke Argument */ switch(session->ros_op & ROS_OP_OPCODE_MASK) { case 1: /* read */ dsp_dissector = dissect_dsp_ChainedReadArgument; dsp_op_name = "Chained-Read-Argument"; break; case 2: /* compare */ dsp_dissector = dissect_dsp_ChainedCompareArgument; dsp_op_name = "Chained-Compare-Argument"; break; case 3: /* abandon */ dsp_dissector = dissect_dsp_ChainedAbandonArgument; dsp_op_name = "Chained-Abandon-Argument"; break; case 4: /* list */ dsp_dissector = dissect_dsp_ChainedListArgument; dsp_op_name = "Chained-List-Argument"; break; case 5: /* search */ dsp_dissector = dissect_dsp_ChainedSearchArgument; dsp_op_name = "Chained-Search-Argument"; break; case 6: /* addEntry */ dsp_dissector = dissect_dsp_ChainedAddEntryArgument; dsp_op_name = "Chained-Add-Entry-Argument"; break; case 7: /* removeEntry */ dsp_dissector = dissect_dsp_ChainedRemoveEntryArgument; dsp_op_name = "Chained-Remove-Entry-Argument"; break; case 8: /* modifyEntry */ dsp_dissector = dissect_dsp_ChainedModifyEntryArgument; dsp_op_name = "ChainedModify-Entry-Argument"; break; case 9: /* modifyDN */ dsp_dissector = dissect_dsp_ChainedModifyDNArgument; dsp_op_name = "ChainedModify-DN-Argument"; break; default: proto_tree_add_expert_format(tree, pinfo, &ei_dsp_unsupported_opcode, tvb, offset, -1, "Unsupported DSP opcode (%d)", session->ros_op & ROS_OP_OPCODE_MASK); break; } break; case (ROS_OP_INVOKE | ROS_OP_RESULT): /* Return Result */ switch(session->ros_op & ROS_OP_OPCODE_MASK) { case 1: /* read */ dsp_dissector = dissect_dsp_ChainedReadResult; dsp_op_name = "Chained-Read-Result"; break; case 2: /* compare */ dsp_dissector = dissect_dsp_ChainedCompareResult; dsp_op_name = "Chained-Compare-Result"; break; case 3: /* abandon */ dsp_dissector = dissect_dsp_ChainedAbandonResult; dsp_op_name = "Chained-Abandon-Result"; break; case 4: /* list */ dsp_dissector = dissect_dsp_ChainedListResult; dsp_op_name = "Chained-List-Result"; break; case 5: /* search */ dsp_dissector = dissect_dsp_ChainedSearchResult; dsp_op_name = "Chained-Search-Result"; break; case 6: /* addEntry */ dsp_dissector = dissect_dsp_ChainedAddEntryResult; dsp_op_name = "Chained-Add-Entry-Result"; break; case 7: /* removeEntry */ dsp_dissector = dissect_dsp_ChainedRemoveEntryResult; dsp_op_name = "Chained-Remove-Entry-Result"; break; case 8: /* modifyEntry */ dsp_dissector = dissect_dsp_ChainedModifyEntryResult; dsp_op_name = "Chained-Modify-Entry-Result"; break; case 9: /* modifyDN */ dsp_dissector = dissect_dsp_ChainedModifyDNResult; dsp_op_name = "ChainedModify-DN-Result"; break; default: proto_tree_add_expert(tree, pinfo, &ei_dsp_unsupported_opcode, tvb, offset, -1); break; } break; case (ROS_OP_INVOKE | ROS_OP_ERROR): /* Return Error */ switch(session->ros_op & ROS_OP_OPCODE_MASK) { case 1: /* attributeError */ dsp_dissector = dissect_dap_AttributeError; dsp_op_name = "Attribute-Error"; break; case 2: /* nameError */ dsp_dissector = dissect_dap_NameError; dsp_op_name = "Name-Error"; break; case 3: /* serviceError */ dsp_dissector = dissect_dap_ServiceError; dsp_op_name = "Service-Error"; break; case 4: /* referral */ dsp_dissector = dissect_dap_Referral; dsp_op_name = "Referral"; break; case 5: /* abandoned */ dsp_dissector = dissect_dap_Abandoned; dsp_op_name = "Abandoned"; break; case 6: /* securityError */ dsp_dissector = dissect_dap_SecurityError; dsp_op_name = "Security-Error"; break; case 7: /* abandonFailed */ dsp_dissector = dissect_dap_AbandonFailedError; dsp_op_name = "Abandon-Failed-Error"; break; case 8: /* updateError */ dsp_dissector = dissect_dap_UpdateError; dsp_op_name = "Update-Error"; break; case 9: /* DSAReferral */ dsp_dissector = dissect_dsp_DSAReferral; dsp_op_name = "DSA-Referral"; break; default: proto_tree_add_expert(tree, pinfo, &ei_dsp_unsupported_errcode, tvb, offset, -1); break; } break; default: proto_tree_add_expert(tree, pinfo, &ei_dsp_unsupported_pdu, tvb, offset, -1); return tvb_captured_length(tvb); } if(dsp_dissector) { col_set_str(pinfo->cinfo, COL_INFO, dsp_op_name); while (tvb_reported_length_remaining(tvb, offset) > 0){ old_offset=offset; offset=(*dsp_dissector)(FALSE, tvb, offset, &asn1_ctx, tree, -1); if(offset == old_offset){ proto_tree_add_expert(tree, pinfo, &ei_dsp_zero_pdu, tvb, offset, -1); break; } } } return tvb_captured_length(tvb); }
/* * Process a multipart body-part: * MIME-part-headers [ line-end *OCTET ] * line-end dashed-boundary transport-padding line-end * * If applicable, call a media subdissector. * * Return the offset to the start of the next body-part. */ static gint process_body_part(proto_tree *tree, tvbuff_t *tvb, multipart_info_t *m_info, packet_info *pinfo, gint start, gint idx, gboolean *last_boundary) { proto_tree *subtree; proto_item *ti; gint offset = start, next_offset = 0; char *parameters = NULL; gint body_start, boundary_start, boundary_line_len; gchar *content_type_str = NULL; gchar *content_encoding_str = NULL; char *filename = NULL; char *mimetypename = NULL; int len = 0; gboolean last_field = FALSE; gboolean is_raw_data = FALSE; const guint8 *boundary = (guint8 *)m_info->boundary; gint boundary_len = m_info->boundary_length; ti = proto_tree_add_item(tree, hf_multipart_part, tvb, start, 0, ENC_ASCII|ENC_NA); subtree = proto_item_add_subtree(ti, ett_multipart_body); /* find the next boundary to find the end of this body part */ boundary_start = find_next_boundary(tvb, offset, boundary, boundary_len, &boundary_line_len, last_boundary); if (boundary_start <= 0) { return -1; } /* * Process the MIME-part-headers */ while (!last_field) { gint colon_offset; char *hdr_str; char *header_str; /* Look for the end of the header (denoted by cr) * 3:d argument to imf_find_field_end() maxlen; must be last offset in the tvb. */ next_offset = imf_find_field_end(tvb, offset, tvb_reported_length_remaining(tvb, offset)+offset, &last_field); /* the following should never happen */ /* If cr not found, won't have advanced - get out to avoid infinite loop! */ /* if (next_offset == offset) { break; } */ if (last_field && (next_offset+2) <= boundary_start) { /* Add the extra CRLF of the last field */ next_offset += 2; } else if((next_offset-2) == boundary_start) { /* if CRLF is the start of next boundary it belongs to the boundary and not the field, so it's the last field without CRLF */ last_field = TRUE; next_offset -= 2; } else if (next_offset > boundary_start) { /* if there is no CRLF between last field and next boundary - trim it! */ next_offset = boundary_start; } hdr_str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, next_offset - offset, ENC_ASCII); header_str = unfold_and_compact_mime_header(hdr_str, &colon_offset); if (colon_offset <= 0) { /* if there is no colon it's no header, so break and add complete line to the body */ next_offset = offset; break; } else { gint hf_index; /* Split header name from header value */ header_str[colon_offset] = '\0'; hf_index = is_known_multipart_header(header_str, colon_offset); if (hf_index == -1) { if(isprint_string(hdr_str)) { proto_tree_add_format_text(subtree, tvb, offset, next_offset - offset); } else { /* if the header name is unkown and not printable, break and add complete line to the body */ next_offset = offset; break; } } else { char *value_str = header_str + colon_offset + 1; proto_tree_add_string_format(subtree, hf_header_array[hf_index], tvb, offset, next_offset - offset, (const char *)value_str, "%s", tvb_format_text(tvb, offset, next_offset - offset)); switch (hf_index) { case POS_ORIGINALCONTENT: { gint semicolon_offset; /* The Content-Type starts at colon_offset + 1 or after the type parameter */ char* type_str = find_parameter(value_str, "type=", NULL); if(type_str != NULL) { value_str = type_str; } semicolon_offset = index_of_char( value_str, ';'); if (semicolon_offset > 0) { value_str[semicolon_offset] = '\0'; m_info->orig_parameters = wmem_strdup(wmem_packet_scope(), value_str + semicolon_offset + 1); } m_info->orig_content_type = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); } break; case POS_CONTENT_TYPE: { /* The Content-Type starts at colon_offset + 1 */ gint semicolon_offset = index_of_char( value_str, ';'); if (semicolon_offset > 0) { value_str[semicolon_offset] = '\0'; parameters = wmem_strdup(wmem_packet_scope(), value_str + semicolon_offset + 1); } else { parameters = NULL; } content_type_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); /* Show content-type in root 'part' label */ proto_item_append_text(ti, " (%s)", content_type_str); /* find the "name" parameter in case we don't find a content disposition "filename" */ if((mimetypename = find_parameter(parameters, "name=", &len)) != NULL) { mimetypename = g_strndup(mimetypename, len); } if(strncmp(content_type_str, "application/octet-stream", sizeof("application/octet-stream")-1) == 0) { is_raw_data = TRUE; } /* there are only 2 body parts possible and each part has specific content types */ if(m_info->protocol && idx == 0 && (is_raw_data || g_ascii_strncasecmp(content_type_str, m_info->protocol, strlen(m_info->protocol)) != 0)) { return -1; } } break; case POS_CONTENT_TRANSFER_ENCODING: { /* The Content-Transferring starts at colon_offset + 1 */ gint cr_offset = index_of_char(value_str, '\r'); if (cr_offset > 0) { value_str[cr_offset] = '\0'; } content_encoding_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); } break; case POS_CONTENT_DISPOSITION: { /* find the "filename" parameter */ if((filename = find_parameter(value_str, "filename=", &len)) != NULL) { filename = g_strndup(filename, len); } } break; default: break; } } } offset = next_offset; } body_start = next_offset; /* * Process the body */ { gint body_len = boundary_start - body_start; tvbuff_t *tmp_tvb = tvb_new_subset_length(tvb, body_start, body_len); /* if multipart subtype is encrypted the protcol string was set */ /* see: https://msdn.microsoft.com/en-us/library/cc251581.aspx */ /* there are only 2 body parts possible and each part has specific content types */ if(m_info->protocol && idx == 1 && is_raw_data) { gssapi_encrypt_info_t encrypt; memset(&encrypt, 0, sizeof(encrypt)); encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL; dissect_kerberos_encrypted_message(tmp_tvb, pinfo, subtree, &encrypt); if(encrypt.gssapi_decrypted_tvb) { tmp_tvb = encrypt.gssapi_decrypted_tvb; is_raw_data = FALSE; content_type_str = m_info->orig_content_type; parameters = m_info->orig_parameters; } else if(encrypt.gssapi_encrypted_tvb) { tmp_tvb = encrypt.gssapi_encrypted_tvb; proto_tree_add_expert(tree, pinfo, &ei_multipart_decryption_not_possible, tmp_tvb, 0, -1); } } if (!is_raw_data && content_type_str) { /* * subdissection */ gboolean dissected; /* * Try and remove any content transfer encoding so that each sub-dissector * doesn't have to do it itself * */ if(content_encoding_str && remove_base64_encoding) { if(!g_ascii_strncasecmp(content_encoding_str, "base64", 6)) tmp_tvb = base64_decode(pinfo, tmp_tvb, filename ? filename : (mimetypename ? mimetypename : content_type_str)); } /* * First try the dedicated multipart dissector table */ dissected = dissector_try_string(multipart_media_subdissector_table, content_type_str, tmp_tvb, pinfo, subtree, parameters); if (! dissected) { /* * Fall back to the default media dissector table */ dissected = dissector_try_string(media_type_dissector_table, content_type_str, tmp_tvb, pinfo, subtree, parameters); } if (! dissected) { const char *save_match_string = pinfo->match_string; pinfo->match_string = content_type_str; call_dissector_with_data(media_handle, tmp_tvb, pinfo, subtree, parameters); pinfo->match_string = save_match_string; } parameters = NULL; /* Shares same memory as content_type_str */ } else { call_dissector(data_handle, tmp_tvb, pinfo, subtree); } proto_item_set_len(ti, boundary_start - start); if (*last_boundary == TRUE) { proto_tree_add_item(tree, hf_multipart_last_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII); } else { proto_tree_add_item(tree, hf_multipart_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII); } g_free(filename); g_free(mimetypename); return boundary_start + boundary_line_len; } }
static void dissect_ath(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; /* various lengths as reported in the packet itself */ guint8 hlen = 0; gint32 clen = 0; gint32 dlen = 0; gint32 plen = 0; /* detect the Tribes (Tomcat) version */ gint tribes_version_mark; /* store the info */ const gchar *info_srcaddr = ""; const gchar *info_domain = ""; const gchar *info_command = ""; proto_item *ti, *hlen_item; proto_tree *ath_tree; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATH"); /* Clear out stuff in the info column */ col_clear(pinfo->cinfo,COL_INFO); ti = proto_tree_add_item(tree, proto_ath, tvb, 0, -1, ENC_NA); ath_tree = proto_item_add_subtree(ti, ett_ath); /* Determine the Tribes version, which means determining the Tomcat version. * There are 2 versions : one for Tomcat 6, and one for Tomcat 7/8 * We know that Tomcat 6 packets end with "-E" (Ox2d 0x45 or 11589 in decimal) * and Tomcat 7/8 packets end with "Ox01 0x00" (256 in decimal) * This is why we read these 2 last bytes of the packet */ tribes_version_mark = tvb_get_ntohs(tvb, tvb_reported_length(tvb) - 2); /* dissecting a Tomcat 6 packet */ if (tribes_version_mark == 11589) { /* "-E" */ /* BEGIN */ proto_tree_add_item(ath_tree, hf_ath_begin, tvb, offset, 8, ENC_ASCII|ENC_NA); offset += 8; /* LENGTH */ proto_tree_add_item(ath_tree, hf_ath_length, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* ALIVE TIME */ proto_tree_add_item(ath_tree, hf_ath_alive, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8; /* PORT */ proto_tree_add_item(ath_tree, hf_ath_port, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* SECURE PORT */ proto_tree_add_item(ath_tree, hf_ath_sport, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* HOST LENGTH */ hlen_item = proto_tree_add_item(ath_tree, hf_ath_hlen, tvb, offset, 1, ENC_BIG_ENDIAN); hlen = tvb_get_guint8(tvb, offset); offset += 1; /* HOST */ if (hlen == 4) { proto_tree_add_item(ath_tree, hf_ath_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN); info_srcaddr = tvb_ip_to_str(tvb, offset); } else if (hlen == 6) { proto_tree_add_item(ath_tree, hf_ath_ipv6, tvb, offset, 6, ENC_NA); info_srcaddr = tvb_ip6_to_str(tvb, offset); } else { expert_add_info(pinfo, hlen_item, &ei_ath_hlen_invalid); } offset += hlen; /* COMMAND LENGTH */ proto_tree_add_item_ret_int(ath_tree, hf_ath_clen, tvb, offset, 4, ENC_BIG_ENDIAN, &clen); offset += 4; /* COMMAND */ proto_tree_add_item(ath_tree, hf_ath_comm, tvb, offset, clen, ENC_ASCII|ENC_NA); if (clen != -1) info_command = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, clen, ENC_ASCII); offset += clen; /* DOMAIN LENGTH */ proto_tree_add_item_ret_int(ath_tree, hf_ath_dlen, tvb, offset, 4, ENC_BIG_ENDIAN, &dlen); offset += 4; /* DOMAIN */ proto_tree_add_item(ath_tree, hf_ath_domain, tvb, offset, dlen, ENC_ASCII|ENC_NA); if (dlen != 0) info_domain = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, dlen, ENC_ASCII); offset += dlen; /* UNIQUEID */ proto_tree_add_item(ath_tree, hf_ath_unique, tvb, offset, 16, ENC_NA); offset += 16; /* PAYLOAD LENGTH */ proto_tree_add_item_ret_int(ath_tree, hf_ath_plen, tvb, offset, 4, ENC_BIG_ENDIAN, &plen); offset += 4; /* PAYLOAD */ proto_tree_add_item(ath_tree, hf_ath_payload, tvb, offset, plen, ENC_ASCII|ENC_NA); offset += plen; /* END */ proto_tree_add_item(ath_tree, hf_ath_end, tvb, offset, 8, ENC_ASCII|ENC_NA); } /* dissecting a Tomcat 7/8 packet */ else if (tribes_version_mark == 256) { /* BEGIN */ proto_tree_add_item(ath_tree, hf_ath_begin, tvb, offset, 8, ENC_ASCII|ENC_NA); offset += 8; proto_tree_add_item(ath_tree, hf_ath_padding, tvb, offset, 2, ENC_ASCII|ENC_NA); offset += 2; /* LENGTH */ proto_tree_add_item(ath_tree, hf_ath_length, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* ALIVE TIME */ proto_tree_add_item(ath_tree, hf_ath_alive, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8; /* PORT */ proto_tree_add_item(ath_tree, hf_ath_port, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* SECURE PORT */ proto_tree_add_item(ath_tree, hf_ath_sport, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* UDP PORT, only in Tomcat 7/8 */ proto_tree_add_item(ath_tree, hf_ath_uport, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* HOST LENGTH */ hlen_item = proto_tree_add_item(ath_tree, hf_ath_hlen, tvb, offset, 1, ENC_BIG_ENDIAN); hlen = tvb_get_guint8(tvb, offset); offset += 1; /* HOST */ if (hlen == 4) { proto_tree_add_item(ath_tree, hf_ath_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN); info_srcaddr = tvb_ip_to_str(tvb, offset); } else if (hlen == 6) { proto_tree_add_item(ath_tree, hf_ath_ipv6, tvb, offset, 6, ENC_NA); info_srcaddr = tvb_ip6_to_str(tvb, offset); } else { expert_add_info(pinfo, hlen_item, &ei_ath_hlen_invalid); } offset += hlen; /* COMMAND LENGTH */ proto_tree_add_item_ret_int(ath_tree, hf_ath_clen, tvb, offset, 4, ENC_BIG_ENDIAN, &clen); offset += 4; /* COMMAND */ proto_tree_add_item(ath_tree, hf_ath_comm, tvb, offset, clen, ENC_ASCII|ENC_NA); if (clen != -1) info_command = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, clen, ENC_ASCII); offset += clen; /* DOMAIN LENGTH */ proto_tree_add_item_ret_int(ath_tree, hf_ath_dlen, tvb, offset, 4, ENC_BIG_ENDIAN, &dlen); offset += 4; /* DOMAIN */ proto_tree_add_item(ath_tree, hf_ath_domain, tvb, offset, dlen, ENC_ASCII|ENC_NA); if (dlen != 0) info_domain = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, dlen, ENC_ASCII); offset += dlen; /* UNIQUEID */ proto_tree_add_item(ath_tree, hf_ath_unique, tvb, offset, 16, ENC_NA); offset += 16; /* PAYLOAD LENGTH */ proto_tree_add_item_ret_int(ath_tree, hf_ath_plen, tvb, offset, 4, ENC_BIG_ENDIAN, &plen); offset += 4; /* PAYLOAD */ proto_tree_add_item(ath_tree, hf_ath_payload, tvb, offset, plen, ENC_ASCII|ENC_NA); offset += plen; /* END */ proto_tree_add_item(ath_tree, hf_ath_end, tvb, offset, 8, ENC_ASCII|ENC_NA); } else { proto_tree_add_expert(tree, pinfo, &ei_ath_hmark_invalid, tvb, offset, -1); return; } /* set the INFO column, and we're done ! */ if (strcmp(info_command, "") != 0) { if (strcmp(info_command, "BABY-ALEX") == 0) { if (strcmp(info_domain, "") != 0) { col_append_fstr(pinfo->cinfo, COL_INFO, "%s is leaving domain %s", info_srcaddr, info_domain); } else { col_append_fstr(pinfo->cinfo, COL_INFO, "%s is leaving default domain", info_srcaddr); } } else { if (strcmp(info_domain, "") != 0) { col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to domain %s", info_srcaddr, info_domain); } else { col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to default domain", info_srcaddr); } } } else { if (strcmp(info_domain, "") != 0) { col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to domain %s", info_srcaddr, info_domain); } else { col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to default domain", info_srcaddr); } } }
static gint dissect_hci_mon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_tree *hci_mon_item; proto_item *hci_mon_tree; proto_item *sub_item; gint offset = 0; guint16 opcode; guint16 adapter_id; bluetooth_data_t *bluetooth_data; tvbuff_t *next_tvb; guint32 *adapter_disconnect_in_frame; wmem_tree_t *subtree; wmem_tree_key_t key[4]; guint32 k_interface_id; guint32 k_adapter_id; guint32 k_frame_number; bluetooth_data = (bluetooth_data_t *) data; DISSECTOR_ASSERT(bluetooth_data->previous_protocol_data_type == BT_PD_BTMON); adapter_id = bluetooth_data->previous_protocol_data.btmon->adapter_id; opcode = bluetooth_data->previous_protocol_data.btmon->opcode; if (opcode == 0x00 || opcode == 0x01) pinfo->p2p_dir = P2P_DIR_RECV; else if (opcode % 2) pinfo->p2p_dir = P2P_DIR_RECV; else pinfo->p2p_dir = P2P_DIR_SENT; hci_mon_item = proto_tree_add_item(tree, proto_hci_mon, tvb, offset, tvb_captured_length(tvb), ENC_NA); hci_mon_tree = proto_item_add_subtree(hci_mon_item, ett_hci_mon); col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_MON"); if (opcode == 0x00 || opcode == 0x01) col_set_str(pinfo->cinfo, COL_INFO, "Info "); else switch (pinfo->p2p_dir) { case P2P_DIR_SENT: col_set_str(pinfo->cinfo, COL_INFO, "Sent "); break; case P2P_DIR_RECV: col_set_str(pinfo->cinfo, COL_INFO, "Rcvd "); break; default: col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection "); break; } sub_item = proto_tree_add_uint(hci_mon_tree, hf_adapter_id, tvb, offset, 0, adapter_id); PROTO_ITEM_SET_GENERATED(sub_item); sub_item = proto_tree_add_uint(hci_mon_tree, hf_opcode, tvb, offset, 0, opcode); PROTO_ITEM_SET_GENERATED(sub_item); col_append_fstr(pinfo->cinfo, COL_INFO, "Adapter Id: %u, Opcode: %s", adapter_id, val_to_str_ext_const(opcode, &hci_mon_opcode_vals_ext, "Unknown")); bluetooth_data->adapter_id = adapter_id; k_interface_id = bluetooth_data->interface_id; k_adapter_id = adapter_id; k_frame_number = pinfo->num; key[0].length = 1; key[0].key = &k_interface_id; key[1].length = 1; key[1].key = &k_adapter_id; if (!pinfo->fd->flags.visited && opcode == 0x01) { /* Delete Index */ guint32 *disconnect_in_frame; key[2].length = 1; key[2].key = &k_frame_number; key[3].length = 0; key[3].key = NULL; disconnect_in_frame = wmem_new(wmem_file_scope(), guint32); if (disconnect_in_frame) { *disconnect_in_frame = pinfo->num; wmem_tree_insert32_array(adapter_to_disconnect_in_frame, key, disconnect_in_frame); } } key[2].length = 0; key[2].key = NULL; subtree = (wmem_tree_t *) wmem_tree_lookup32_array(adapter_to_disconnect_in_frame, key); adapter_disconnect_in_frame = (subtree) ? (guint32 *) wmem_tree_lookup32_le(subtree, k_frame_number) : NULL; if (adapter_disconnect_in_frame) { bluetooth_data->adapter_disconnect_in_frame = adapter_disconnect_in_frame; } else { bluetooth_data->adapter_disconnect_in_frame = &max_disconnect_in_frame; } pinfo->ptype = PT_BLUETOOTH; next_tvb = tvb_new_subset_remaining(tvb, offset); switch(opcode) { case 0x00: /* New Index */ proto_tree_add_item(hci_mon_tree, hf_bus, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(hci_mon_tree, hf_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; offset = dissect_bd_addr(hf_bd_addr, pinfo, hci_mon_tree, tvb, offset, TRUE, bluetooth_data->interface_id, bluetooth_data->adapter_id, NULL); proto_tree_add_item(hci_mon_tree, hf_name, tvb, offset, 8, ENC_NA | ENC_ASCII); offset += 8; break; case 0x01: /* Delete Index */ /* No parameters */ break; case 0x02: /* HCI Command Packet */ call_dissector_with_data(bthci_cmd_handle, next_tvb, pinfo, tree, bluetooth_data); offset = tvb_reported_length(tvb); break; case 0x03: /* HCI Event Packet */ call_dissector_with_data(bthci_evt_handle, next_tvb, pinfo, tree, bluetooth_data); offset = tvb_reported_length(tvb); break; case 0x04: /* ACL Tx Packet */ case 0x05: /* ACL Rx Packet */ call_dissector_with_data(bthci_acl_handle, next_tvb, pinfo, tree, bluetooth_data); offset = tvb_reported_length(tvb); break; case 0x06: /* SCO Tx Packet */ case 0x07: /* SCO Rx Packet */ call_dissector_with_data(bthci_sco_handle, next_tvb, pinfo, tree, bluetooth_data); offset = tvb_reported_length(tvb); break; } if (tvb_reported_length_remaining(tvb, offset) > 0) { proto_tree_add_expert(hci_mon_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset)); offset = tvb_reported_length(tvb); } /* NOTE: Oops... HCI_MON have special packet with length 0, but there is a pseudo-header with certain infos, mark it as dissected */ if (opcode == 0x01) return 1; return offset; }
/* * Dissect P1 PDUs inside a PPDU. */ static int dissect_p1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data) { int offset = 0; int old_offset; proto_item *item; proto_tree *tree; struct SESSION_DATA_STRUCTURE* session; int (*p1_dissector)(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, asn1_ctx_t *actx _U_, proto_tree *tree, int hf_index _U_) = NULL; const char *p1_op_name; int hf_p1_index = -1; asn1_ctx_t asn1_ctx; asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo); /* do we have operation information from the ROS dissector? */ if (data == NULL) return 0; session = (struct SESSION_DATA_STRUCTURE*)data; /* save parent_tree so subdissectors can create new top nodes */ p1_initialize_content_globals (&asn1_ctx, parent_tree, TRUE); asn1_ctx.private_data = session; item = proto_tree_add_item(parent_tree, proto_p1, tvb, 0, -1, ENC_NA); tree = proto_item_add_subtree(item, ett_p1); col_set_str(pinfo->cinfo, COL_PROTOCOL, "P1"); col_clear(pinfo->cinfo, COL_INFO); switch(session->ros_op & ROS_OP_MASK) { case (ROS_OP_BIND | ROS_OP_ARGUMENT): /* BindInvoke */ p1_dissector = dissect_p1_MTABindArgument; p1_op_name = "Bind-Argument"; hf_p1_index = hf_p1_MTABindArgument_PDU; break; case (ROS_OP_BIND | ROS_OP_RESULT): /* BindResult */ p1_dissector = dissect_p1_MTABindResult; p1_op_name = "Bind-Result"; hf_p1_index = hf_p1_MTABindResult_PDU; break; case (ROS_OP_BIND | ROS_OP_ERROR): /* BindError */ p1_dissector = dissect_p1_MTABindError; p1_op_name = "Bind-Error"; hf_p1_index = hf_p1_MTABindError_PDU; break; case (ROS_OP_INVOKE | ROS_OP_ARGUMENT): /* Invoke Argument */ p1_dissector = dissect_p1_MTS_APDU; p1_op_name = "Transfer"; hf_p1_index = hf_p1_MTS_APDU_PDU; break; default: proto_tree_add_expert(tree, pinfo, &ei_p1_unsupported_pdu, tvb, offset, -1); return tvb_captured_length(tvb); } col_set_str(pinfo->cinfo, COL_INFO, p1_op_name); while (tvb_reported_length_remaining(tvb, offset) > 0){ old_offset=offset; offset=(*p1_dissector)(FALSE, tvb, offset, &asn1_ctx , tree, hf_p1_index); if(offset == old_offset){ proto_tree_add_expert(tree, pinfo, &ei_p1_zero_pdu, tvb, offset, -1); break; } } p1_initialize_content_globals (&asn1_ctx, NULL, FALSE); return tvb_captured_length(tvb); }
/*--- dissect_q932_facility_ie -------------------------------------------------------*/ static void dissect_q932_facility_ie(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int length) { gint8 appclass; gboolean pc; gint32 tag; guint32 len; int hoffset, eoffset; int ie_end; tvbuff_t *next_tvb; ie_end = offset + length; proto_tree_add_item(tree, hf_q932_pp, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; while (offset < ie_end) { hoffset = offset; offset = get_ber_identifier(tvb, offset, &appclass, &pc, &tag); offset = get_ber_length(tvb, offset, &len, NULL); eoffset = offset + len; next_tvb = tvb_new_subset_length(tvb, hoffset, eoffset - hoffset); switch (appclass) { case BER_CLASS_CON: switch (tag) { case 10 : /* Network Facility Extension */ dissect_NetworkFacilityExtension_PDU(next_tvb, pinfo, tree, NULL); break; case 18 : /* Network Protocol Profile */ dissect_NetworkProtocolProfile_PDU(next_tvb, pinfo, tree, NULL); break; case 11 : /* Interpretation Component */ dissect_InterpretationComponent_PDU(next_tvb, pinfo, tree, NULL); break; /* ROSE APDU */ case 1 : /* invoke */ case 2 : /* returnResult */ case 3 : /* returnError */ case 4 : /* reject */ q932_rose_ctx.apdu_depth = 1; call_dissector_with_data(q932_ros_handle, next_tvb, pinfo, tree, &q932_rose_ctx); break; /* DSE APDU */ case 12 : /* begin */ case 14 : /* end */ case 15 : /* continue */ case 17 : /* abort */ offset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL); offset = dissect_ber_length(pinfo, tree, tvb, offset, NULL, NULL); proto_tree_add_expert(tree, pinfo, &ei_q932_dse_not_supported, tvb, offset, len); break; default: offset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL); offset = dissect_ber_length(pinfo, tree, tvb, offset, NULL, NULL); proto_tree_add_expert(tree, pinfo, &ei_q932_unknown_component, tvb, offset, len); } break; case BER_CLASS_APP: switch (tag) { /* ACSE APDU */ case 0 : /* aarq */ case 1 : /* aare */ case 2 : /* rlrq */ case 3 : /* rlre */ case 4 : /* abrt */ offset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL); offset = dissect_ber_length(pinfo, tree, tvb, offset, NULL, NULL); proto_tree_add_expert(tree, pinfo, &ei_q932_acse_not_supported, tvb, offset, len); break; default: offset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL); offset = dissect_ber_length(pinfo, tree, tvb, offset, NULL, NULL); proto_tree_add_expert(tree, pinfo, &ei_q932_unknown_component, tvb, offset, len); } break; default: offset = dissect_ber_identifier(pinfo, tree, tvb, hoffset, NULL, NULL, NULL); offset = dissect_ber_length(pinfo, tree, tvb, offset, NULL, NULL); proto_tree_add_expert(tree, pinfo, &ei_q932_unknown_component, tvb, offset, len); } offset = eoffset; } }
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->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; }
/* 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); }
/* * Call this method to actually dissect the multipart body. * NOTE - Only do so if a boundary string has been found! */ static int dissect_multipart(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { proto_tree *subtree; proto_item *ti; proto_item *type_ti; multipart_info_t *m_info = get_multipart_info(pinfo, (const char*)data); gint header_start = 0; gint body_index = 0; gboolean last_boundary = FALSE; if (m_info == NULL) { /* * We can't get the required multipart information */ proto_tree_add_expert(tree, pinfo, &ei_multipart_no_required_parameter, tvb, 0, -1); call_dissector(data_handle, tvb, pinfo, tree); return tvb_reported_length(tvb); } /* Clean up the memory if an exception is thrown */ /* CLEANUP_PUSH(cleanup_multipart_info, m_info); */ /* Add stuff to the protocol tree */ ti = proto_tree_add_item(tree, proto_multipart, tvb, 0, -1, ENC_NA); subtree = proto_item_add_subtree(ti, ett_multipart); proto_item_append_text(ti, ", Type: %s, Boundary: \"%s\"", m_info->type, m_info->boundary); /* Show multi-part type as a generated field */ type_ti = proto_tree_add_string(subtree, hf_multipart_type, tvb, 0, 0, pinfo->match_string); PROTO_ITEM_SET_GENERATED(type_ti); /* * Make no entries in Protocol column and Info column on summary display, * but stop sub-dissectors from clearing entered text in summary display. */ col_set_fence(pinfo->cinfo, COL_INFO); /* * Process the multipart preamble */ header_start = process_preamble(subtree, tvb, m_info, &last_boundary); if (header_start == -1) { call_dissector(data_handle, tvb, pinfo, subtree); /* Clean up the dynamically allocated memory */ cleanup_multipart_info(m_info); return tvb_reported_length(tvb); } /* * Process the encapsulated bodies */ while (last_boundary == FALSE) { header_start = process_body_part(subtree, tvb, m_info, pinfo, header_start, body_index++, &last_boundary); if (header_start == -1) { /* Clean up the dynamically allocated memory */ cleanup_multipart_info(m_info); return tvb_reported_length(tvb); } } /* * Process the multipart trailer */ if (tvb_reported_length_remaining(tvb, header_start) > 0) { proto_tree_add_item(subtree, hf_multipart_trailer, tvb, header_start, -1, ENC_NA); } /* Clean up the dynamically allocated memory */ cleanup_multipart_info(m_info); return tvb_reported_length(tvb); }
static void dissect_fip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint op; guint sub; guint rlen; proto_item *ti; proto_item *item; proto_tree *fip_tree; proto_tree *subtree; guint dtype; guint dlen; guint desc_offset; guint val; tvbuff_t *desc_tvb; const char *info; const char *text; col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIP"); col_clear(pinfo->cinfo, COL_INFO); if (!tvb_bytes_exist(tvb, 0, FIP_HEADER_LEN)) { col_set_str(pinfo->cinfo, COL_INFO, "[packet too short]"); if (tree) proto_tree_add_protocol_format(tree, proto_fip, tvb, 0, -1, "FIP [packet too short]"); return; } op = tvb_get_ntohs(tvb, 2); sub = tvb_get_guint8(tvb, 5); switch (op) { case FIP_OP_DISC: info = val_to_str(sub, fip_disc_subcodes, "Discovery 0x%x"); break; case FIP_OP_LS: info = val_to_str(sub, fip_ls_subcodes, "Link Service 0x%x"); break; case FIP_OP_CTRL: info = val_to_str(sub, fip_ctrl_subcodes, "Control 0x%x"); break; case FIP_OP_VLAN: info = val_to_str(sub, fip_vlan_subcodes, "VLAN 0x%x"); break; case FIP_OP_VN2VN: info = val_to_str(sub, fip_vn2vn_subcodes, "VN2VN 0x%x"); break; default: info = val_to_str(op, fip_opcodes, "Unknown op 0x%x"); break; } col_add_str(pinfo->cinfo, COL_INFO, info); rlen = tvb_get_ntohs(tvb, 6); ti = proto_tree_add_protocol_format(tree, proto_fip, tvb, 0, FIP_HEADER_LEN + rlen * FIP_BPW, "FIP %s", info); fip_tree = proto_item_add_subtree(ti, ett_fip); proto_tree_add_item(fip_tree, hf_fip_ver, tvb, 0, 1, ENC_BIG_ENDIAN); proto_tree_add_item(fip_tree, hf_fip_op, tvb, 2, 2, ENC_BIG_ENDIAN); switch (op) { case FIP_OP_DISC: proto_tree_add_item(fip_tree, hf_fip_disc_subcode, tvb, 5, 1, ENC_BIG_ENDIAN); break; case FIP_OP_LS: proto_tree_add_item(fip_tree, hf_fip_ls_subcode, tvb, 5, 1, ENC_BIG_ENDIAN); break; case FIP_OP_CTRL: proto_tree_add_item(fip_tree, hf_fip_ctrl_subcode, tvb, 5, 1, ENC_BIG_ENDIAN); break; case FIP_OP_VLAN: proto_tree_add_item(fip_tree, hf_fip_vlan_subcode, tvb, 5, 1, ENC_BIG_ENDIAN); break; case FIP_OP_VN2VN: proto_tree_add_item(fip_tree, hf_fip_vn2vn_subcode, tvb, 5, 1, ENC_BIG_ENDIAN); break; default: proto_tree_add_item(fip_tree, hf_fip_hex_subcode, tvb, 5, 1, ENC_BIG_ENDIAN); break; } proto_tree_add_item(fip_tree, hf_fip_dlen, tvb, 6, 2, ENC_BIG_ENDIAN); proto_tree_add_bitmask(fip_tree, tvb, 8, hf_fip_flags, ett_fip_flags, hf_fip_flags_fields, ENC_BIG_ENDIAN); desc_offset = FIP_HEADER_LEN; rlen *= FIP_BPW; proto_tree_add_bytes_format(fip_tree, hf_fip_descriptors, tvb, desc_offset, rlen, NULL, "Descriptors"); while ((rlen > 0) && tvb_bytes_exist(tvb, desc_offset, 2)) { dlen = tvb_get_guint8(tvb, desc_offset + 1) * FIP_BPW; if (!dlen) { proto_tree_add_expert(fip_tree, pinfo, &ei_fip_descriptors, tvb, desc_offset, -1); break; } if (!tvb_bytes_exist(tvb, desc_offset, dlen) || dlen > rlen) { break; } desc_tvb = tvb_new_subset(tvb, desc_offset, dlen, -1); dtype = tvb_get_guint8(desc_tvb, 0); desc_offset += dlen; rlen -= dlen; switch (dtype) { case FIP_DT_PRI: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_pri, &item); proto_tree_add_item(subtree, hf_fip_desc_pri, desc_tvb, 3, 1, ENC_BIG_ENDIAN); proto_item_append_text(item, "%u", tvb_get_guint8(desc_tvb, 3)); break; case FIP_DT_MAC: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_mac, &item); proto_tree_add_item(subtree, hf_fip_desc_mac, desc_tvb, 2, 6, ENC_NA); proto_item_append_text(item, "%s", tvb_bytes_to_ep_str_punct(desc_tvb, 2, 6, ':')); break; case FIP_DT_MAP_OUI: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_map, &item); text = tvb_fc_to_str(desc_tvb, 5); proto_tree_add_string(subtree, hf_fip_desc_map, desc_tvb, 5, 3, text); proto_item_append_text(item, "%s", text); break; case FIP_DT_NAME: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_name, &item); text = tvb_fcwwn_to_str(desc_tvb, 4); proto_tree_add_string(subtree, hf_fip_desc_name, desc_tvb, 4, 8, text); proto_item_append_text(item, "%s", text); break; case FIP_DT_FAB: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_fab, &item); proto_tree_add_item(subtree, hf_fip_desc_fab_vfid, desc_tvb, 2, 2, ENC_BIG_ENDIAN); text = tvb_fc_to_str(desc_tvb, 5); proto_tree_add_string(subtree, hf_fip_desc_fab_map, desc_tvb, 5, 3, text); text = tvb_fcwwn_to_str(desc_tvb, 8); proto_tree_add_string(subtree, hf_fip_desc_fab_name, desc_tvb, 8, 8, text); proto_item_append_text(item, "%s", text); break; case FIP_DT_FCOE_SIZE: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_mdl, &item); proto_tree_add_item(subtree, hf_fip_desc_fcoe_size, desc_tvb, 2, 2, ENC_BIG_ENDIAN); proto_item_append_text(item, "%u", tvb_get_ntohs(desc_tvb, 2)); break; case FIP_DT_FLOGI: case FIP_DT_FDISC: case FIP_DT_LOGO: case FIP_DT_ELP: { tvbuff_t *ls_tvb; fc_data_t fc_data = {ETHERTYPE_FIP, 0}; subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_caps, &item); ls_tvb = tvb_new_subset(desc_tvb, 4, dlen - 4, -1); call_dissector_with_data(fc_handle, ls_tvb, pinfo, subtree, &fc_data); proto_item_append_text(item, "%u bytes", dlen - 4); } break; case FIP_DT_VN: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_vn, &item); proto_tree_add_item(subtree, hf_fip_desc_vn_mac, desc_tvb, 2, 6, ENC_NA); proto_tree_add_item(subtree, hf_fip_desc_vn_fid, desc_tvb, 9, 3, ENC_BIG_ENDIAN); text = tvb_fcwwn_to_str(desc_tvb, 12); proto_tree_add_string(subtree, hf_fip_desc_vn_wwpn, desc_tvb, 12, 8, text); proto_item_append_text(item, "MAC %s FC_ID %6.6x", tvb_bytes_to_ep_str_punct(desc_tvb, 2, 6, ':'), tvb_get_ntoh24(desc_tvb, 9)); break; case FIP_DT_FKA: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_fka, &item); val = tvb_get_ntohl(desc_tvb, 4); proto_tree_add_uint_format_value(subtree, hf_fip_desc_fka, desc_tvb, 4, 4, val, "%u ms", val); proto_item_append_text(item, "%u ms", val); break; case FIP_DT_VEND: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_vend, &item); proto_tree_add_item(subtree, hf_fip_desc_vend, desc_tvb, 4, 8, ENC_NA); if (tvb_bytes_exist(desc_tvb, 9, -1)) { proto_tree_add_item(subtree, hf_fip_desc_vend_data, desc_tvb, 9, -1, ENC_NA); } break; case FIP_DT_VLAN: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_vlan, &item); proto_tree_add_item(subtree, hf_fip_desc_vlan, desc_tvb, 2, 2, ENC_BIG_ENDIAN); proto_item_append_text(item, "%u", tvb_get_ntohs(desc_tvb, 2)); break; case FIP_DT_FC4F: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_fc4f, &item); fip_desc_fc4f(desc_tvb, subtree, item); break; default: subtree = fip_desc_type_len(fip_tree, desc_tvb, dtype, ett_fip_dt_unk, &item); proto_tree_add_item(subtree, hf_fip_desc_unk, desc_tvb, 2, -1, ENC_NA); break; } } }
static void dissect_isis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti, *version_item; proto_tree *isis_tree = NULL; int offset = 0; guint8 isis_version; guint8 isis_type; tvbuff_t *next_tvb; isis_data_t subdissector_data; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISIS"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_isis, tvb, 0, -1, ENC_NA); isis_tree = proto_item_add_subtree(ti, ett_isis); proto_tree_add_item(isis_tree, hf_isis_irpd, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; subdissector_data.header_length = tvb_get_guint8(tvb, offset); proto_tree_add_uint(isis_tree, hf_isis_header_length, tvb, offset, 1, subdissector_data.header_length ); offset += 1; isis_version = tvb_get_guint8(tvb, offset); version_item = proto_tree_add_uint(isis_tree, hf_isis_version, tvb, offset, 1, isis_version ); if (isis_version != ISIS_REQUIRED_VERSION){ col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ISIS version (%u vs %u)", isis_version, ISIS_REQUIRED_VERSION ); expert_add_info(pinfo, version_item, &ei_isis_version); return; } offset += 1; subdissector_data.system_id_len = tvb_get_guint8(tvb, offset); proto_tree_add_uint(isis_tree, hf_isis_system_id_length, tvb, offset, 1, subdissector_data.system_id_len ); offset += 1; isis_type = tvb_get_guint8(tvb, offset) & ISIS_TYPE_MASK; col_add_str(pinfo->cinfo, COL_INFO, val_to_str ( isis_type, isis_vals, "Unknown (0x%x)" ) ); proto_tree_add_item(isis_tree, hf_isis_type, tvb, offset, 1, ENC_BIG_ENDIAN ); proto_tree_add_item(isis_tree, hf_isis_type_reserved, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; proto_tree_add_item(isis_tree, hf_isis_version2, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; proto_tree_add_item(isis_tree, hf_isis_reserved, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; proto_tree_add_item(isis_tree, hf_isis_max_area_adr, tvb, offset, 1, ENC_BIG_ENDIAN ); offset += 1; /* * Interpret the system ID length. */ if (subdissector_data.system_id_len == 0) subdissector_data.system_id_len = 6; /* zero means 6-octet ID field length */ else if (subdissector_data.system_id_len == 255) { subdissector_data.system_id_len = 0; /* 255 means null ID field */ /* XXX - what about the LAN ID? */ } /* XXX - otherwise, must be in the range 1 through 8 */ next_tvb = tvb_new_subset_remaining(tvb, offset); if (!dissector_try_uint_new(isis_dissector_table, isis_type, next_tvb, pinfo, tree, TRUE, &subdissector_data)) { proto_tree_add_expert(tree, pinfo, &ei_isis_type, tvb, offset, -1); } } /* dissect_isis */
static gint dissect_acr122(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *p1_item; proto_tree *p1_tree; proto_item *p2_item; proto_tree *p2_tree; proto_item *sub_item; proto_item *sub_tree; proto_item *sw2_item; proto_item *sw2_tree; gint offset = 0; guint32 value; tvbuff_t *next_tvb; guint8 acr_class; guint8 ins; guint8 p1; guint8 p2; guint8 length; guint8 command = CMD_UNKNOWN; command_data_t *command_data; usb_conv_info_t *usb_conv_info; wmem_tree_key_t key[5]; guint32 bus_id; guint32 device_address; guint32 endpoint; guint32 k_bus_id; guint32 k_device_address; guint32 k_endpoint; guint32 k_frame_number; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACR 122"); col_clear(pinfo->cinfo, COL_INFO); main_item = proto_tree_add_item(tree, proto_acr122, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_acr122); if (!data) return offset; usb_conv_info = (usb_conv_info_t *) data; bus_id = usb_conv_info->bus_id; device_address = usb_conv_info->device_address; endpoint = usb_conv_info->endpoint; k_bus_id = bus_id; k_device_address = device_address; k_endpoint = endpoint; k_frame_number = pinfo->fd->num; key[0].length = 1; key[0].key = &k_bus_id; key[1].length = 1; key[1].key = &k_device_address; key[2].length = 1; key[2].key = &k_endpoint; key[3].length = 1; key[3].key = &k_frame_number; key[4].length = 0; key[4].key = NULL; if (pinfo->p2p_dir == P2P_DIR_SENT) { /* Request */ acr_class = tvb_get_guint8(tvb, offset); ins = tvb_get_guint8(tvb, offset + 1); p1 = tvb_get_guint8(tvb, offset + 2); p2 = tvb_get_guint8(tvb, offset + 3); length = tvb_get_guint8(tvb, offset + 4); /* Recognize command by simple heuristic */ if (acr_class == 0xFF) { if (ins == 0xCA && p1 == 0x00 && p2 == 0x00 && length == 0) command = CMD_GET_DATA_UID; if (ins == 0xCA && p1 == 0x01 && p2 == 0x00 && length == 0) command = CMD_GET_DATA_ATS; else if (ins == 0x82 && length == 6) command = CMD_LOAD_AUTHENTICATION_KEYS; else if (ins == 0x88 && p1 == 0x00) command = CMD_AUTHENTICATION_OBSOLETE; else if (ins == 0x86 && p1 == 0x00 && p2 == 0x00 && length == 5) command = CMD_AUTHENTICATION; else if (ins == 0xB0 && p1 == 0x00) command = CMD_READ_BINARY_BLOCKS; else if (ins == 0xD6 && p1 == 0x00) command = CMD_UPDATE_BINARY_BLOCKS; else if (ins == 0xD7 && p1 == 0x00 && length == 5) command = CMD_VALUE_BLOCK_OPERATION; else if (ins == 0xB1 && p1 == 0x00 && length == 4) command = CMD_READ_VALUE_BLOCK; else if (ins == 0xD7 && p1 == 0x00 && length == 2) command = CMD_RESTORE_VALUE_BLOCK; else if (ins == 0x00 && p1 == 0x00 && p2 == 0x00) command = CMD_DIRECT_TRANSMIT; else if (ins == 0x00 && p1 == 0x40 && length == 4) command = CMD_BI_COLOR_AND_BUZZER_LED_CONTROL; else if (ins == 0x00 && p1 == 0x48 && p2 == 0x00) command = CMD_GET_FIRMWARE_VERSION; else if (ins == 0x00 && p1 == 0x50 && p2 == 0x00) command = CMD_GET_PICC_OPERATING_PARAMETER; else if (ins == 0x00 && p1 == 0x51 && length == 0) command = CMD_SET_PICC_OPERATING_PARAMETER; else if (ins == 0x00 && p1 == 0x41 && length == 0) command = CMD_SET_TIMEOUT_PARAMETER; else if (ins == 0x00 && p1 == 0x52 && length == 0) command = CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION; } sub_item = proto_tree_add_uint(main_tree, hf_command, tvb, offset, 4 + length, command); PROTO_ITEM_SET_GENERATED(sub_item); if (command == CMD_UNKNOWN) proto_tree_add_expert(sub_item, pinfo, &ei_unknown_command_or_invalid_parameters, tvb, offset, 4 + length); col_add_fstr(pinfo->cinfo, COL_INFO, "Command: %s", val_to_str_const(command, command_vals, "Unknown")); proto_tree_add_item(main_tree, hf_class, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(main_tree, hf_ins, tvb, offset, 1, ENC_NA); offset += 1; p1_item = proto_tree_add_item(main_tree, hf_p1, tvb, offset, 1, ENC_NA); offset += 1; p2_item = proto_tree_add_item(main_tree, hf_p2, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(main_tree, hf_length, tvb, offset, 1, ENC_NA); offset += 1; switch (command) { case CMD_DIRECT_TRANSMIT: if (length > 0) { next_tvb = tvb_new_subset(tvb, offset, length, length); call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info); offset += length; } break; case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_led_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_green_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_red_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_initial_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_initial_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_final_green_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_final_red_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_led_t1_duration, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_led_t2_duration, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_led_number_of_repetition, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_led_link_to_buzzer, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_GET_DATA_UID: case CMD_GET_DATA_ATS: /* Nothing to decode */ break; case CMD_LOAD_AUTHENTICATION_KEYS: p1_tree = proto_item_add_subtree(p1_item, ett_p1_item); proto_tree_add_item(p1_tree, hf_key_structure, tvb, offset - 3, 1, ENC_BIG_ENDIAN); p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_key_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_key, tvb, offset, 6, ENC_NA); offset += 6; break; case CMD_AUTHENTICATION_OBSOLETE: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_AUTHENTICATION: proto_tree_add_item(main_tree, hf_version, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(main_tree, hf_block_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_READ_BINARY_BLOCKS: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_UPDATE_BINARY_BLOCKS: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); offset += length; break; case CMD_VALUE_BLOCK_OPERATION: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_vb_op, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; break; case CMD_READ_VALUE_BLOCK: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_RESTORE_VALUE_BLOCK: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_source_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_static_byte, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_target_block_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_SET_PICC_OPERATING_PARAMETER: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_picc_operating_auto_picc_polling, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_auto_ats_generation, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_polling_interval, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_felica_424k, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_felica_212k, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_topaz, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_SET_TIMEOUT_PARAMETER: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_timeout, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_poll_buzzer_status, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_GET_PICC_OPERATING_PARAMETER: /* No parameters */ break; } if (!pinfo->fd->flags.visited) { command_data = wmem_new(wmem_file_scope(), command_data_t); command_data->bus_id = bus_id; command_data->device_address = device_address; command_data->endpoint = endpoint; command_data->command = command; command_data->command_frame_number = pinfo->fd->num; command_data->response_frame_number = 0; wmem_tree_insert32_array(command_info, key, command_data); } } else { /* Response */ guint32 command_frame_number = 0; gboolean use_status_word = FALSE; wmem_tree_t *wmem_tree; key[3].length = 0; key[3].key = NULL; wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key); if (wmem_tree) { command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->fd->num); if (command_data && (command_data->response_frame_number == 0 || command_data->response_frame_number == pinfo->fd->num)) { command = command_data->command; command_frame_number = command_data->command_frame_number; if (!pinfo->fd->flags.visited && command_data->response_frame_number == 0) { command_data->response_frame_number = pinfo->fd->num; } } } sub_item = proto_tree_add_uint(main_tree, hf_response, tvb, offset, tvb_length_remaining(tvb, offset), command); PROTO_ITEM_SET_GENERATED(sub_item); col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s", val_to_str_const(command, command_vals, "Unknown")); if (command != CMD_UNKNOWN) { sub_item = proto_tree_add_uint(main_tree, hf_response_for, tvb, offset, tvb_length_remaining(tvb, offset), command_frame_number); PROTO_ITEM_SET_GENERATED(sub_item); } switch (command) { case CMD_GET_FIRMWARE_VERSION: proto_tree_add_item(main_tree, hf_firmware_version, tvb, offset, -1, ENC_NA | ENC_ASCII); offset += tvb_length_remaining(tvb, offset); break; case CMD_DIRECT_TRANSMIT: use_status_word = TRUE; if (tvb_length_remaining(tvb, offset) > 2) { next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset) - 2, tvb_length_remaining(tvb, offset) - 2); call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info); offset += tvb_length_remaining(tvb, offset) - 2; } break; case CMD_READ_BINARY_BLOCKS: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_data, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA); offset += tvb_length_remaining(tvb, offset) - 2; break; case CMD_READ_VALUE_BLOCK: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN); break; case CMD_GET_DATA_UID: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_uid, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA); offset += tvb_length_remaining(tvb, offset) - 2; break; case CMD_GET_DATA_ATS: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_ats, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA); offset += tvb_length_remaining(tvb, offset) - 2; break; case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL: case CMD_LOAD_AUTHENTICATION_KEYS: case CMD_AUTHENTICATION: case CMD_AUTHENTICATION_OBSOLETE: case CMD_UPDATE_BINARY_BLOCKS: case CMD_VALUE_BLOCK_OPERATION: case CMD_RESTORE_VALUE_BLOCK: case CMD_SET_TIMEOUT_PARAMETER: case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION: case CMD_SET_PICC_OPERATING_PARAMETER: case CMD_GET_PICC_OPERATING_PARAMETER: default: use_status_word = TRUE; break; } if (use_status_word) { value = tvb_get_ntohs(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, " - %s%s", (((value & 0xFF00) != 0x9000) && (value & 0xFF00) != 0x6100) ? "Error: " : "", rval_to_str(value, status_word_rvals, "Unknown error")); if ((value & 0xFF00) == 0x6100) col_append_fstr(pinfo->cinfo, COL_INFO, " - Length %u", value & 0x00FF); sub_item = proto_tree_add_item(main_tree, hf_status_word, tvb, offset, 2, ENC_BIG_ENDIAN); sub_tree = proto_item_add_subtree(sub_item, ett_status_word); proto_tree_add_item(sub_tree, hf_status_word_sw1, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; sw2_item = proto_tree_add_item(sub_tree, hf_status_word_sw2, tvb, offset, 1, ENC_BIG_ENDIAN); if (command == CMD_BI_COLOR_AND_BUZZER_LED_CONTROL) { sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2); col_append_fstr(pinfo->cinfo, COL_INFO, " - Red LED: %s, Green LED: %s", (value & 0x02) ? "On" : "Off", (value & 0x01) ? "On" : "Off"); proto_tree_add_item(sw2_tree, hf_status_word_led_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_status_word_led_green, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_status_word_led_red, tvb, offset, 1, ENC_BIG_ENDIAN); } else if (command == CMD_SET_PICC_OPERATING_PARAMETER || command == CMD_GET_PICC_OPERATING_PARAMETER) { sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2); proto_tree_add_item(sw2_tree, hf_picc_operating_auto_picc_polling, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_auto_ats_generation, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_polling_interval, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_felica_424k, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_felica_212k, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_topaz, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN); } offset += 1; } } return offset; }
static gint dissect_usb_dfu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *command_item; proto_item *sub_item; proto_tree *command_tree; gint offset = 0; gint p2p_dir_save; guint8 command; gint16 command_response = -1; command_data_t *command_data = NULL; wmem_tree_t *wmem_tree; wmem_tree_key_t key[5]; guint32 bus_id; guint32 device_address; guint32 k_bus_id; guint32 k_device_address; guint32 k_frame_number; gint32 block_number = -1; usb_conv_info_t *usb_conv_info = (usb_conv_info_t *)data; if (!usb_conv_info) return offset; bus_id = usb_conv_info->bus_id; device_address = usb_conv_info->device_address; k_bus_id = bus_id; k_device_address = device_address; k_frame_number = pinfo->fd->num; key[0].length = 1; key[0].key = &k_bus_id; key[1].length = 1; key[1].key = &k_device_address; main_item = proto_tree_add_item(tree, proto_usb_dfu, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_usb_dfu); col_set_str(pinfo->cinfo, COL_PROTOCOL, "USB DFU"); p2p_dir_save = pinfo->p2p_dir; pinfo->p2p_dir = (usb_conv_info->is_request) ? P2P_DIR_SENT : P2P_DIR_RECV; switch (pinfo->p2p_dir) { case P2P_DIR_SENT: col_set_str(pinfo->cinfo, COL_INFO, "Sent "); break; case P2P_DIR_RECV: col_set_str(pinfo->cinfo, COL_INFO, "Rcvd "); break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction "); break; } if (usb_conv_info->is_setup) { guint16 interface; command_item = proto_tree_add_item(main_tree, hf_setup_command, tvb, offset, 1, ENC_NA); command = tvb_get_guint8(tvb, offset); if (!((usb_conv_info->setup_requesttype == 0x21 && (command == 0x00 || command == 0x01 || command == 0x04 || command == 0x06)) || (usb_conv_info->setup_requesttype == 0xa1 && (command == 0x02 || command == 0x03 || command == 0x05)))) expert_add_info(pinfo, command_item, &ei_invalid_command_for_request_type); offset += 1; col_append_fstr(pinfo->cinfo, COL_INFO, "Command: %s", val_to_str_ext_const(command, &command_vals_ext, "Unknown")); if (command == 0x00) { /* Detach */ proto_tree_add_item(main_tree, hf_setup_timeout, tvb, offset, 2, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " Timeout=%u", tvb_get_letohs(tvb, offset)); } else if (command == 0x01 || command == 0x02) { /* Download || Upload */ proto_tree_add_item(main_tree, hf_setup_block_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " Block Number=%u", tvb_get_letohs(tvb, offset)); block_number = tvb_get_letohs(tvb, offset); } else { proto_tree_add_item(main_tree, hf_setup_unused, tvb, offset, 2, ENC_LITTLE_ENDIAN); } offset += 2; proto_tree_add_item(main_tree, hf_setup_interface, tvb, offset, 2, ENC_LITTLE_ENDIAN); interface = tvb_get_letohs(tvb, offset); offset += 2; proto_tree_add_item(main_tree, hf_setup_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; if (command == 0x01) { /* Download */ proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_length(tvb); } if (tvb_length_remaining(tvb, offset) > 0) { proto_tree_add_expert(main_tree, pinfo, &ei_unexpected_data, tvb, offset, tvb_length_remaining(tvb, offset)); offset = tvb_length(tvb); } /* Save request info (command_data) */ if (!pinfo->fd->flags.visited && command != 21) { key[2].length = 1; key[2].key = &k_frame_number; key[3].length = 0; key[3].key = NULL; command_data = wmem_new(wmem_file_scope(), command_data_t); command_data->bus_id = bus_id; command_data->device_address = device_address; command_data->command = command; command_data->interface = interface; command_data->command_frame_number = pinfo->fd->num; command_data->block_number = block_number; wmem_tree_insert32_array(command_info, key, command_data); } pinfo->p2p_dir = p2p_dir_save; return offset; } /* Get request info (command_data) */ key[2].length = 0; key[2].key = NULL; wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key); if (wmem_tree) { command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->fd->num); if (command_data) { command_response = command_data->command; block_number = command_data->block_number; } } if (!command_data) { col_append_str(pinfo->cinfo, COL_INFO, "Response: Unknown"); proto_tree_add_expert(main_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_length_remaining(tvb, offset)); pinfo->p2p_dir = p2p_dir_save; return tvb_length(tvb); } col_append_fstr(pinfo->cinfo, COL_INFO, "Response: %s", val_to_str_ext_const(command_response, &command_vals_ext, "Unknown")); command_item = proto_tree_add_uint(main_tree, hf_response, tvb, offset, 0, command_response); command_tree = proto_item_add_subtree(command_item, ett_command); PROTO_ITEM_SET_GENERATED(command_item); if (command_data) { command_item = proto_tree_add_uint(main_tree, hf_setup_interface, tvb, offset, 0, command_data->interface); PROTO_ITEM_SET_GENERATED(command_item); command_item = proto_tree_add_uint(main_tree, hf_command_in_frame, tvb, offset, 0, command_data->command_frame_number); PROTO_ITEM_SET_GENERATED(command_item); } switch (command_response) { case 0x02: /* Upload */ if (block_number != -1) { sub_item = proto_tree_add_uint(main_tree, hf_setup_block_number, tvb, offset, 0, block_number); PROTO_ITEM_SET_GENERATED(sub_item); col_append_fstr(pinfo->cinfo, COL_INFO, " Block Number=%u", block_number); } proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_length(tvb); break; case 0x03: /* Get Status */ col_append_fstr(pinfo->cinfo, COL_INFO, " = Status: %s, PollTimeout: %u ms, State: %s", val_to_str_ext_const(tvb_get_guint8(tvb, offset), &status_vals_ext, "Unknown"), tvb_get_letoh24(tvb, offset + 1), val_to_str_ext_const(tvb_get_guint8(tvb, offset + 4), &state_vals_ext, "Unknown")); proto_tree_add_item(main_tree, hf_status, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(main_tree, hf_poll_timeout, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; proto_tree_add_item(main_tree, hf_state, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(main_tree, hf_iString, tvb, offset, 1, ENC_NA); offset += 1; break; case 0x05: /* Get State */ proto_tree_add_item(main_tree, hf_state, tvb, offset, 1, ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " = %s", val_to_str_ext_const(tvb_get_guint8(tvb, offset), &state_vals_ext, "Unknown")); offset += 1; break; case 0x00: /* Detach */ case 0x01: /* Download */ case 0x04: /* Clear Status */ case 0x06: /* Abort */ default: proto_tree_add_expert(command_tree, pinfo, &ei_unexpected_response, tvb, offset, 0); if (tvb_length_remaining(tvb, offset) > 0) { proto_tree_add_expert(main_tree, pinfo, &ei_unknown_data, tvb, offset, -1); offset = tvb_length(tvb); } } pinfo->p2p_dir = p2p_dir_save; return offset; }