Esempio n. 1
0
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 */
Esempio n. 2
0
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 */
Esempio n. 3
0
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 );
  }
}
Esempio n. 4
0
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 );
}
Esempio n. 5
0
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 );
}
Esempio n. 6
0
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 */
Esempio n. 8
0
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 */