Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-clnp.c
Line
Count
Source
1
/* packet-clnp.c
2
 * Routines for ISO/OSI network protocol packet disassembly
3
 *
4
 * Laurent Deniel <laurent.deniel@free.fr>
5
 * Ralf Schneider <Ralf.Schneider@t-online.de>
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
#include "config.h"
15
16
#include <epan/packet.h>
17
#include <epan/prefs.h>
18
#include <epan/reassemble.h>
19
#include <epan/expert.h>
20
#include <epan/tfs.h>
21
22
#include "packet-osi.h"
23
#include "packet-osi-options.h"
24
25
void proto_register_clnp(void);
26
void proto_reg_handoff_clnp(void);
27
28
/* protocols and fields */
29
30
static int  proto_clnp;
31
static int ett_clnp;
32
static int ett_clnp_type;
33
static int ett_clnp_segments;
34
static int ett_clnp_segment;
35
static int ett_clnp_disc_pdu;
36
37
static int hf_clnp_id;
38
static int hf_clnp_length;
39
static int hf_clnp_version;
40
static int hf_clnp_ttl;
41
static int hf_clnp_type;
42
static int hf_clnp_cnf_segmentation;
43
static int hf_clnp_cnf_more_segments;
44
static int hf_clnp_cnf_report_error;
45
static int hf_clnp_cnf_type;
46
static int hf_clnp_pdu_length;
47
static int hf_clnp_data_unit_identifier;
48
static int hf_clnp_segment_offset;
49
static int hf_clnp_total_length;
50
static int hf_clnp_checksum;
51
static int hf_clnp_checksum_status;
52
static int hf_clnp_dest_length;
53
static int hf_clnp_dest;
54
static int hf_clnp_src_length;
55
static int hf_clnp_src;
56
static int hf_clnp_segments;
57
static int hf_clnp_segment;
58
static int hf_clnp_segment_overlap;
59
static int hf_clnp_segment_overlap_conflict;
60
static int hf_clnp_segment_multiple_tails;
61
static int hf_clnp_segment_too_long_segment;
62
static int hf_clnp_segment_error;
63
static int hf_clnp_segment_count;
64
static int hf_clnp_reassembled_in;
65
static int hf_clnp_reassembled_length;
66
67
static const fragment_items clnp_frag_items = {
68
    &ett_clnp_segment,
69
    &ett_clnp_segments,
70
    &hf_clnp_segments,
71
    &hf_clnp_segment,
72
    &hf_clnp_segment_overlap,
73
    &hf_clnp_segment_overlap_conflict,
74
    &hf_clnp_segment_multiple_tails,
75
    &hf_clnp_segment_too_long_segment,
76
    &hf_clnp_segment_error,
77
    &hf_clnp_segment_count,
78
    &hf_clnp_reassembled_in,
79
    &hf_clnp_reassembled_length,
80
    /* Reassembled data field */
81
    NULL,
82
    "segments"
83
};
84
85
static expert_field ei_clnp_length;
86
static expert_field ei_clnp_checksum;
87
88
static dissector_handle_t clnp_handle;
89
static dissector_handle_t ositp_handle;
90
static dissector_handle_t ositp_inactive_handle;
91
static dissector_handle_t idrp_handle;
92
93
/*
94
 * ISO 8473 OSI CLNP definition (see RFC994)
95
 *
96
 *            _________________________________
97
 *           |           Fixed Part            |
98
 *           |_________________________________|
99
 *           |          Address Part           |
100
 *           |_________________________________|
101
 *           |   Segmentation Part (optional)  |
102
 *           |_________________________________|
103
 *           |     Options Part (optional)     |
104
 *           |_________________________________|
105
 *           |         Data (optional)         |
106
 *           |_________________________________|
107
 */
108
109
211
#define ISO8473_V1  0x01    /* CLNP version 1 */
110
111
/* Fixed part */
112
113
/* Length of fixed part */
114
390
#define FIXED_PART_LEN          9
115
116
363
#define CNF_TYPE                0x1f
117
210
#define CNF_ERR_OK              0x20
118
707
#define CNF_MORE_SEGS           0x40
119
1.05k
#define CNF_SEG_OK              0x80
120
121
144
#define DT_NPDU                 0x1C
122
150
#define MD_NPDU                 0x1D
123
1
#define ER_NPDU                 0x01
124
0
#define ERQ_NPDU                0x1E
125
0
#define ERP_NPDU                0x1F
126
127
static const value_string npdu_type_abbrev_vals[] = {
128
    { DT_NPDU,    "DT" },
129
    { MD_NPDU,    "MD" },
130
    { ER_NPDU,    "ER" },
131
    { ERQ_NPDU,   "ERQ" },
132
    { ERP_NPDU,   "ERP" },
133
    { 0,          NULL }
134
};
135
136
static const value_string npdu_type_vals[] = {
137
    { DT_NPDU,    "Data" },
138
    { MD_NPDU,    "Multicast Data" },
139
    { ER_NPDU,    "Error Report" },
140
    { ERQ_NPDU,   "Echo Request" },
141
    { ERP_NPDU,   "Echo Response" },
142
    { 0,          NULL }
143
};
144
145
/* field position */
146
147
21.9k
#define P_CLNP_PROTO_ID         0
148
392
#define P_CLNP_HDR_LEN          1
149
407
#define P_CLNP_VERS             2
150
392
#define P_CLNP_TTL              3
151
1.17k
#define P_CLNP_TYPE             4
152
392
#define P_CLNP_SEGLEN           5
153
370
#define P_CLNP_CKSUM            7
154
185
#define P_CLNP_ADDRESS_PART     9
155
156
/* Segmentation part */
157
158
487
#define SEGMENTATION_PART_LEN   6
159
160
struct clnp_segment {
161
    uint16_t      cng_id;         /* data unit identifier */
162
    uint16_t      cng_off;        /* segment offset */
163
    uint16_t      cng_tot_len;    /* total length */
164
};
165
166
/* NSAP selector */
167
168
300
#define NSEL_NET                0x00
169
#define NSEL_NP                 0x20
170
#define NSEL_TP                 0x21
171
172
/* global variables */
173
174
/* List of dissectors to call for CLNP packets */
175
static heur_dissector_list_t clnp_heur_subdissector_list;
176
177
/*
178
 * Reassembly of CLNP.
179
 */
180
static reassembly_table clnp_reassembly_table;
181
182
/* options */
183
static unsigned tp_nsap_selector = NSEL_TP;
184
static bool always_decode_transport;
185
static bool clnp_reassemble = true;
186
187
/* function definitions */
188
189
/*
190
 *  CLNP part / main entry point
191
*/
192
193
static int
194
dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
195
7.38k
{
196
7.38k
    proto_tree     *clnp_tree;
197
7.38k
    proto_item     *ti, *ti_len = NULL, *ti_pdu_len = NULL, *ti_tot_len = NULL;
198
7.38k
    uint8_t         cnf_proto_id;
199
7.38k
    uint8_t         cnf_hdr_len;
200
7.38k
    uint8_t         cnf_vers;
201
7.38k
    uint8_t         cnf_ttl;
202
7.38k
    uint8_t         cnf_type;
203
7.38k
    char            flag_string[6+1];
204
7.38k
    const char     *pdu_type_string;
205
7.38k
    proto_tree     *type_tree;
206
7.38k
    uint16_t        segment_length;
207
7.38k
    uint16_t        du_id = 0;
208
7.38k
    uint16_t        segment_offset = 0;
209
7.38k
    uint16_t        total_length;
210
7.38k
    uint16_t        cnf_cksum;
211
7.38k
    bool            cksum_valid = true;
212
7.38k
    int             offset;
213
7.38k
    unsigned char   src_len, dst_len, nsel, opt_len = 0;
214
7.38k
    unsigned        next_length;
215
7.38k
    proto_tree     *discpdu_tree;
216
7.38k
    bool            save_in_error_pkt;
217
7.38k
    fragment_head  *fd_head;
218
7.38k
    tvbuff_t       *next_tvb;
219
7.38k
    bool            update_col_info = true;
220
7.38k
    bool            save_fragmented;
221
7.38k
    heur_dtbl_entry_t *hdtbl_entry;
222
223
7.38k
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
224
7.38k
    col_clear(pinfo->cinfo, COL_INFO);
225
226
7.38k
    cnf_proto_id = tvb_get_uint8(tvb, P_CLNP_PROTO_ID);
227
7.38k
    if (cnf_proto_id == NLPID_NULL) {
228
7.17k
        col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
229
7.17k
        ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, ENC_NA);
230
7.17k
        clnp_tree = proto_item_add_subtree(ti, ett_clnp);
231
7.17k
        proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
232
7.17k
                cnf_proto_id, "Inactive subset");
233
7.17k
        next_tvb = tvb_new_subset_remaining(tvb, 1);
234
7.17k
        call_dissector(ositp_inactive_handle, next_tvb, pinfo, tree);
235
7.17k
        return tvb_captured_length(tvb);
236
7.17k
    }
237
238
    /* return if version not known */
239
211
    cnf_vers = tvb_get_uint8(tvb, P_CLNP_VERS);
240
211
    if (cnf_vers != ISO8473_V1) {
241
15
        call_data_dissector(tvb, pinfo, tree);
242
15
        return tvb_captured_length(tvb);
243
15
    }
244
245
    /* fixed part decoding */
246
196
    cnf_hdr_len = tvb_get_uint8(tvb, P_CLNP_HDR_LEN);
247
248
196
    ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, ENC_NA);
249
196
    clnp_tree = proto_item_add_subtree(ti, ett_clnp);
250
196
    proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1,
251
196
            cnf_proto_id);
252
196
    ti_len = proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1,
253
196
            cnf_hdr_len);
254
196
    if (cnf_hdr_len < FIXED_PART_LEN) {
255
        /* Header length is less than the length of the fixed part of
256
           the header. */
257
0
        expert_add_info_format(pinfo, ti_len, &ei_clnp_length,
258
0
                "Header length value < minimum length %u",
259
0
                FIXED_PART_LEN);
260
0
        return 2;
261
0
    }
262
196
    proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1,
263
196
                cnf_vers);
264
196
    cnf_ttl = tvb_get_uint8(tvb, P_CLNP_TTL);
265
196
    proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1,
266
196
            cnf_ttl,
267
196
            "Holding Time : %u (%u.%u secs)",
268
196
            cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5);
269
196
    cnf_type = tvb_get_uint8(tvb, P_CLNP_TYPE);
270
196
    pdu_type_string = val_to_str(pinfo->pool, cnf_type & CNF_TYPE, npdu_type_abbrev_vals,
271
196
            "Unknown (0x%02x)");
272
196
    flag_string[0] = '\0';
273
196
    if (cnf_type & CNF_SEG_OK)
274
169
        (void) g_strlcat(flag_string, "S ", 7);
275
196
    if (cnf_type & CNF_MORE_SEGS)
276
11
        (void) g_strlcat(flag_string, "M ", 7);
277
196
    if (cnf_type & CNF_ERR_OK)
278
171
        (void) g_strlcat(flag_string, "E ", 7);
279
196
    ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1,
280
196
            cnf_type,
281
196
            "PDU Type     : 0x%02x (%s%s)",
282
196
            cnf_type,
283
196
            flag_string,
284
196
            pdu_type_string);
285
196
    type_tree = proto_item_add_subtree(ti, ett_clnp_type);
286
196
    proto_tree_add_item(type_tree, hf_clnp_cnf_segmentation, tvb, P_CLNP_TYPE, 1, ENC_NA);
287
196
    proto_tree_add_item(type_tree, hf_clnp_cnf_more_segments, tvb, P_CLNP_TYPE, 1, ENC_NA);
288
196
    proto_tree_add_item(type_tree, hf_clnp_cnf_report_error, tvb, P_CLNP_TYPE, 1, ENC_NA);
289
196
    proto_tree_add_item(type_tree, hf_clnp_cnf_type, tvb, P_CLNP_TYPE, 1, ENC_BIG_ENDIAN);
290
291
    /* If we don't have the full header - i.e., not enough to see the
292
       segmentation part and determine whether this datagram is segmented
293
       or not - set the Info column now; we'll get an exception before
294
       we set it otherwise. */
295
296
196
    if (tvb_reported_length(tvb) < cnf_hdr_len) {
297
20
        col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
298
20
    }
299
300
196
    segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
301
196
    ti_pdu_len = proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2,
302
196
            segment_length);
303
196
    if (segment_length < cnf_hdr_len) {
304
        /* Segment length is less than the header length. */
305
11
        expert_add_info_format(pinfo, ti_pdu_len, &ei_clnp_length,
306
11
                "PDU length < header length %u", cnf_hdr_len);
307
11
        return 7;
308
11
    }
309
185
    cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM);
310
185
    if (cnf_cksum == 0) {
311
        /* No checksum present */
312
8
        proto_tree_add_checksum(clnp_tree, tvb, P_CLNP_CKSUM, hf_clnp_checksum, hf_clnp_checksum_status, &ei_clnp_checksum, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NOT_PRESENT);
313
177
    } else {
314
177
        uint32_t c0 = 0, c1 = 0;
315
316
177
        if (osi_calc_checksum(tvb, 0, cnf_hdr_len, &c0, &c1)) {
317
            /* Successfully processed checksum, verify it */
318
167
            proto_tree_add_checksum(clnp_tree, tvb, P_CLNP_CKSUM, hf_clnp_checksum, hf_clnp_checksum_status, &ei_clnp_checksum, pinfo, c0 | c1, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_ZERO);
319
167
            cksum_valid = (c0 | c1) ? false : true;
320
167
        } else {
321
10
            proto_tree_add_checksum(clnp_tree, tvb, P_CLNP_CKSUM, hf_clnp_checksum, hf_clnp_checksum_status, &ei_clnp_checksum, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
322
10
        }
323
177
    }
324
325
185
    opt_len = cnf_hdr_len;
326
185
    opt_len -= FIXED_PART_LEN; /* Fixed part of Header */
327
328
    /* address part */
329
330
185
    offset = P_CLNP_ADDRESS_PART;
331
185
    if (opt_len < 1) {
332
        /* Header length is less than the minimum value in CLNP,
333
           including the destination address length. */
334
0
        expert_add_info_format(pinfo, ti_len, &ei_clnp_length,
335
0
                "Header length value < %u",
336
0
                FIXED_PART_LEN + 1);
337
0
        return offset;
338
0
    }
339
185
    dst_len  = tvb_get_uint8(tvb, offset);
340
185
    if (tree) {
341
183
        proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1,
342
183
                dst_len);
343
183
    }
344
185
    offset += 1;
345
185
    opt_len -= 1;
346
347
185
    if (opt_len < dst_len) {
348
        /* Header length is less than the minimum value,
349
           including the destination address length and the
350
           destination address. */
351
4
        expert_add_info_format(pinfo, ti_len, &ei_clnp_length,
352
4
                "Header length value < %u",
353
4
                FIXED_PART_LEN + 1 + dst_len);
354
4
        return offset;
355
4
    }
356
181
    nsel     = tvb_get_uint8(tvb, offset + dst_len - 1);
357
181
    set_address_tvb(&pinfo->net_dst, get_osi_address_type(), dst_len, tvb, offset);
358
181
    copy_address_shallow(&pinfo->dst, &pinfo->net_dst);
359
181
    proto_tree_add_bytes_format_value(clnp_tree, hf_clnp_dest, tvb, offset, dst_len,
360
181
            NULL,
361
181
            "%s",
362
181
            print_nsap_net(pinfo->pool, tvb, offset, dst_len));
363
181
    offset += dst_len;
364
181
    opt_len -= dst_len;
365
366
181
    if (opt_len < 1) {
367
        /* Header length is less than the minimum value,
368
           including the destination address length, the
369
           destination address, and the source address length. */
370
1
        expert_add_info_format(pinfo, ti_len, &ei_clnp_length,
371
1
                "Header length value < %u",
372
1
                FIXED_PART_LEN + 1 + dst_len + 1);
373
1
        return offset;
374
1
    }
375
180
    src_len  = tvb_get_uint8(tvb, offset);
376
180
    if (tree) {
377
178
        proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb,
378
178
                offset, 1, src_len);
379
178
    }
380
180
    offset += 1;
381
180
    opt_len -= 1;
382
383
180
    if (opt_len < src_len) {
384
        /* Header length is less than the minimum value,
385
           including the destination address length, the
386
           destination address, the source address length,
387
           and the source address. */
388
3
        expert_add_info_format(pinfo, ti_len, &ei_clnp_length,
389
3
                "Header length value < %u",
390
3
                FIXED_PART_LEN + 1 + dst_len + 1 + src_len);
391
3
        return offset;
392
3
    }
393
177
    set_address_tvb(&pinfo->net_src, get_osi_address_type(), src_len, tvb, offset);
394
177
    copy_address_shallow(&pinfo->src, &pinfo->net_src);
395
177
    proto_tree_add_bytes_format_value(clnp_tree, hf_clnp_src, tvb, offset, src_len,
396
177
            NULL,
397
177
            "%s",
398
177
            print_nsap_net(pinfo->pool, tvb, offset, src_len));
399
177
    offset += src_len;
400
177
    opt_len -= src_len;
401
402
    /* Segmentation Part */
403
404
177
    if (cnf_type & CNF_SEG_OK) {
405
164
        if (opt_len < SEGMENTATION_PART_LEN) {
406
            /* Header length is less than the minimum value,
407
               including the destination address length, the
408
               destination address, the source address length,
409
               the source address, and the segmentation part. */
410
1
            expert_add_info_format(pinfo, ti_len, &ei_clnp_length,
411
1
                    "Header length value < %u",
412
1
                    FIXED_PART_LEN + 1 + dst_len + 1 + SEGMENTATION_PART_LEN);
413
1
            return offset;
414
1
        }
415
416
163
        du_id = tvb_get_ntohs(tvb, offset);
417
163
        proto_tree_add_item(clnp_tree, hf_clnp_data_unit_identifier, tvb, offset, 2, ENC_BIG_ENDIAN);
418
163
        segment_offset = tvb_get_ntohs(tvb, offset + 2);
419
163
        proto_tree_add_item(clnp_tree, hf_clnp_segment_offset, tvb, offset + 2 , 2, ENC_BIG_ENDIAN);
420
163
        total_length = tvb_get_ntohs(tvb, offset + 4);
421
163
        ti_tot_len = proto_tree_add_item(clnp_tree, hf_clnp_total_length, tvb, offset + 4 , 2, ENC_BIG_ENDIAN);
422
163
        if (total_length < segment_length) {
423
            /* Reassembled length is less than the length of this segment. */
424
2
            expert_add_info_format(pinfo, ti_tot_len, &ei_clnp_length,
425
2
                    "Total length < segment length %u", segment_length);
426
2
            return offset;
427
2
        }
428
161
        offset  += SEGMENTATION_PART_LEN;
429
161
        opt_len -= SEGMENTATION_PART_LEN;
430
161
    }
431
432
174
    dissect_osi_options(opt_len, tvb, offset, clnp_tree, pinfo);
433
434
174
    offset += opt_len;
435
436
    /* If clnp_reassemble is on, this is a segment, we have all the
437
     * data in the segment, and the checksum is valid, then just add the
438
     * segment to the hashtable.
439
     */
440
174
    save_fragmented = pinfo->fragmented;
441
174
    if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
442
155
            ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
443
5
            tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) &&
444
3
            segment_length > cnf_hdr_len &&
445
3
            cksum_valid != false) {
446
2
        fd_head = fragment_add_check(&clnp_reassembly_table,
447
2
                tvb, offset, pinfo, du_id, NULL,
448
2
                segment_offset, segment_length - cnf_hdr_len,
449
2
                cnf_type & CNF_MORE_SEGS);
450
451
2
        next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP",
452
2
                fd_head, &clnp_frag_items, &update_col_info, clnp_tree);
453
172
    } else {
454
        /* If this is the first segment, dissect its contents, otherwise
455
           just show it as a segment.
456
457
           XXX - if we eventually don't save the reassembled contents of all
458
           segmented datagrams, we may want to always reassemble. */
459
172
        if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) {
460
            /* Not the first segment - don't dissect it. */
461
2
            next_tvb = NULL;
462
170
        } else {
463
            /* First segment, or not segmented.  Dissect what we have here. */
464
465
            /* Get a tvbuff for the payload.  Set its length to the segment
466
               length, and flag it as a fragment, so going past the end
467
               reports FragmentBoundsError, i.e. "there's data missing
468
               because this isn't reassembled", not ReportedBoundsError,
469
               i.e. "the dissector ran past the end of the packet, so the
470
               packet must not have been constructed properly". */
471
170
            next_tvb = tvb_new_subset_length(tvb, offset, segment_length - cnf_hdr_len);
472
170
            tvb_set_fragment(next_tvb);
473
474
            /*
475
             * If this is the first segment, but not the only segment,
476
             * tell the next protocol that.
477
             */
478
170
            if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS))
479
1
                pinfo->fragmented = true;
480
169
            else
481
169
                pinfo->fragmented = false;
482
170
        }
483
172
    }
484
485
174
    if (next_tvb == NULL) {
486
        /* Just show this as a segment. */
487
4
        col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
488
4
                pdu_type_string, flag_string, segment_offset);
489
490
        /* As we haven't reassembled anything, we haven't changed "pi", so
491
           we don't have to restore it. */
492
4
        call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
493
4
        pinfo->fragmented = save_fragmented;
494
4
        return tvb_captured_length(tvb);
495
4
    }
496
497
170
    if (tvb_offset_exists(tvb, offset)) {
498
153
        switch (cnf_type & CNF_TYPE) {
499
500
144
            case DT_NPDU:
501
150
            case MD_NPDU:
502
                /* Continue with COTP if any data.
503
                   XXX - if this isn't the first Derived PDU of a segmented Initial
504
                   PDU, skip that? */
505
506
150
                if (nsel==NSEL_NET && tvb_get_uint8(next_tvb, 0)==NLPID_ISO10747_IDRP) {
507
148
                    if(call_dissector(idrp_handle, next_tvb, pinfo, tree) != 0) {
508
9
                        pinfo->fragmented = save_fragmented;
509
9
                        return tvb_captured_length(tvb);
510
9
                    }
511
148
                }
512
141
                if (nsel == (unsigned char)tp_nsap_selector || always_decode_transport) {
513
0
                    if (call_dissector(ositp_handle, next_tvb, pinfo, tree) != 0) {
514
0
                        pinfo->fragmented = save_fragmented;
515
0
                        return tvb_captured_length(tvb);       /* yes, it appears to be COTP or CLTP */
516
0
                    }
517
0
                }
518
141
                if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb,
519
141
                            pinfo, tree, &hdtbl_entry, NULL)) {
520
0
                    pinfo->fragmented = save_fragmented;
521
0
                    return tvb_captured_length(tvb);       /* yes, it appears to be one of the protocols in the heuristic list */
522
0
                }
523
524
141
                break;
525
526
141
            case ER_NPDU:
527
                /* The payload is the header and "none, some, or all of the data
528
                   part of the discarded PDU", i.e. it's like an ICMP error;
529
                   dissect it as a CLNP PDU. */
530
531
1
                col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
532
1
                next_length = tvb_reported_length_remaining(tvb, offset);
533
1
                if (next_length != 0) {
534
                    /* We have payload; dissect it. */
535
1
                    discpdu_tree = proto_tree_add_subtree(clnp_tree, tvb, offset, next_length,
536
1
                            ett_clnp_disc_pdu, NULL, "Discarded PDU");
537
538
                    /* Save the current value of the "we're inside an error packet"
539
                       flag, and set that flag; subdissectors may treat packets
540
                       that are the payload of error packets differently from
541
                       "real" packets. */
542
1
                    save_in_error_pkt = pinfo->flags.in_error_pkt;
543
1
                    pinfo->flags.in_error_pkt = true;
544
545
1
                    call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree);
546
547
                    /* Restore the "we're inside an error packet" flag. */
548
1
                    pinfo->flags.in_error_pkt = save_in_error_pkt;
549
1
                }
550
1
                pinfo->fragmented = save_fragmented;
551
1
                return tvb_captured_length(tvb);   /* we're done with this PDU */
552
553
0
            case ERQ_NPDU:
554
0
            case ERP_NPDU:
555
                /* XXX - dissect this */
556
0
                break;
557
153
        }
558
153
    }
559
21
    col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
560
21
    call_data_dissector(next_tvb, pinfo, tree);
561
21
    pinfo->fragmented = save_fragmented;
562
21
    return tvb_captured_length(tvb);
563
170
} /* dissect_clnp */
564
565
void
566
proto_register_clnp(void)
567
14
{
568
14
    static hf_register_info hf[] = {
569
14
        { &hf_clnp_id,
570
14
            { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
571
14
                VALS(nlpid_vals), 0x0, NULL, HFILL }},
572
573
14
        { &hf_clnp_length,
574
14
            { "HDR Length", "clnp.len",          FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
575
576
14
        { &hf_clnp_version,
577
14
            { "Version", "clnp.version",  FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
578
579
14
        { &hf_clnp_ttl,
580
14
            { "Holding Time", "clnp.ttl",        FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
581
582
14
        { &hf_clnp_type,
583
14
            { "PDU Type", "clnp.type",     FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
584
585
14
        { &hf_clnp_cnf_segmentation,
586
14
            { "Segmentation permitted", "clnp.cnf.segmentation", FT_BOOLEAN, 8, TFS(&tfs_yes_no), CNF_SEG_OK, NULL, HFILL }},
587
588
14
        { &hf_clnp_cnf_more_segments,
589
14
            { "More segments", "clnp.cnf.more_segments", FT_BOOLEAN, 8, TFS(&tfs_yes_no), CNF_MORE_SEGS, NULL, HFILL }},
590
591
14
        { &hf_clnp_cnf_report_error,
592
14
            { "Report error if PDU discarded", "clnp.cnf.report_error", FT_BOOLEAN, 8, TFS(&tfs_yes_no), CNF_ERR_OK, NULL, HFILL }},
593
594
14
        { &hf_clnp_cnf_type,
595
14
            { "Type", "clnp.cnf.type", FT_UINT8, BASE_DEC, VALS(npdu_type_vals), CNF_TYPE, NULL, HFILL }},
596
597
14
        { &hf_clnp_pdu_length,
598
14
            { "PDU length", "clnp.pdu.len",  FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
599
600
14
        { &hf_clnp_data_unit_identifier,
601
14
            { "Data unit identifier", "clnp.data_unit_identifier",  FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
602
603
14
        { &hf_clnp_segment_offset,
604
14
            { "Segment offset", "clnp.segment_offset",  FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
605
606
14
        { &hf_clnp_total_length,
607
14
            { "Total length", "clnp.total_length",  FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
608
609
14
        { &hf_clnp_checksum,
610
14
            { "Checksum", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
611
612
14
        { &hf_clnp_checksum_status,
613
14
            { "Checksum Status", "clnp.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }},
614
615
14
        { &hf_clnp_dest_length,
616
14
            { "DAL", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
617
618
14
        { &hf_clnp_dest,
619
14
            { "DA", "clnp.dsap",     FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
620
621
14
        { &hf_clnp_src_length,
622
14
            { "SAL", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
623
624
14
        { &hf_clnp_src,
625
14
            { "SA", "clnp.ssap",     FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
626
627
14
        { &hf_clnp_segment_overlap,
628
14
            { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
629
14
                "Segment overlaps with other segments", HFILL }},
630
631
14
        { &hf_clnp_segment_overlap_conflict,
632
14
            { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
633
14
                "Overlapping segments contained conflicting data", HFILL }},
634
635
14
        { &hf_clnp_segment_multiple_tails,
636
14
            { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
637
14
                "Several tails were found when reassembling the packet", HFILL }},
638
639
14
        { &hf_clnp_segment_too_long_segment,
640
14
            { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
641
14
                "Segment contained data past end of packet", HFILL }},
642
643
14
        { &hf_clnp_segment_error,
644
14
            { "Reassembly error", "clnp.segment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
645
14
                "Reassembly error due to illegal segments", HFILL }},
646
647
14
        { &hf_clnp_segment_count,
648
14
            { "Segment count", "clnp.segment.count", FT_UINT32, BASE_DEC, NULL, 0x0,
649
14
                NULL, HFILL }},
650
651
14
        { &hf_clnp_segment,
652
14
            { "CLNP Segment", "clnp.segment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
653
14
                NULL, HFILL }},
654
655
14
        { &hf_clnp_segments,
656
14
            { "CLNP Segments", "clnp.segments", FT_NONE, BASE_NONE, NULL, 0x0,
657
14
                NULL, HFILL }},
658
659
14
        { &hf_clnp_reassembled_in,
660
14
            { "Reassembled CLNP in frame", "clnp.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
661
14
                "This CLNP packet is reassembled in this frame", HFILL }},
662
663
14
        { &hf_clnp_reassembled_length,
664
14
            { "Reassembled CLNP length", "clnp.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
665
14
                "The total length of the reassembled payload", HFILL }}
666
14
    };
667
14
    static int *ett[] = {
668
14
        &ett_clnp,
669
14
        &ett_clnp_type,
670
14
        &ett_clnp_segments,
671
14
        &ett_clnp_segment,
672
14
        &ett_clnp_disc_pdu,
673
14
    };
674
675
14
    static ei_register_info ei[] = {
676
14
        { &ei_clnp_length, { "clnp.len.bad", PI_MALFORMED, PI_ERROR, "Header length value bad", EXPFILL }},
677
14
        { &ei_clnp_checksum, { "clnp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
678
14
    };
679
680
14
    module_t *clnp_module;
681
14
    expert_module_t* expert_clnp;
682
683
14
    proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "CLNP", "clnp");
684
14
    proto_register_field_array(proto_clnp, hf, array_length(hf));
685
14
    proto_register_subtree_array(ett, array_length(ett));
686
14
    expert_clnp = expert_register_protocol(proto_clnp);
687
14
    expert_register_field_array(expert_clnp, ei, array_length(ei));
688
14
    clnp_handle = register_dissector("clnp", dissect_clnp, proto_clnp);
689
14
    clnp_heur_subdissector_list = register_heur_dissector_list_with_description("clnp", "CLNP DT/MD payload", proto_clnp);
690
691
14
    reassembly_table_register(&clnp_reassembly_table,
692
14
            &addresses_reassembly_table_functions);
693
694
14
    register_osi_address_type();
695
696
14
    clnp_module = prefs_register_protocol(proto_clnp, NULL);
697
14
    prefs_register_uint_preference(clnp_module, "tp_nsap_selector",
698
14
            "NSAP selector for Transport Protocol (last byte in hex)",
699
14
            "NSAP selector for Transport Protocol (last byte in hex)",
700
14
            16, &tp_nsap_selector);
701
14
    prefs_register_bool_preference(clnp_module, "always_decode_transport",
702
14
            "Always try to decode NSDU as transport PDUs",
703
14
            "Always try to decode NSDU as transport PDUs",
704
14
            &always_decode_transport);
705
14
    prefs_register_bool_preference(clnp_module, "reassemble",
706
14
            "Reassemble segmented CLNP datagrams",
707
14
            "Whether segmented CLNP datagrams should be reassembled",
708
14
            &clnp_reassemble);
709
    /* XXX - catch this and tweak the decode_as settings? */
710
14
    prefs_register_obsolete_preference(clnp_module, "decode_atn_options");
711
14
}
712
713
void
714
proto_reg_handoff_clnp(void)
715
14
{
716
14
    ositp_handle = find_dissector_add_dependency("ositp", proto_clnp);
717
14
    ositp_inactive_handle = find_dissector_add_dependency("ositp_inactive", proto_clnp);
718
14
    idrp_handle = find_dissector_add_dependency("idrp", proto_clnp);
719
720
14
    dissector_add_uint("osinl.incl", NLPID_ISO8473_CLNP, clnp_handle);
721
14
    dissector_add_uint("osinl.incl", NLPID_NULL, clnp_handle); /* Inactive subset */
722
14
    dissector_add_uint("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
723
14
}
724
725
/*
726
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
727
 *
728
 * Local variables:
729
 * c-basic-offset: 4
730
 * tab-width: 8
731
 * indent-tabs-mode: nil
732
 * End:
733
 *
734
 * vi: set shiftwidth=4 tabstop=8 expandtab:
735
 * :indentSize=4:tabSize=8:noTabs=true:
736
 */