/* Both Source-Active and Source-Active Response have the same format * with one exception. Encapsulated multicast data is not allowed in * SA Response. */ static void dissect_msdp_sa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, int length) { guint8 entries; if (length < 1) return; entries = tvb_get_guint8(tvb, *offset); proto_tree_add_uint(tree, hf_msdp_sa_entry_count, tvb, *offset, 1, entries); *offset += 1; length -= 1; if (length < 4) { *offset += length; return; } proto_tree_add_item(tree, hf_msdp_sa_rp_addr, tvb, *offset, 4, ENC_BIG_ENDIAN); *offset += 4; length -= 4; /* Put each of the (S,G) entries in their own subtree. * This is probably visually better. */ while (entries-- > 0) { proto_tree *entry_tree; if (length < 12) { *offset += length; return; } entry_tree = proto_tree_add_subtree_format(tree, tvb, *offset, 12, ett_msdp_sa_entry, NULL, "(S,G) block: %s/%u -> %s", tvb_ip_to_str(tvb, *offset + 8), tvb_get_guint8(tvb, *offset + 3), tvb_ip_to_str(tvb, *offset + 4)); proto_tree_add_item(entry_tree, hf_msdp_sa_reserved, tvb, *offset, 3, ENC_BIG_ENDIAN); *offset += 3; length -= 3; proto_tree_add_item(entry_tree, hf_msdp_sa_sprefix_len, tvb, *offset, 1, ENC_BIG_ENDIAN); *offset += 1; length -= 1; proto_tree_add_item(entry_tree, hf_msdp_sa_group_addr, tvb, *offset, 4, ENC_BIG_ENDIAN); *offset += 4; length -= 4; proto_tree_add_item(entry_tree, hf_msdp_sa_src_addr, tvb, *offset, 4, ENC_BIG_ENDIAN); *offset += 4; length -= 4; } /* * Check if an encapsulated multicast IPv4 packet follows */ if (length > 0) { proto_tree *enc_tree; gint available_length, reported_length; tvbuff_t *next_tvb; enc_tree = proto_tree_add_subtree_format(tree, tvb, *offset, length, ett_msdp_sa_enc_data, NULL, "Encapsulated IPv4 packet: %u bytes", length); available_length = tvb_captured_length_remaining(tvb, *offset); reported_length = tvb_reported_length_remaining(tvb, *offset); DISSECTOR_ASSERT(available_length >= 0); DISSECTOR_ASSERT(reported_length >= 0); if (available_length > reported_length) available_length = reported_length; if (available_length > length) available_length = length; if (reported_length > length) reported_length = length; next_tvb = tvb_new_subset(tvb, *offset, available_length, reported_length); /* Set the information columns read-only so that they * reflect the MSDP packet rather than the * encapsulated packet. */ col_set_writable(pinfo->cinfo, FALSE); call_dissector(ip_handle, next_tvb, pinfo, enc_tree); } *offset += length; return; }
/* ----------------------------- from netatalk/etc/afpd/status.c */ static gint dissect_dsi_reply_get_status(tvbuff_t *tvb, proto_tree *tree, gint offset) { proto_tree *sub_tree; proto_item *ti; guint16 ofs; guint16 flag; guint16 sign_ofs = 0; guint16 adr_ofs = 0; guint16 dir_ofs = 0; guint16 utf_ofs = 0; guint8 nbe; guint8 len; guint8 i; if (!tree) return offset; ti = proto_tree_add_text(tree, tvb, offset, -1, "Get Status"); tree = proto_item_add_subtree(ti, ett_dsi_status); ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_MACHOFF); proto_tree_add_text(tree, tvb, offset +AFPSTATUS_MACHOFF, 2, "Machine offset: %d", ofs); ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF); proto_tree_add_text(tree, tvb, offset +AFPSTATUS_VERSOFF, 2, "Version offset: %d", ofs); ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF); proto_tree_add_text(tree, tvb, offset +AFPSTATUS_UAMSOFF, 2, "UAMS offset: %d", ofs); ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF); proto_tree_add_text(tree, tvb, offset +AFPSTATUS_ICONOFF, 2, "Icon offset: %d", ofs); ofs = offset +AFPSTATUS_FLAGOFF; ti = proto_tree_add_item(tree, hf_dsi_server_flag, tvb, ofs, 2, ENC_BIG_ENDIAN); sub_tree = proto_item_add_subtree(ti, ett_dsi_status_server_flag); proto_tree_add_item(sub_tree, hf_dsi_server_flag_copyfile , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_passwd , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_no_save_passwd, tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_srv_msg , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_srv_sig , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_tcpip , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_notify , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_reconnect , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_directory , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_utf8_name , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_uuid , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_ext_sleep , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_dsi_server_flag_fast_copy , tvb, ofs, 2, ENC_BIG_ENDIAN); proto_tree_add_item(tree, hf_dsi_server_name, tvb, offset +AFPSTATUS_PRELEN, 1, ENC_ASCII|ENC_NA); flag = tvb_get_ntohs(tvb, ofs); if ((flag & AFPSRVRINFO_SRVSIGNATURE)) { ofs = offset +AFPSTATUS_PRELEN +tvb_get_guint8(tvb, offset +AFPSTATUS_PRELEN) +1; if ((ofs & 1)) ofs++; sign_ofs = tvb_get_ntohs(tvb, ofs); proto_tree_add_text(tree, tvb, ofs, 2, "Signature offset: %d", sign_ofs); if (sign_ofs) sign_ofs += offset; if ((flag & AFPSRVRINFO_TCPIP)) { ofs += 2; adr_ofs = tvb_get_ntohs(tvb, ofs); proto_tree_add_text(tree, tvb, ofs, 2, "Network address offset: %d", adr_ofs); adr_ofs += offset; } if ((flag & AFPSRVRINFO_SRVDIRECTORY)) { ofs += 2; dir_ofs = tvb_get_ntohs(tvb, ofs); proto_tree_add_text(tree, tvb, ofs, 2, "Directory services offset: %d", dir_ofs); dir_ofs += offset; } if ((flag & AFPSRVRINFO_SRVUTF8)) { ofs += 2; utf_ofs = tvb_get_ntohs(tvb, ofs); proto_tree_add_text(tree, tvb, ofs, 2, "UTF8 server name offset: %d", utf_ofs); utf_ofs += offset; } } ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_MACHOFF); if (ofs) { ofs += offset; proto_tree_add_item(tree, hf_dsi_server_type, tvb, ofs, 1, ENC_ASCII|ENC_NA); } ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_VERSOFF); if (ofs) { ofs += offset; nbe = tvb_get_guint8(tvb, ofs); ti = proto_tree_add_text(tree, tvb, ofs, 1, "Version list: %d", nbe); ofs++; sub_tree = proto_item_add_subtree(ti, ett_dsi_vers); for (i = 0; i < nbe; i++) { len = tvb_get_guint8(tvb, ofs); proto_tree_add_item(sub_tree, hf_dsi_server_vers, tvb, ofs, 1, ENC_ASCII|ENC_NA); ofs += len + 1; } } ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_UAMSOFF); if (ofs) { ofs += offset; nbe = tvb_get_guint8(tvb, ofs); ti = proto_tree_add_text(tree, tvb, ofs, 1, "UAMS list: %d", nbe); ofs++; sub_tree = proto_item_add_subtree(ti, ett_dsi_uams); for (i = 0; i < nbe; i++) { len = tvb_get_guint8(tvb, ofs); proto_tree_add_item(sub_tree, hf_dsi_server_uams, tvb, ofs, 1, ENC_ASCII|ENC_NA); ofs += len + 1; } } ofs = tvb_get_ntohs(tvb, offset +AFPSTATUS_ICONOFF); if (ofs) { ofs += offset; proto_tree_add_item(tree, hf_dsi_server_icon, tvb, ofs, 256, ENC_NA); } if (sign_ofs) { proto_tree_add_item(tree, hf_dsi_server_signature, tvb, sign_ofs, 16, ENC_NA); } if (adr_ofs) { proto_tree *adr_tree; unsigned char *tmp; guint16 net; guint8 node; guint16 port; ofs = adr_ofs; nbe = tvb_get_guint8(tvb, ofs); ti = proto_tree_add_text(tree, tvb, ofs, 1, "Address list: %d", nbe); ofs++; adr_tree = proto_item_add_subtree(ti, ett_dsi_addr); for (i = 0; i < nbe; i++) { guint8 type; len = tvb_get_guint8(tvb, ofs); type = tvb_get_guint8(tvb, ofs +1); switch (type) { case 1: /* IP */ ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip: %s", tvb_ip_to_str(tvb, ofs+2)); break; case 2: /* IP + port */ port = tvb_get_ntohs(tvb, ofs+6); ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip %s:%d", tvb_ip_to_str(tvb, ofs+2), port); break; case 3: /* DDP, atalk_addr_to_str want host order not network */ net = tvb_get_ntohs(tvb, ofs+2); node = tvb_get_guint8(tvb, ofs +4); port = tvb_get_guint8(tvb, ofs +5); ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ddp: %u.%u:%u", net, node, port); break; case 4: /* DNS */ case 5: /* SSH tunnel */ if (len > 2) { tmp = tvb_get_string(wmem_packet_scope(), tvb, ofs +2, len -2); ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "%s: %s", (type==4)?"dns":"ssh tunnel", tmp); break; } else { ti = proto_tree_add_text(adr_tree, tvb, ofs, len,"Malformed address type %d", type); } break; case 6: /* IP6 */ ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip6: %s", tvb_ip6_to_str(tvb, ofs+2)); break; case 7: /* IP6 + 2bytes port */ port = tvb_get_ntohs(tvb, ofs+ 2+INET6_ADDRLEN); ti = proto_tree_add_text(adr_tree, tvb, ofs, len, "ip6 %s:%d", tvb_ip6_to_str(tvb, ofs+2), port); break; default: ti = proto_tree_add_text(adr_tree, tvb, ofs, len,"Unknown type : %d", type); break; } len -= 2; sub_tree = proto_item_add_subtree(ti,ett_dsi_addr_line); proto_tree_add_item(sub_tree, hf_dsi_server_addr_len, tvb, ofs, 1, ENC_BIG_ENDIAN); ofs++; proto_tree_add_item(sub_tree, hf_dsi_server_addr_type, tvb, ofs, 1, ENC_BIG_ENDIAN); ofs++; proto_tree_add_item(sub_tree, hf_dsi_server_addr_value,tvb, ofs, len, ENC_NA); ofs += len; } } if (dir_ofs) { ofs = dir_ofs; nbe = tvb_get_guint8(tvb, ofs); ti = proto_tree_add_text(tree, tvb, ofs, 1, "Directory services list: %d", nbe); ofs++; sub_tree = proto_item_add_subtree(ti, ett_dsi_directory); for (i = 0; i < nbe; i++) { len = tvb_get_guint8(tvb, ofs); proto_tree_add_item(sub_tree, hf_dsi_server_directory, tvb, ofs, 1, ENC_ASCII|ENC_NA); ofs += len + 1; } } if (utf_ofs) { guint16 ulen; char *tmp; ofs = utf_ofs; ulen = tvb_get_ntohs(tvb, ofs); tmp = tvb_get_string(wmem_packet_scope(), tvb, ofs + 2, ulen); ti = proto_tree_add_text(tree, tvb, ofs, ulen + 2, "UTF8 server name: %s", tmp); sub_tree = proto_item_add_subtree(ti, ett_dsi_utf8_name); proto_tree_add_uint(sub_tree, hf_dsi_utf8_server_name_len, tvb, ofs, 2, ulen); ofs += 2; proto_tree_add_string(sub_tree, hf_dsi_utf8_server_name, tvb, ofs, ulen, tmp); ofs += ulen; } return ofs; }
/* * For PIM v2, see RFC 4601, RFC 3973 and draft-ietf-pim-sm-v2-new-03 * (when PIM is run over IPv6, the rules for computing the PIM checksum * from the draft in question, not from RFC 2362, should be used). */ static void dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; guint8 pim_typever; guint length, pim_length; guint16 pim_cksum, computed_cksum; vec_t cksum_vec[4]; guint32 phdr[2]; const char *typestr; proto_tree *pim_tree = NULL; proto_item *ti; proto_tree *pimopt_tree = NULL; proto_item *tiopt; col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIM"); col_clear(pinfo->cinfo, COL_INFO); pim_typever = tvb_get_guint8(tvb, 0); switch (PIM_VER(pim_typever)) { case 2: typestr = val_to_str(PIM_TYPE(pim_typever), type2vals, "Unknown (%u)"); break; case 1: /* PIMv1 - we should never see this */ default: typestr = "Unknown"; break; } if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "PIMv%d", PIM_VER(pim_typever)); } if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, typestr); ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE); pim_tree = proto_item_add_subtree(ti, ett_pim); proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, FALSE); proto_tree_add_item(pim_tree, hf_pim_type, tvb, offset, 1, FALSE); proto_tree_add_item(pim_tree, hf_pim_res_bytes, tvb, offset + 1, 1, FALSE); pim_cksum = tvb_get_ntohs(tvb, offset + 2); length = tvb_length(tvb); if (PIM_VER(pim_typever) == 2) { /* * Well, it's PIM v2, so we can check whether this is a Register * message, and thus can figure out how much to checksum and * whether to make the columns read-only. */ if (PIM_TYPE(pim_typever) == 1) { /* * Register message - the PIM header is 8 bytes long. * Also set the columns non-writable. Otherwise the IPv4 or * IPv6 dissector for the encapsulated packet that caused * this register will overwrite the PIM info in the columns. */ pim_length = 8; col_set_writable(pinfo->cinfo, FALSE); } else { /* * Other message - checksum the entire packet. */ pim_length = tvb_reported_length(tvb); } } else { /* * We don't know what type of message this is, so say that * the length is 0, to force it not to be checksummed. */ pim_length = 0; } if (!pinfo->fragmented && length >= pim_length) { /* * The packet isn't part of a fragmented datagram and isn't * truncated, so we can checksum it. */ switch (pinfo->src.type) { case AT_IPv4: cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length); cksum_vec[0].len = pim_length; computed_cksum = in_cksum(&cksum_vec[0], 1); break; case AT_IPv6: /* Set up the fields of the pseudo-header. */ cksum_vec[0].ptr = pinfo->src.data; cksum_vec[0].len = pinfo->src.len; cksum_vec[1].ptr = pinfo->dst.data; cksum_vec[1].len = pinfo->dst.len; cksum_vec[2].ptr = (const guint8 *)&phdr; phdr[0] = g_htonl(pim_length); phdr[1] = g_htonl(IP_PROTO_PIM); cksum_vec[2].len = 8; cksum_vec[3].ptr = tvb_get_ptr(tvb, 0, pim_length); cksum_vec[3].len = pim_length; computed_cksum = in_cksum(&cksum_vec[0], 4); break; default: /* PIM is available for IPv4 and IPv6 right now */ computed_cksum = 0; /* squelch GCC complaints */ DISSECTOR_ASSERT_NOT_REACHED(); break; } if (computed_cksum == 0) { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset + 2, 2, pim_cksum, "Checksum: 0x%04x [correct]", pim_cksum); } else { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset + 2, 2, pim_cksum, "Checksum: 0x%04x [incorrect, should be 0x%04x]", pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum)); } } else { proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb, offset + 2, 2, pim_cksum); } offset += 4; if (tvb_reported_length_remaining(tvb, offset) > 0) { tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options"); pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts); } else goto done; if (PIM_VER(pim_typever) != 2) goto done; /* version 2 decoder */ switch (PIM_TYPE(pim_typever)) { case 0: /*hello*/ { int opt_count = 0; while (tvb_reported_length_remaining(tvb, offset) >= 2) { guint16 hello_opt, opt_len; guint16 opt_value; proto_item *opt_item; proto_tree *opt_tree; opt_count++; hello_opt = tvb_get_ntohs(tvb, offset); opt_len = tvb_get_ntohs(tvb, offset + 2); opt_item = proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len, "Option %u: %s", hello_opt, val_to_str(hello_opt, pim_opt_vals, "Unknown: %u")); opt_tree = proto_item_add_subtree(opt_item, ett_pim_opt); proto_tree_add_item(opt_tree, hf_pim_optiontype, tvb, offset, 2, FALSE); proto_tree_add_item(opt_tree, hf_pim_optionlength, tvb, offset + 2, 2, FALSE); switch(hello_opt) { case 1: /* Hello Hold Time Option */ opt_value = tvb_get_ntohs(tvb, offset + 4); proto_tree_add_uint_format(opt_tree, hf_pim_holdtime, tvb, offset + 4, opt_len, opt_value, "Holdtime: %us %s", opt_value, opt_value == 0 ? "(goodbye)" : opt_value == 0xffff ? "(infinity)": ""); proto_item_append_text(opt_item, ": %us %s", opt_value, opt_value == 0 ? "(goodbye)" : opt_value == 0xffff ? "(infinity)": ""); break; case 2: /* LAN Prune Delay Option */ proto_tree_add_item(opt_tree, hf_pim_t, tvb, offset + 4, 1, FALSE); proto_tree_add_item(opt_tree, hf_pim_propagation_delay, tvb, offset + 4, 2, FALSE); proto_tree_add_item(opt_tree, hf_pim_override_interval, tvb, offset + 6, 2, FALSE); proto_item_append_text(opt_item, ": T = %u, Propagation Delay = %ums, Override Interval = %ums", tvb_get_guint8(tvb, offset + 4) & 0x80 ? 1 : 0, tvb_get_ntohs(tvb, offset + 4) & 0x7fff, tvb_get_ntohs(tvb, offset + 6)); break; case 19: /* DR priority */ proto_tree_add_item(opt_tree, hf_pim_dr_priority, tvb, offset + 4, 4, FALSE); proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4)); break; case 20: /* Generation ID */ proto_tree_add_item(opt_tree, hf_pim_generation_id, tvb, offset + 4, 4, FALSE); proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4)); break; case 21: /* State Refresh Capable Option */ proto_tree_add_item(opt_tree, hf_pim_state_refresh_version, tvb, offset + 4, 1, FALSE); proto_tree_add_item(opt_tree, hf_pim_state_refresh_interval, tvb, offset + 5, 1, FALSE); proto_tree_add_item(opt_tree, hf_pim_state_refresh_reserved, tvb, offset + 6, 2, FALSE); proto_item_append_text(opt_item, ": Version = %u, Interval = %us", tvb_get_guint8(tvb, offset + 4), tvb_get_guint8(tvb, offset + 5)); break; case 24: /* address list */ case 65001: /* address list (old implementations) */ { int i; proto_tree *sub_tree = NULL; proto_item *addrlist_option; addrlist_option = proto_tree_add_text(opt_tree, tvb, offset, 4 + opt_len, "%sAddress List (%u)", hello_opt == 65001 ? "old " : "", hello_opt); sub_tree = proto_item_add_subtree(addrlist_option, ett_pim_opt); for (i = offset + 4; i < offset + 4 + opt_len; ) { int advance; const char *s; s = dissect_pim_addr(tvb, i, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(sub_tree, tvb, offset, advance, "Address: %s", s); i += advance; } break; } default: if (opt_len) proto_tree_add_item(opt_tree, hf_pim_optionvalue, tvb, offset + 4, opt_len, FALSE); break; } offset += 4 + opt_len; } proto_item_append_text(tiopt, ": %u", opt_count); break; } case 1: /* register */ { guint32 flags; guint8 v_hl; tvbuff_t *next_tvb; proto_tree *flag_tree = NULL; proto_item *tiflag; flags = tvb_get_ntohl(tvb, offset); tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Flags: 0x%08x", flags); flag_tree = proto_item_add_subtree(tiflag, ett_pim); proto_tree_add_text(flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(flags, 0x80000000, 32, "Border", "Not border")); proto_tree_add_text(flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(flags, 0x40000000, 32, "Null-Register", "Not Null-Register")); offset += 4; /* * The rest of the packet is a multicast data packet. */ next_tvb = tvb_new_subset_remaining(tvb, offset); /* * It's an IP packet - determine whether it's IPv4 or IPv6. */ v_hl = tvb_get_guint8(tvb, offset); switch((v_hl & 0xf0) >> 4) { case 0: /* Null-Register dummy header. * Has the same address family as the encapsulating PIM packet, * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet. */ if (pinfo->src.type == AT_IPv4) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv4 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4, "Source: %s", tvb_ip_to_str(tvb, offset + 12)); proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4, "Group: %s", tvb_ip_to_str(tvb, offset + 16)); } else if (pinfo->src.type == AT_IPv6) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv6 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 8, 16, "Source: %s", tvb_ip6_to_str(tvb, offset + 8)); proto_tree_add_text(pimopt_tree, tvb, offset + 8 + 16, 16, "Group: %s", tvb_ip6_to_str(tvb, offset + 8 + 16)); } else proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Dummy header for an unknown protocol"); break; case 4: /* IPv4 */ #if 0 call_dissector(ip_handle, next_tvb, pinfo, tree); #else call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree); #endif break; case 6: /* IPv6 */ #if 0 call_dissector(ipv6_handle, next_tvb, pinfo, tree); #else call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree); #endif break; default: proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Unknown IP version %d", (v_hl & 0xf0) >> 4); break; } break; } case 2: /* register-stop */ { int advance; const char *s; s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s); break; } case 3: /* join/prune */ case 6: /* graft */ case 7: /* graft-ack */ { int advance; int off; const char *s; int ngroup, i, njoin, nprune, j; guint16 holdtime; proto_tree *grouptree = NULL; proto_item *tigroup; proto_tree *subtree = NULL; proto_item *tisub; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Upstream-neighbor: %s", s); offset += advance; proto_tree_add_item(pimopt_tree, hf_pim_res_bytes, tvb, offset, 1, FALSE); offset += 1; /* skip reserved field */ ngroup = tvb_get_guint8(tvb, offset); proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, FALSE); offset += 1; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; for (i = 0; i < ngroup; i++) { s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) goto breakbreak3; tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group %d: %s", i, s); grouptree = proto_item_add_subtree(tigroup, ett_pim); offset += advance; njoin = tvb_get_ntohs(tvb, offset); nprune = tvb_get_ntohs(tvb, offset + 2); tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb, offset, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); off = offset + 4; for (j = 0; j < njoin; j++) { s = dissect_pim_addr(tvb, off, pimv2_source, &advance); if (s == NULL) goto breakbreak3; proto_tree_add_text(subtree, tvb, off, advance, "IP address: %s", s); off += advance; } tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb, offset + 2, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); for (j = 0; j < nprune; j++) { s = dissect_pim_addr(tvb, off, pimv2_source, &advance); if (s == NULL) goto breakbreak3; proto_tree_add_text(subtree, tvb, off, advance, "IP address: %s", s); off += advance; } offset = off; } breakbreak3: break; } case 4: /* bootstrap */ { const char *s; int advance; int i, j; int frpcnt; guint16 holdtime; proto_tree *grouptree = NULL; proto_item *tigroup; proto_tree_add_text(pimopt_tree, tvb, offset, 2, "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset)); offset += 2; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Hash mask len: %u", tvb_get_guint8(tvb, offset)); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "BSR priority: %u", tvb_get_guint8(tvb, offset)); offset += 1; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "BSR: %s", s); offset += advance; for (i = 0; tvb_reported_length_remaining(tvb, offset) > 0; i++) { s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) goto breakbreak4; tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group %d: %s", i, s); grouptree = proto_item_add_subtree(tigroup, ett_pim); offset += advance; proto_tree_add_text(grouptree, tvb, offset, 1, "RP count: %u", tvb_get_guint8(tvb, offset)); offset += 1; frpcnt = tvb_get_guint8(tvb, offset); proto_tree_add_text(grouptree, tvb, offset, 1, "FRP count: %u", frpcnt); offset += 3; for (j = 0; j < frpcnt; j++) { s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) goto breakbreak4; proto_tree_add_text(grouptree, tvb, offset, advance, "RP %d: %s", j, s); offset += advance; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(grouptree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; proto_tree_add_text(grouptree, tvb, offset, 1, "Priority: %u", tvb_get_guint8(tvb, offset)); offset += 2; /* also skips reserved field */ } } breakbreak4: break; } case 5: /* assert */ { const char *s; int advance; guint32 pref; s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s); offset += advance; proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, FALSE); pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff; proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb, offset, 4, pref, "Metric Preference: %u", pref); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, FALSE); offset += 4; break; } case 8: /* Candidate-RP-Advertisement */ { const char *s; int advance; int pfxcnt; guint16 holdtime; int i; pfxcnt = tvb_get_guint8(tvb, offset); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prefix-count: %u", pfxcnt); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Priority: %u", tvb_get_guint8(tvb, offset)); offset += 1; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "RP: %s", s); offset += advance; for (i = 0; i < pfxcnt; i++) { s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) goto breakbreak8; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group %d: %s", i, s); offset += advance; } breakbreak8: break; } case 9: /* State-Refresh */ { const char *s; int advance; guint32 pref; s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Originator: %s", s); offset += advance; proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, FALSE); pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff; proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb, offset, 4, pref, "Metric Preference: %u", pref); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Masklen: %u", tvb_get_guint8(tvb, offset)); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "TTL: %u", tvb_get_guint8(tvb, offset)); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune indicator %s", decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8, "set", "clear")); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune now %s", decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x40, 8, "set", "clear")); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Assert override %s", decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x20, 8, "set", "clear")); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Interval: %u", tvb_get_guint8(tvb, offset)); offset += 1; break; } default: break; } done:; }
static const char * dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at, int *advance) { emem_strbuf_t *strbuf; guint8 af; guint8 et; guint8 flags; guint8 mask_len; int len = 0; af = tvb_get_guint8(tvb, offset); if (af != AFNUM_INET && af != AFNUM_INET6) { /* * We don't handle the other formats, and addresses don't include * a length field, so we can't even show them as raw bytes. */ return NULL; } et = tvb_get_guint8(tvb, offset + 1); if (et != 0) { /* * The only defined encoding type is 0, for the native encoding; * again, as addresses don't include a length field, we can't * even show addresses with a different encoding type as raw * bytes. */ return NULL; } strbuf = ep_strbuf_new_label(NULL); switch (at) { case pimv2_unicast: switch (af) { case AFNUM_INET: len = 4; ep_strbuf_printf(strbuf, "%s", tvb_ip_to_str(tvb, offset + 2)); break; case AFNUM_INET6: len = 16; ep_strbuf_printf(strbuf, "%s", tvb_ip6_to_str(tvb, offset + 2)); break; } if (advance) *advance = 2 + len; break; case pimv2_group: mask_len = tvb_get_guint8(tvb, offset + 3); switch (af) { case AFNUM_INET: len = 4; ep_strbuf_printf(strbuf, "%s/%u", tvb_ip_to_str(tvb, offset + 4), mask_len); break; case AFNUM_INET6: len = 16; ep_strbuf_printf(strbuf, "%s/%u", tvb_ip6_to_str(tvb, offset + 4), mask_len); break; } if (advance) *advance = 4 + len; break; case pimv2_source: flags = tvb_get_guint8(tvb, offset + 2); mask_len = tvb_get_guint8(tvb, offset + 3); switch (af) { case AFNUM_INET: len = 4; ep_strbuf_printf(strbuf, "%s/%u", tvb_ip_to_str(tvb, offset + 4), mask_len); break; case AFNUM_INET6: len = 16; ep_strbuf_printf(strbuf, "%s/%u", tvb_ip6_to_str(tvb, offset + 4), mask_len); break; } if (flags) { ep_strbuf_append_printf(strbuf, " (%s%s%s)", flags & 0x04 ? "S" : "", flags & 0x02 ? "W" : "", flags & 0x01 ? "R" : ""); } if (advance) *advance = 4 + len; break; default: return NULL; } return strbuf->str; }
/* This function is only called from the IGMP dissector */ int dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { guint8 pim_type; guint8 pim_ver; guint length, pim_length; guint16 pim_cksum, computed_cksum; vec_t cksum_vec[1]; proto_tree *pim_tree = NULL; proto_item *ti; proto_tree *pimopt_tree = NULL; proto_item *tiopt; if (!proto_is_protocol_enabled(find_protocol_by_id(proto_pim))) { /* * We are not enabled; skip entire packet to be nice to the * IGMP layer (so clicking on IGMP will display the data). */ return offset+tvb_length_remaining(tvb, offset); } col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIMv1"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE); pim_tree = proto_item_add_subtree(ti, ett_pim); /* Put IGMP type, 0x14, into the tree */ proto_tree_add_text(pim_tree, tvb, offset, 1, "Type: PIM (0x14)"); offset += 1; pim_type = tvb_get_guint8(tvb, offset); if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pim_type, type1vals, "Unknown (%u)")); proto_tree_add_uint(pim_tree, hf_pim_code, tvb, offset, 1, pim_type); offset += 1; pim_cksum = tvb_get_ntohs(tvb, offset); pim_ver = PIM_VER(tvb_get_guint8(tvb, offset + 2)); if (pim_ver != 1) { /* * Not PIMv1 - what gives? */ proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum); offset += 2; proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, FALSE); return offset+tvb_length_remaining(tvb, offset); } /* * Well, it's PIM v1, so we can check whether this is a * Register message, and thus can figure out how much to * checksum and whether to make the columns read-only. */ length = tvb_length(tvb); if (pim_type == 1) { /* * Register message - the PIM header is 8 bytes long. * Also set the columns non-writable. Otherwise the IPv4 or * IPv6 dissector for the encapsulated packet that caused * this register will overwrite the PIM info in the columns. */ pim_length = 8; col_set_writable(pinfo->cinfo, FALSE); } else { /* * Other message - checksum the entire packet. */ pim_length = tvb_reported_length(tvb); } if (!pinfo->fragmented && length >= pim_length) { /* * The packet isn't part of a fragmented datagram and isn't * truncated, so we can checksum it. */ cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length); cksum_vec[0].len = pim_length; computed_cksum = in_cksum(&cksum_vec[0], 1); if (computed_cksum == 0) { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum, "Checksum: 0x%04x [correct]", pim_cksum); } else { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum, "Checksum: 0x%04x [incorrect, should be 0x%04x]", pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum)); } } else { proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum); } offset += 2; proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, FALSE); offset += 1; offset += 3; /* skip reserved stuff */ if (tvb_reported_length_remaining(tvb, offset) > 0) { tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options"); pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts); } else goto done; /* version 1 decoder */ switch (pim_type) { case 0: /* query */ { guint16 holdtime; proto_tree_add_item(pimopt_tree, hf_pim_mode, tvb, offset, 1, FALSE); offset += 2; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; break; } case 1: /* register */ { guint8 v_hl; tvbuff_t *next_tvb; /* * The rest of the packet is a multicast data packet. */ next_tvb = tvb_new_subset_remaining(tvb, offset); /* * It's an IP packet - determine whether it's IPv4 or IPv6. */ v_hl = tvb_get_guint8(tvb, offset); switch((v_hl & 0xf0) >> 4) { case 0: /* Null-Register dummy header. * Has the same address family as the encapsulating PIM packet, * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet. */ if (pinfo->src.type == AT_IPv4) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv4 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4, "Source: %s", tvb_ip_to_str(tvb, offset + 12)); proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4, "Group: %s", tvb_ip_to_str(tvb, offset + 16)); } else if (pinfo->src.type == AT_IPv6) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv6 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 8, 16, "Source: %s", tvb_ip6_to_str(tvb, offset + 8)); proto_tree_add_text(pimopt_tree, tvb, offset + 8 + 16, 16, "Group: %s", tvb_ip6_to_str(tvb, offset + 8)); } else proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Dummy header for an unknown protocol"); break; case 4: /* IPv4 */ #if 0 call_dissector(ip_handle, next_tvb, pinfo, tree); #else call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree); #endif break; case 6: /* IPv6 */ #if 0 call_dissector(ipv6_handle, next_tvb, pinfo, tree); #else call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree); #endif break; default: proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Unknown IP version %d", (v_hl & 0xf0) >> 4); break; } break; } case 2: /* register-stop */ { proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Source: %s", tvb_ip_to_str(tvb, offset)); offset += 4; break; } case 3: /* join/prune */ case 6: /* graft */ case 7: /* graft-ack */ { int off; const char *s; int ngroup, i, njoin, nprune, j; guint16 holdtime; guint8 mask_len; guint8 adr_len; proto_tree *grouptree = NULL; proto_item *tigroup; proto_tree *subtree = NULL; proto_item *tisub; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Upstream-neighbor: %s", tvb_ip_to_str(tvb, offset)); offset += 4; offset += 2; /* skip reserved stuff */ holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; offset += 1; /* skip reserved stuff */ mask_len = tvb_get_guint8(tvb, offset); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Mask length: %u", mask_len); offset += 1; adr_len = tvb_get_guint8(tvb, offset); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Address length: %u", adr_len); offset += 1; ngroup = tvb_get_guint8(tvb, offset); proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, FALSE); offset += 1; for (i = 0; i < ngroup; i++) { /* * XXX - does the group address have the length "adr_len" * and the group mask the length "mask_len"? */ tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group %d: %s", i, tvb_ip_to_str(tvb, offset)); grouptree = proto_item_add_subtree(tigroup, ett_pim); offset += 4; proto_tree_add_text(grouptree, tvb, offset, 4, "Group %d Mask: %s", i, tvb_ip_to_str(tvb, offset)); offset += 4; njoin = tvb_get_ntohs(tvb, offset); nprune = tvb_get_ntohs(tvb, offset + 2); tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb, offset, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); off = offset + 4; for (j = 0; j < njoin; j++) { s = dissect_pimv1_addr(tvb, off); proto_tree_add_text(subtree, tvb, off, 6, "IP address: %s", s); off += 6; } tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb, offset + 2, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); for (j = 0; j < nprune; j++) { s = dissect_pimv1_addr(tvb, off); proto_tree_add_text(subtree, tvb, off, 6, "IP address: %s", s); off += 6; } offset = off; } break; } case 4: /* rp-reachability */ { guint16 holdtime; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Address: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Mask: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "RP Address: %s", tvb_ip_to_str(tvb, offset)); offset += 4; offset += 2; /* skip reserved stuff */ holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; break; } case 5: /* assert */ { guint32 pref; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Address: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Mask: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, FALSE); pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff; proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb, offset, 4, pref, "Metric Preference: %u", pref); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, FALSE); offset += 4; break; } default: break; } done:; return offset+tvb_length_remaining(tvb, offset); }
static int dissect_bencoded_dict_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset ) { proto_item *ti; proto_tree *sub_tree; gboolean tohex; char *key, *val; guint orig_offset = offset; key = NULL; val = NULL; ti = proto_tree_add_item( tree, hf_bencoded_dict_entry, tvb, offset, 0, ENC_NA ); sub_tree = proto_item_add_subtree( ti, ett_bencoded_dict_entry); /* dissect the key, it must be a string */ offset = dissect_bencoded_string( tvb, pinfo, sub_tree, offset, &key, FALSE, "Key" ); /* If it is a dict, then just do recursion */ switch( tvb_get_guint8(tvb,offset) ) { case 'd': offset = dissect_bencoded_dict( tvb, pinfo, sub_tree, offset, "Value" ); val = (char*)dict_str; break; case 'l': if( strcmp(key,"e")==0 ) offset = dissect_bt_dht_error( tvb, pinfo, sub_tree, offset, &val, "Value" ); else if( strcmp(key,"values")==0 ) offset = dissect_bt_dht_values( tvb, pinfo, sub_tree, offset, &val, "Value" ); /* other unfamiliar lists */ else { offset = dissect_bencoded_list( tvb, pinfo, sub_tree, offset, "Value" ); val = (char*)list_str; } break; case 'i': offset = dissect_bencoded_int( tvb, pinfo, sub_tree, offset, &val, "Value" ); break; /* it's a string */ default: /* special process */ if( strcmp(key,"nodes")==0 ) { offset = dissect_bt_dht_nodes( tvb, pinfo, sub_tree, offset, &val, "Value" ); } else if( strcmp(key,"ip")==0 ) { /* * Not found in BEP 0005 but explained by * http://www.rasterbar.com/products/libtorrent/dht_sec.html */ int len, old_offset; old_offset = offset; len = bencoded_string_length(tvb, &offset); if(len == 4) { proto_tree_add_item(sub_tree, hf_ip, tvb, offset, len, ENC_BIG_ENDIAN); val = (char*)tvb_ip_to_str(tvb, offset); offset += len; } else { offset = dissect_bencoded_string( tvb, pinfo, sub_tree, old_offset, &val, TRUE, "Value" ); } } else { /* some need to return hex string */ tohex = strcmp(key,"id")==0 || strcmp(key,"target")==0 || strcmp(key,"info_hash")==0 || strcmp(key,"t")==0 || strcmp(key,"v")==0 || strcmp(key,"token")==0; offset = dissect_bencoded_string( tvb, pinfo, sub_tree, offset, &val, tohex, "Value" ); } } if( strlen(key)==1 ) key = (char*)val_to_str_const( key[0], short_key_name_value_string, key ); if( strlen(val)==1 ) val = (char*)val_to_str_const( val[0], short_val_name_value_string, val ); proto_item_set_text( ti, "%s: %s", key, val ); proto_item_set_len( ti, offset-orig_offset ); if( strcmp(key,"message_type")==0 || strcmp(key,"request_type")==0 ) col_append_fstr(pinfo->cinfo, COL_INFO, "%s=%s ", key, val); return offset; }