static void esis_dissect_esh_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo) { proto_tree *esis_area_tree; int offset = 0; int no_sa = 0; int sal = 0; proto_item *ti; offset += ESIS_HDR_FIXED_LENGTH; no_sa = tvb_get_guint8(tvb, offset); len -= 1; ti = proto_tree_add_uint( tree, hf_esis_number_of_source_addresses, tvb, offset, 1, no_sa); offset++; esis_area_tree = proto_item_add_subtree( ti, ett_esis_area_addr ); while ( no_sa-- > 0 ) { sal = (int) tvb_get_guint8(tvb, offset); proto_tree_add_uint_format_value(esis_area_tree, hf_esis_sal, tvb, offset, 1, sal, "%2u Octets", sal); offset++; proto_tree_add_string(esis_area_tree, hf_esis_sa, tvb, offset, sal, print_nsap_net(tvb, offset, sal ) ); offset += sal; len -= ( sal + 1 ); } dissect_osi_options( len, tvb, offset, tree, pinfo ); } /* esis_dissect_esh_pdu */
static void esis_dissect_esh_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) { proto_tree *esis_area_tree; int offset = 0; int no_sa = 0; int sal = 0; proto_item *ti; if (tree) { offset += ESIS_HDR_FIXED_LENGTH; no_sa = tvb_get_guint8(tvb, offset); len -= 1; ti = proto_tree_add_text( tree, tvb, offset, -1, "Number of Source Addresses (SA, Format: NSAP) : %u", no_sa ); offset++; esis_area_tree = proto_item_add_subtree( ti, ett_esis_area_addr ); while ( no_sa-- > 0 ) { sal = (int) tvb_get_guint8(tvb, offset); proto_tree_add_text(esis_area_tree, tvb, offset, 1, "SAL: %2u Octets", sal); offset++; proto_tree_add_text(esis_area_tree, tvb, offset, sal, " SA: %s", print_nsap_net( tvb_get_ptr(tvb, offset, sal), sal ) ); offset += sal; len -= ( sal + 1 ); } dissect_osi_options( len, tvb, offset, tree ); } } /* esis_dissect_esh_pdu */
static void esis_dissect_redirect_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) { int offset = 0; int tmpl = 0; if (tree) { offset += ESIS_HDR_FIXED_LENGTH; tmpl = (int) tvb_get_guint8(tvb, offset); proto_tree_add_text( tree, tvb, offset, tmpl + 1, "### Destination Address Section ###" ); proto_tree_add_text( tree, tvb, offset++, 1, "DAL: %2u Octets", tmpl); proto_tree_add_text( tree, tvb, offset, tmpl, " DA : %s", print_nsap_net( tvb_get_ptr(tvb, offset, tmpl), tmpl ) ); offset += tmpl; len -= ( tmpl + 1 ); tmpl = (int) tvb_get_guint8(tvb, offset); proto_tree_add_text( tree, tvb, offset, tmpl + 1, "### Subnetwork Address Section ###"); proto_tree_add_text( tree, tvb, offset++, 1, "BSNPAL: %2u Octets", tmpl); proto_tree_add_text( tree, tvb, offset, tmpl, " BSNPA: %s", print_system_id( tvb_get_ptr(tvb, offset, tmpl), tmpl ) ); offset += tmpl; len -= ( tmpl + 1 ); tmpl = (int) tvb_get_guint8(tvb, offset); if ( 0 == tmpl ) { proto_tree_add_text( tree, tvb, offset, 1, "### No Network Entity Title Section ###" ); offset++; len--; } else { proto_tree_add_text( tree, tvb, offset, 1, "### Network Entity Title Section ###" ); proto_tree_add_text( tree, tvb, offset++, 1, "NETL: %2u Octets", tmpl ); proto_tree_add_text( tree, tvb, offset, tmpl, " NET: %s", print_nsap_net( tvb_get_ptr(tvb, offset, tmpl), tmpl ) ); offset += tmpl; len -= ( tmpl + 1 ); } dissect_osi_options( len, tvb, offset, tree ); } }
static void esis_dissect_redirect_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo) { int offset = 0; int tmpl = 0; proto_tree *dest_tree, *subnet_tree, *network_tree; offset += ESIS_HDR_FIXED_LENGTH; tmpl = (int) tvb_get_guint8(tvb, offset); dest_tree = proto_tree_add_subtree( tree, tvb, offset, tmpl + 1, ett_esis_dest_addr, NULL, "### Destination Address Section ###" ); proto_tree_add_uint_format_value(dest_tree, hf_esis_dal, tvb, offset++, 1, tmpl, "%2u Octets", tmpl); proto_tree_add_string( dest_tree, hf_esis_da, tvb, offset, tmpl, print_nsap_net( tvb, offset, tmpl ) ); offset += tmpl; len -= ( tmpl + 1 ); tmpl = (int) tvb_get_guint8(tvb, offset); subnet_tree = proto_tree_add_subtree( tree, tvb, offset, tmpl + 1, ett_esis_subnetwork, NULL, "### Subnetwork Address Section ###"); proto_tree_add_uint_format_value(subnet_tree, hf_esis_bsnpal, tvb, offset++, 1, tmpl, "%2u Octets", tmpl); proto_tree_add_item(subnet_tree, hf_esis_bsnpa, tvb, offset, tmpl, ENC_NA); offset += tmpl; len -= ( tmpl + 1 ); tmpl = (int) tvb_get_guint8(tvb, offset); if ( 0 == tmpl ) { network_tree = proto_tree_add_subtree( tree, tvb, offset, 1, ett_esis_network, NULL, "### No Network Entity Title Section ###" ); offset++; len--; } else { network_tree = proto_tree_add_subtree( tree, tvb, offset, 1, ett_esis_network, NULL, "### Network Entity Title Section ###" ); proto_tree_add_uint_format_value(network_tree, hf_esis_netl, tvb, offset++, 1, tmpl, "%2u Octets", tmpl ); proto_tree_add_string( network_tree, hf_esis_net, tvb, offset, tmpl, print_nsap_net( tvb, offset, tmpl ) ); offset += tmpl; len -= ( tmpl + 1 ); } dissect_osi_options( len, tvb, offset, network_tree, pinfo ); }
static void esis_dissect_ish_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo) { int offset = 0; int netl = 0; proto_tree* network_tree; offset += ESIS_HDR_FIXED_LENGTH; netl = (int) tvb_get_guint8(tvb, offset); network_tree = proto_tree_add_subtree( tree, tvb, offset, netl + 1, ett_esis_network, NULL, "### Network Entity Title Section ###"); proto_tree_add_uint_format_value(network_tree, hf_esis_netl, tvb, offset++, 1, netl, "%2u Octets", netl); proto_tree_add_string(network_tree, hf_esis_net, tvb, offset, netl, print_nsap_net( tvb, offset, netl ) ); offset += netl; len -= ( netl + 1 ); dissect_osi_options( len, tvb, offset, network_tree, pinfo ); }
static void esis_dissect_ish_pdu( guint8 len, tvbuff_t *tvb, proto_tree *tree) { int offset = 0; int netl = 0; if (tree) { offset += ESIS_HDR_FIXED_LENGTH; netl = (int) tvb_get_guint8(tvb, offset); proto_tree_add_text( tree, tvb, offset, netl + 1, "### Network Entity Title Section ###"); proto_tree_add_text( tree, tvb, offset++, 1, "NETL: %2u Octets", netl); proto_tree_add_text( tree, tvb, offset, netl, " NET: %s", print_nsap_net( tvb_get_ptr(tvb, offset, netl), netl ) ); offset += netl; len -= ( netl + 1 ); dissect_osi_options( len, tvb, offset, tree ); } }
static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *clnp_tree; proto_item *ti, *ti_len = NULL, *ti_pdu_len = NULL, *ti_tot_len = NULL; 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 total_length; 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_head *fd_head; tvbuff_t *next_tvb; gboolean update_col_info = TRUE; gboolean save_fragmented; heur_dtbl_entry_t *hdtbl_entry; 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"); 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); 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); ti_len = proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1, cnf_hdr_len); if (cnf_hdr_len < FIXED_PART_LEN) { /* Header length is less than the length of the fixed part of the header. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < minimum length %u", FIXED_PART_LEN); return; } 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); 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_item(type_tree, hf_clnp_cnf_segmentation, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_more_segments, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_report_error, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_type, tvb, P_CLNP_TYPE, 1, ENC_NA); /* 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); ti_pdu_len = proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2, segment_length); if (segment_length < cnf_hdr_len) { /* Segment length is less than the header length. */ expert_add_info_format(pinfo, ti_pdu_len, &ei_clnp_length, "PDU length < header length %u", cnf_hdr_len); return; } cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM); cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum); switch (cksum_status) { default: /* * No checksum present, or not enough of the header present to * checksum it. */ proto_tree_add_uint(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum); break; case CKSUM_OK: /* * Checksum is correct. */ proto_tree_add_uint_format_value(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "0x%04x (correct)", cnf_cksum); break; case CKSUM_NOT_OK: /* * Checksum is not correct. */ proto_tree_add_uint_format_value(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "0x%04x (incorrect)", cnf_cksum); break; } opt_len = cnf_hdr_len; opt_len -= FIXED_PART_LEN; /* Fixed part of Header */ /* address part */ offset = P_CLNP_ADDRESS_PART; if (opt_len < 1) { /* Header length is less than the minimum value in CLNP, including the destination address length. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1); return; } dst_len = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1, dst_len); } offset += 1; opt_len -= 1; if (opt_len < dst_len) { /* Header length is less than the minimum value, including the destination address length and the destination address. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len); return; } dst_addr = tvb_get_ptr(tvb, offset, dst_len); nsel = tvb_get_guint8(tvb, offset + dst_len - 1); SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr); SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr); proto_tree_add_bytes_format_value(clnp_tree, hf_clnp_dest, tvb, offset, dst_len, dst_addr, "%s", print_nsap_net(dst_addr, dst_len)); offset += dst_len; opt_len -= dst_len; if (opt_len < 1) { /* Header length is less than the minimum value, including the destination address length, the destination address, and the source address length. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1); return; } src_len = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb, offset, 1, src_len); } offset += 1; opt_len -= 1; if (opt_len < src_len) { /* Header length is less than the minimum value, including the destination address length, the destination address, the source address length, and the source address. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1 + src_len); return; } src_addr = tvb_get_ptr(tvb, offset, src_len); SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr); SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr); proto_tree_add_bytes_format_value(clnp_tree, hf_clnp_src, tvb, offset, src_len, src_addr, "%s", print_nsap_net(src_addr, src_len)); offset += src_len; opt_len -= src_len; /* Segmentation Part */ if (cnf_type & CNF_SEG_OK) { if (opt_len < SEGMENTATION_PART_LEN) { /* Header length is less than the minimum value, including the destination address length, the destination address, the source address length, the source address, and the segmentation part. */ expert_add_info_format(pinfo, ti_len, &ei_clnp_length, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1 + SEGMENTATION_PART_LEN); return; } du_id = tvb_get_ntohs(tvb, offset); proto_tree_add_text(clnp_tree, tvb, offset, 2, "Data unit identifier: %06u", du_id); segment_offset = tvb_get_ntohs(tvb, offset + 2); proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2, "Segment offset : %6u", segment_offset); total_length = tvb_get_ntohs(tvb, offset + 4); ti_tot_len = proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2, "Total length : %6u", total_length); if (total_length < segment_length) { /* Reassembled length is less than the length of this segment. */ expert_add_info_format(pinfo, ti_tot_len, &ei_clnp_length, "Total length < segment length %u", segment_length); return; } offset += SEGMENTATION_PART_LEN; opt_len -= SEGMENTATION_PART_LEN; } dissect_osi_options(opt_len, tvb, offset, clnp_tree); offset += opt_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(&clnp_reassembly_table, tvb, offset, pinfo, du_id, NULL, 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. Set its length to the segment length, and flag it as a fragment, so going past the end reports FragmentBoundsError, i.e. "there's data missing because this isn't reassembled", not ReportedBoundsError, i.e. "the dissector ran past the end of the packet, so the packet must not have been constructed properly". */ next_tvb = tvb_new_subset_length(tvb, offset, segment_length - cnf_hdr_len); tvb_set_fragment(next_tvb); /* * 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==NSEL_NET && tvb_get_guint8(next_tvb, 0)==NLPID_ISO10747_IDRP) { if(call_dissector(idrp_handle, next_tvb, pinfo, tree) != 0) { pinfo->fragmented = save_fragmented; return; } } 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, &hdtbl_entry, NULL)) { 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 */
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 */