static void dissect_conn_control(tvbuff_t *tvb, int offset, proto_tree *tree) { guint8 conn_control; proto_item *ti; proto_tree *cc_tree; if (tree) { conn_control = tvb_get_guint8(tvb, offset); ti = proto_tree_add_text(tree, tvb, offset, 1, "Connection control: 0x%02x", conn_control); cc_tree = proto_item_add_subtree(ti, ett_nbipx_conn_ctrl); proto_tree_add_text(cc_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(conn_control, 0x80, 8, "System packet", "Non-system packet")); proto_tree_add_text(cc_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(conn_control, 0x40, 8, "Acknowledgement required", "Acknowledgement not required")); proto_tree_add_text(cc_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(conn_control, 0x20, 8, "Attention", "No attention")); proto_tree_add_text(cc_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(conn_control, 0x10, 8, "End of message", "No end of message")); proto_tree_add_text(cc_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(conn_control, 0x08, 8, "Resend", "No resend")); } }
static void dissect_tacplus_body_acct_req( tvbuff_t* tvb, proto_tree *tree ) { int val, var_off; proto_item *tf; proto_tree *flags_tree; val=tvb_get_guint8( tvb, ACCT_Q_FLAGS_OFF ); tf = proto_tree_add_uint( tree, hf_tacplus_acct_flags, tvb, ACCT_Q_FLAGS_OFF, 1, val ); flags_tree = proto_item_add_subtree( tf, ett_tacplus_acct_flags ); proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s", decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_MORE, 8, "More: Set", "More: Not set" ) ); proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s", decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_START, 8, "Start: Set", "Start: Not set" ) ); proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s", decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_STOP, 8, "Stop: Set", "Stop: Not set" ) ); proto_tree_add_text( flags_tree, tvb, ACCT_Q_FLAGS_OFF, 1, "%s", decode_boolean_bitfield( val, TAC_PLUS_ACCT_FLAG_WATCHDOG, 8, "Watchdog: Set", "Watchdog: Not set" ) ); val=tvb_get_guint8( tvb, ACCT_Q_METHOD_OFF ); proto_tree_add_text( tree, tvb, ACCT_Q_METHOD_OFF, 1, "Authen Method: 0x%01x (%s)", val, val_to_str( val, tacplus_authen_method, "Unknown Authen Method" ) ); val=tvb_get_guint8( tvb, ACCT_Q_ARG_CNT_OFF ); /* authen_type */ var_off=proto_tree_add_tacplus_common_fields( tvb, tree , ACCT_Q_PRIV_LVL_OFF, ACCT_Q_VARDATA_OFF+val ); proto_tree_add_text( tree, tvb, ACCT_Q_ARG_CNT_OFF, 1, "Arg Cnt: %d", val ); dissect_tacplus_args_list( tvb, tree, var_off, ACCT_Q_VARDATA_OFF, val ); }
static int dissect_nfsacl_mask(tvbuff_t *tvb, int offset, proto_tree *tree, const char *name) { guint32 mask; proto_item *mask_item = NULL; proto_tree *mask_tree = NULL; mask = tvb_get_ntohl(tvb, offset + 0); if (tree) { mask_item = proto_tree_add_text(tree, tvb, offset, 4, "%s: 0x%02x", name, mask); if (mask_item) mask_tree = proto_item_add_subtree(mask_item, ett_nfsacl_mask); } if (mask_tree) { proto_tree_add_text(mask_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(mask, 0x01, 8, "ACL entry", "(no ACL entry)")); proto_tree_add_text(mask_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(mask, 0x02, 8, "ACL count", "(no ACL count)")); proto_tree_add_text(mask_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(mask, 0x04, 8, "default ACL entry", "(no default ACL entry)")); proto_tree_add_text(mask_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(mask, 0x08, 8, "default ACL count", "(no default ACL count)")); } offset += 4; return offset; }
/* dissect 9P Qid */ static void dissect_9P_qid(tvbuff_t * tvb, proto_tree * tree,int offset) { proto_item *qid_item,*qidtype_item; proto_tree *qid_tree,*qidtype_tree; guint64 path; guint32 vers; guint8 type; if(!tree) return; type = tvb_get_guint8(tvb,offset); vers = tvb_get_letohs(tvb,offset+1); path = tvb_get_letoh64(tvb,offset+1+4); qid_item = proto_tree_add_text(tree,tvb,offset,13,"Qid type=0x%02x vers=%d path=%" G_GINT64_MODIFIER "u",type,vers,path); qid_tree = proto_item_add_subtree(qid_item,ett_9P_qid); qidtype_item = proto_tree_add_item(qid_tree, hf_9P_qidtype, tvb, offset, 1, TRUE); qidtype_tree = proto_item_add_subtree(qidtype_item,ett_9P_qidtype); proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(type, QTDIR, 8, "Directory", "not a Directory")); proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(type, QTAPPEND, 8, "Append only", "not Append only")); proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(type, QTEXCL, 8, "Exclusive use", "not Exclusive use")); proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(type, QTMOUNT, 8, "Mounted channel", "not a Mounted channel")); proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(type, QTAUTH, 8, "Authentication file", "not an Authentication file")); proto_tree_add_text(qidtype_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(type, QTTMP, 8, "Temporary file (not backed up)", "not a Temporary file")); proto_tree_add_item(qid_tree, hf_9P_qidvers, tvb, offset+1, 4, TRUE); proto_tree_add_item(qid_tree, hf_9P_qidpath, tvb, offset+1+4, 8, TRUE); }
/* * 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, ENC_NA); pim_tree = proto_item_add_subtree(ti, ett_pim); proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(pim_tree, hf_pim_type, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(pim_tree, hf_pim_res_bytes, tvb, offset + 1, 1, ENC_NA); 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, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_pim_optionlength, tvb, offset + 2, 2, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_pim_propagation_delay, tvb, offset + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_pim_override_interval, tvb, offset + 6, 2, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_pim_state_refresh_interval, tvb, offset + 5, 1, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_pim_state_refresh_reserved, tvb, offset + 6, 2, ENC_BIG_ENDIAN); 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, ENC_NA); 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, ENC_NA); offset += 1; /* skip reserved field */ ngroup = tvb_get_guint8(tvb, offset); proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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, ENC_BIG_ENDIAN); 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:; }
/*dissect 9P stat mode and create perm flags */ static void dissect_9P_dm(tvbuff_t * tvb, proto_item * item,int offset,int iscreate) { proto_item *mode_tree; guint32 dm; dm = tvb_get_letohl(tvb,offset); mode_tree = proto_item_add_subtree(item, ett_9P_dm); if(!mode_tree) return; proto_tree_add_text(mode_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(dm, DMDIR, 32, "Directory", "not a Directory")); if(!iscreate) { /* Not applicable to Tcreate (?) */ proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, DMAPPEND, 32, "Append only", "not Append only")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, DMEXCL, 32, "Exclusive use", "not Exclusive use")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, DMMOUNT, 32, "Mounted channel", "not a Mounted channel")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, DMAUTH, 32, "Authentication file", "not an Authentication file")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, DMTMP, 32, "Temporary file (not backed up)", "not a Temporary file")); } proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 0400, 32, "Read permission for owner", "no Read permission for owner")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 0200, 32, "Write permission for owner", "no Write permission for owner")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 0100, 32, "Execute permission for owner", "no Execute permission for owner")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 040, 32, "Read permission for group", "no Read permission for group")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 020, 32, "Write permission for group", "no Write permission for group")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 010, 32, "Execute permission for group", "no Execute permission for group")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 04, 32, "Read permission for others", "no Read permission for others")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 02, 32, "Write permission for others", "no Write permission for others")); proto_tree_add_text(mode_tree, tvb, offset, 4, "%s", decode_boolean_bitfield(dm, 01, 32, "Execute permission for others", "no Execute permission for others")); }
static void dissect_nbipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean has_routes; proto_tree *nbipx_tree = NULL; proto_item *ti = NULL; int offset = 0; guint8 packet_type; guint8 name_type_flag; proto_tree *name_type_flag_tree; proto_item *tf; char name[(NETBIOS_NAME_LEN - 1)*4 + 1]; int name_type; gboolean has_payload; tvbuff_t *next_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBIPX"); col_clear(pinfo->cinfo, COL_INFO); if (pinfo->ipxptype == IPX_PACKET_TYPE_WANBCAST) { /* * This is a WAN Broadcast packet; we assume it will have * 8 IPX addresses at the beginning. */ has_routes = TRUE; } else { /* * This isn't a WAN Broadcast packet, but it still might * have the 8 addresses. * * If it's the right length for a name operation, * and, if we assume it has routes, the packet type * is a name operation, assume it has routes. * * NOTE: this will throw an exception if the byte that * would be the packet type byte if this has the 8 * addresses isn't present; if that's the case, we don't * know how to interpret this packet, so we can't dissect * it anyway. */ has_routes = FALSE; /* start out assuming it doesn't */ if (tvb_reported_length(tvb) == 50) { packet_type = tvb_get_guint8(tvb, offset + 32 + 1); switch (packet_type) { case NBIPX_FIND_NAME: case NBIPX_NAME_RECOGNIZED: case NBIPX_CHECK_NAME: case NBIPX_NAME_IN_USE: case NBIPX_DEREGISTER_NAME: has_routes = TRUE; break; } } } if (tree) { ti = proto_tree_add_item(tree, proto_nbipx, tvb, 0, -1, FALSE); nbipx_tree = proto_item_add_subtree(ti, ett_nbipx); } if (has_routes) { if (tree) add_routers(nbipx_tree, tvb, 0); offset += 32; } packet_type = tvb_get_guint8(tvb, offset + 1); switch (packet_type) { case NBIPX_FIND_NAME: case NBIPX_NAME_RECOGNIZED: case NBIPX_CHECK_NAME: case NBIPX_NAME_IN_USE: case NBIPX_DEREGISTER_NAME: name_type_flag = tvb_get_guint8(tvb, offset); name_type = get_netbios_name(tvb, offset+2, name, (NETBIOS_NAME_LEN - 1)*4 + 1); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s<%02x>", val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown"), name, name_type); } if (nbipx_tree) { tf = proto_tree_add_text(nbipx_tree, tvb, offset, 1, "Name type flag: 0x%02x", name_type_flag); name_type_flag_tree = proto_item_add_subtree(tf, ett_nbipx_name_type_flags); proto_tree_add_text(name_type_flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(name_type_flag, 0x80, 8, "Group name", "Unique name")); proto_tree_add_text(name_type_flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(name_type_flag, 0x40, 8, "Name in use", "Name not used")); proto_tree_add_text(name_type_flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(name_type_flag, 0x04, 8, "Name registered", "Name not registered")); proto_tree_add_text(name_type_flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(name_type_flag, 0x02, 8, "Name duplicated", "Name not duplicated")); proto_tree_add_text(name_type_flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(name_type_flag, 0x01, 8, "Name deregistered", "Name not deregistered")); } offset += 1; dissect_packet_type(tvb, offset, packet_type, nbipx_tree); offset += 1; if (nbipx_tree) netbios_add_name("Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; /* * No payload to be interpreted by another protocol. */ has_payload = FALSE; break; case NBIPX_SESSION_DATA: case NBIPX_SESSION_END: case NBIPX_SESSION_END_ACK: if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown")); } dissect_conn_control(tvb, offset, nbipx_tree); offset += 1; dissect_packet_type(tvb, offset, packet_type, nbipx_tree); offset += 1; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Source connection ID: 0x%04X", tvb_get_letohs(tvb, offset)); } offset += 2; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Destination connection ID: 0x%04X", tvb_get_letohs(tvb, offset)); } offset += 2; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Send sequence number: %u", tvb_get_letohs(tvb, offset)); } offset += 2; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Total data length: %u", tvb_get_letohs(tvb, offset)); } offset += 2; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Offset: %u", tvb_get_letohs(tvb, offset)); } offset += 2; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Data length: %u", tvb_get_letohs(tvb, offset)); } offset += 2; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Receive sequence number: %u", tvb_get_letohs(tvb, offset)); } offset += 2; if (nbipx_tree) { proto_tree_add_text(nbipx_tree, tvb, offset, 2, "Bytes received: %u", tvb_get_letohs(tvb, offset)); } offset += 2; /* * We may have payload to dissect. */ has_payload = TRUE; break; case NBIPX_DIRECTED_DATAGRAM: if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown")); } dissect_conn_control(tvb, offset, nbipx_tree); offset += 1; dissect_packet_type(tvb, offset, packet_type, nbipx_tree); offset += 1; if (nbipx_tree) netbios_add_name("Receiver's Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; if (nbipx_tree) netbios_add_name("Sender's Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; /* * We may have payload to dissect. */ has_payload = TRUE; break; default: if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(packet_type, nbipx_data_stream_type_vals, "Unknown")); } /* * We don't know what the first byte is. */ offset += 1; /* * The second byte is a data stream type byte. */ dissect_packet_type(tvb, offset, packet_type, nbipx_tree); offset += 1; /* * We don't know what the rest of the packet is. */ has_payload = FALSE; } /* * Set the length of the NBIPX tree item. */ if (ti != NULL) proto_item_set_len(ti, offset); if (has_payload && tvb_offset_exists(tvb, offset)) { next_tvb = tvb_new_subset_remaining(tvb, offset); dissect_netbios_payload(next_tvb, pinfo, tree); } }
static void dissect_lsp_link_info_clv(tvbuff_t *tvb, proto_tree *tree, int offset, int length) { guint8 flags_cost; if (length < 1) { nlsp_dissect_unknown(tvb, tree, offset, "Short link info entry"); return; } if (tree) { flags_cost = tvb_get_guint8(tvb, offset); proto_tree_add_text(tree, tvb, offset, 1, "%s", decode_boolean_bitfield(flags_cost, 0x80, 1*8, "Cost not present", "Cost present")); if (!(flags_cost & 0x80)) { /* * 0x80 clear => cost present. */ proto_tree_add_text(tree, tvb, offset, 1, "%s", decode_boolean_bitfield(flags_cost, 0x40, 1*8, "Cost is internal metric", "Cost is external metric")); proto_tree_add_text(tree, tvb, offset, 1, "%s", decode_numeric_bitfield(flags_cost, 0x3F, 1*8, "Cost = %u")); } } offset += 1; length -= 1; if (length < 3) { nlsp_dissect_unknown(tvb, tree, offset, "Short link info entry"); return; } offset += 3; /* Reserved */ length -= 3; if (length < 7) { nlsp_dissect_unknown(tvb, tree, offset, "Short link info entry"); return; } if (tree) { proto_tree_add_text(tree, tvb, offset, 6, "Router System ID: %s", tvb_ether_to_str(tvb, offset)); proto_tree_add_text(tree, tvb, offset+6, 1, "Router Pseudonode ID: %u", tvb_get_guint8(tvb, offset+6)); } offset += 7; length -= 7; if (length < 4) { nlsp_dissect_unknown(tvb, tree, offset, "Short link info entry"); return; } if (tree) { proto_tree_add_text(tree, tvb, offset, 4, "MTU Size: %u", tvb_get_ntohl(tvb, offset)); } offset += 4; length -= 4; if (length < 4) { nlsp_dissect_unknown(tvb, tree, offset, "Short link info entry"); return; } if (tree) { proto_tree_add_text(tree, tvb, offset, 4, "Delay: %uus", tvb_get_ntohl(tvb, offset)); } offset += 4; length -= 4; if (length < 4) { nlsp_dissect_unknown(tvb, tree, offset, "Short link info entry"); return; } if (tree) { proto_tree_add_text(tree, tvb, offset, 4, "Throughput: %u bits/s", tvb_get_ntohl(tvb, offset)); } offset += 4; length -= 4; if (length < 2) { nlsp_dissect_unknown(tvb, tree, offset, "Short link info entry"); return; } if (tree) { proto_tree_add_text(tree, tvb, offset, 2, "Media type: %s", val_to_str(tvb_get_ntohs(tvb, offset), media_type_vals, "Unknown (0x%04x)")); } offset += 2; length -= 2; }
static void dissect_cups(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *cups_tree = 0; proto_tree *ptype_subtree = 0; proto_item *ti = 0; gint offset = 0; gint next_offset; guint len; unsigned int u; const guint8 *str; cups_ptype_t ptype; unsigned int state; if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_CUPS); col_clear(pinfo->cinfo, COL_INFO); if (tree) { ti = proto_tree_add_item(tree, proto_cups, tvb, offset, -1, FALSE); cups_tree = proto_item_add_subtree(ti, ett_cups); } /* Format (1450 bytes max.): */ /* type state uri ["location" ["info" ["make-and-model"]]]\n */ ptype = get_hex_uint(tvb, offset, &next_offset); len = next_offset - offset; if (len != 0) { if (cups_tree) { ti = proto_tree_add_uint(cups_tree, hf_cups_ptype, tvb, offset, len, ptype); ptype_subtree = proto_item_add_subtree(ti, ett_cups_ptype); for (u = 0; u < N_CUPS_PTYPE_BITS; u++) { proto_tree_add_text(ptype_subtree, tvb, offset, len, "%s", decode_boolean_bitfield(ptype, cups_ptype_bits[u].bit, sizeof (ptype)*8, cups_ptype_bits[u].on_string, cups_ptype_bits[u].off_string)); } } } offset = next_offset; if (!skip_space(tvb, offset, &next_offset)) return; /* end of packet */ offset = next_offset; state = get_hex_uint(tvb, offset, &next_offset); len = next_offset - offset; if (len != 0) { if (cups_tree) proto_tree_add_uint(cups_tree, hf_cups_state, tvb, offset, len, state); } offset = next_offset; if (!skip_space(tvb, offset, &next_offset)) return; /* end of packet */ offset = next_offset; str = get_unquoted_string(tvb, offset, &next_offset, &len); if (str == NULL) return; /* separator/terminator not found */ if (cups_tree) proto_tree_add_text(cups_tree, tvb, offset, len, "URI: %.*s", (guint16) len, str); if (check_col(pinfo->cinfo, COL_INFO)) col_add_fstr(pinfo->cinfo, COL_INFO, "%.*s (%s)", (guint16) len, str, val_to_str(state, cups_state_values, "0x%x")); offset = next_offset; if (!cups_tree) return; if (!skip_space(tvb, offset, &next_offset)) return; /* end of packet */ offset = next_offset; str = get_quoted_string(tvb, offset, &next_offset, &len); if (str == NULL) return; /* separator/terminator not found */ proto_tree_add_text(cups_tree, tvb, offset+1, len, "Location: \"%.*s\"", (guint16) len, str); offset = next_offset; if (!skip_space(tvb, offset, &next_offset)) return; /* end of packet */ offset = next_offset; str = get_quoted_string(tvb, offset, &next_offset, &len); if (str == NULL) return; /* separator/terminator not found */ proto_tree_add_text(cups_tree, tvb, offset+1, len, "Information: \"%.*s\"", (guint16) len, str); offset = next_offset; if (!skip_space(tvb, offset, &next_offset)) return; /* end of packet */ offset = next_offset; str = get_quoted_string(tvb, offset, &next_offset, &len); if (str == NULL) return; /* separator/terminator not found */ proto_tree_add_text(cups_tree, tvb, offset+1, len, "Make and model: \"%.*s\"", (guint16) len, str); offset = next_offset; return; }
static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *clnp_tree = NULL; proto_item *ti; guint8 cnf_proto_id; guint8 cnf_hdr_len; guint8 cnf_vers; guint8 cnf_ttl; guint8 cnf_type; char flag_string[6+1]; const char *pdu_type_string; proto_tree *type_tree; guint16 segment_length; guint16 du_id = 0; guint16 segment_offset = 0; guint16 cnf_cksum; cksum_status_t cksum_status; int offset; guchar src_len, dst_len, nsel, opt_len = 0; const guint8 *dst_addr, *src_addr; guint next_length; proto_tree *discpdu_tree; gboolean save_in_error_pkt; fragment_data *fd_head; tvbuff_t *next_tvb; gboolean update_col_info = TRUE; gboolean save_fragmented; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP"); col_clear(pinfo->cinfo, COL_INFO); cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID); if (cnf_proto_id == NLPID_NULL) { col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset"); if (tree) { ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id, "Inactive subset"); } next_tvb = tvb_new_subset_remaining(tvb, 1); if (call_dissector(ositp_inactive_handle, next_tvb, pinfo, tree) == 0) call_dissector(data_handle,tvb, pinfo, tree); return; } /* return if version not known */ cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS); if (cnf_vers != ISO8473_V1) { call_dissector(data_handle,tvb, pinfo, tree); return; } /* fixed part decoding */ cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN); opt_len = cnf_hdr_len; if (tree) { ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id); proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1, cnf_hdr_len); proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1, cnf_vers); cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL); proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1, cnf_ttl, "Holding Time : %u (%u.%u secs)", cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5); } cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE); pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals, "Unknown (0x%02x)"); flag_string[0] = '\0'; if (cnf_type & CNF_SEG_OK) g_strlcat(flag_string, "S ", 7); if (cnf_type & CNF_MORE_SEGS) g_strlcat(flag_string, "M ", 7); if (cnf_type & CNF_ERR_OK) g_strlcat(flag_string, "E ", 7); if (tree) { ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1, cnf_type, "PDU Type : 0x%02x (%s%s)", cnf_type, flag_string, pdu_type_string); type_tree = proto_item_add_subtree(ti, ett_clnp_type); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8, "Segmentation permitted", "Segmentation not permitted")); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8, "More segments", "Last segment")); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8, "Report error if PDU discarded", "Don't report error if PDU discarded")); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8, npdu_type_vals, "%s")); } /* If we don't have the full header - i.e., not enough to see the segmentation part and determine whether this datagram is segmented or not - set the Info column now; we'll get an exception before we set it otherwise. */ if (tvb_length(tvb) < cnf_hdr_len) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); } segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN); cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM); cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2, segment_length); switch (cksum_status) { default: /* * No checksum present, or not enough of the header present to * checksum it. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x", cnf_cksum); break; case CKSUM_OK: /* * Checksum is correct. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x (correct)", cnf_cksum); break; case CKSUM_NOT_OK: /* * Checksum is not correct. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x (incorrect)", cnf_cksum); break; } opt_len -= 9; /* Fixed part of Hesder */ } /* tree */ /* address part */ offset = P_CLNP_ADDRESS_PART; dst_len = tvb_get_guint8(tvb, offset); dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len); nsel = tvb_get_guint8(tvb, offset + dst_len); src_len = tvb_get_guint8(tvb, offset + dst_len + 1); src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1, dst_len); proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len, dst_addr, " DA : %s", print_nsap_net(dst_addr, dst_len)); proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb, offset + 1 + dst_len, 1, src_len); proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb, offset + dst_len + 2, src_len, src_addr, " SA : %s", print_nsap_net(src_addr, src_len)); opt_len -= dst_len + src_len +2; } SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr); SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr); SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr); SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr); /* Segmentation Part */ offset += dst_len + src_len + 2; if (cnf_type & CNF_SEG_OK) { #if 0 struct clnp_segment seg; /* XXX - not used */ tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */ #endif segment_offset = tvb_get_ntohs(tvb, offset + 2); du_id = tvb_get_ntohs(tvb, offset); if (tree) { proto_tree_add_text(clnp_tree, tvb, offset, 2, "Data unit identifier: %06u", du_id); proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2, "Segment offset : %6u", segment_offset); proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2, "Total length : %6u", tvb_get_ntohs(tvb, offset + 4)); } offset += 6; opt_len -= 6; } if (tree) { /* To do : decode options */ #if 0 proto_tree_add_text(clnp_tree, tvb, offset, cnf_hdr_len - offset, "Options/Data: <not shown>"); #endif /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/ dissect_osi_options( opt_len, tvb, offset, clnp_tree ); } offset = cnf_hdr_len; /* If clnp_reassemble is on, this is a segment, we have all the * data in the segment, and the checksum is valid, then just add the * segment to the hashtable. */ save_fragmented = pinfo->fragmented; if (clnp_reassemble && (cnf_type & CNF_SEG_OK) && ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) && tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) && segment_length > cnf_hdr_len && cksum_status != CKSUM_NOT_OK) { fd_head = fragment_add_check(tvb, offset, pinfo, du_id, clnp_segment_table, clnp_reassembled_table, segment_offset, segment_length - cnf_hdr_len, cnf_type & CNF_MORE_SEGS); next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP", fd_head, &clnp_frag_items, &update_col_info, clnp_tree); } else { /* If this is the first segment, dissect its contents, otherwise just show it as a segment. XXX - if we eventually don't save the reassembled contents of all segmented datagrams, we may want to always reassemble. */ if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) { /* Not the first segment - don't dissect it. */ next_tvb = NULL; } else { /* First segment, or not segmented. Dissect what we have here. */ /* Get a tvbuff for the payload. */ next_tvb = tvb_new_subset_remaining(tvb, offset); /* * If this is the first segment, but not the only segment, * tell the next protocol that. */ if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS)) pinfo->fragmented = TRUE; else pinfo->fragmented = FALSE; } } if (next_tvb == NULL) { /* Just show this as a segment. */ col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)", pdu_type_string, flag_string, segment_offset); /* As we haven't reassembled anything, we haven't changed "pi", so we don't have to restore it. */ call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); pinfo->fragmented = save_fragmented; return; } if (tvb_offset_exists(tvb, offset)) { switch (cnf_type & CNF_TYPE) { case DT_NPDU: case MD_NPDU: /* Continue with COTP if any data. XXX - if this isn't the first Derived PDU of a segmented Initial PDU, skip that? */ if (nsel == (guchar)tp_nsap_selector || always_decode_transport) { if (call_dissector(ositp_handle, next_tvb, pinfo, tree) != 0) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be COTP or CLTP */ } } if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb, pinfo, tree)) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be one of the protocols in the heuristic list */ } break; case ER_NPDU: /* The payload is the header and "none, some, or all of the data part of the discarded PDU", i.e. it's like an ICMP error; dissect it as a CLNP PDU. */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); next_length = tvb_length_remaining(tvb, offset); if (next_length != 0) { /* We have payload; dissect it. */ ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length, "Discarded PDU"); discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu); /* Save the current value of the "we're inside an error packet" flag, and set that flag; subdissectors may treat packets that are the payload of error packets differently from "real" packets. */ save_in_error_pkt = pinfo->flags.in_error_pkt; pinfo->flags.in_error_pkt = TRUE; call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree); /* Restore the "we're inside an error packet" flag. */ pinfo->flags.in_error_pkt = save_in_error_pkt; } pinfo->fragmented = save_fragmented; return; /* we're done with this PDU */ case ERQ_NPDU: case ERP_NPDU: /* XXX - dissect this */ break; } } col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); call_dissector(data_handle,next_tvb, pinfo, tree); pinfo->fragmented = save_fragmented; } /* dissect_clnp */