2 * Routines for Subnetwork Dependent Convergence Protocol (SNDCP) dissection
3 * Copyright 2000, Christian Falckenberg <christian.falckenberg@nortelnetworks.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include <epan/reassemble.h>
17 #include <wsutil/array.h>
19 /* Bitmasks for the bits in the address field
26 void proto_register_sndcp(void);
27 void proto_reg_handoff_sndcp(void);
29 /* Initialize the protocol and registered fields
31 static int proto_sndcp
;
32 static int hf_sndcp_x
;
33 static int hf_sndcp_f
;
34 static int hf_sndcp_t
;
35 static int hf_sndcp_m
;
36 static int hf_sndcp_nsapi
;
37 static int hf_sndcp_nsapib
;
38 static int hf_sndcp_dcomp
;
39 static int hf_sndcp_pcomp
;
40 static int hf_sndcp_segment
;
41 static int hf_sndcp_npdu1
;
42 static int hf_sndcp_npdu2
;
43 static int hf_sndcp_payload
;
45 /* These fields are used when reassembling N-PDU fragments
47 static int hf_npdu_fragments
;
48 static int hf_npdu_fragment
;
49 static int hf_npdu_fragment_overlap
;
50 static int hf_npdu_fragment_overlap_conflict
;
51 static int hf_npdu_fragment_multiple_tails
;
52 static int hf_npdu_fragment_too_long_fragment
;
53 static int hf_npdu_fragment_error
;
54 static int hf_npdu_fragment_count
;
55 static int hf_npdu_reassembled_in
;
56 static int hf_npdu_reassembled_length
;
58 /* Initialize the subtree pointers
61 static int ett_sndcp_address_field
;
62 static int ett_sndcp_compression_field
;
63 static int ett_sndcp_npdu_field
;
64 static int ett_npdu_fragment
;
65 static int ett_npdu_fragments
;
67 /* Structure needed for the fragmentation routines in reassemble.c
69 static const fragment_items npdu_frag_items
= {
74 &hf_npdu_fragment_overlap
,
75 &hf_npdu_fragment_overlap_conflict
,
76 &hf_npdu_fragment_multiple_tails
,
77 &hf_npdu_fragment_too_long_fragment
,
78 &hf_npdu_fragment_error
,
79 &hf_npdu_fragment_count
,
80 &hf_npdu_reassembled_in
,
81 &hf_npdu_reassembled_length
,
82 /* Reassembled data field */
87 /* dissectors for the data portion of this protocol
89 static dissector_handle_t ip_handle
;
90 static dissector_handle_t sndcp_handle
;
93 /* reassembly of N-PDU
95 static reassembly_table npdu_reassembly_table
;
99 static const value_string nsapi_t
[] = {
100 { 0, "Escape mechanism for future extensions"},
101 { 1, "Point-to-Multipoint (PTM-M) Information" },
102 { 2, "Reserved for future use" },
103 { 3, "Reserved for future use" },
104 { 4, "Reserved for future use" },
105 { 5, "Dynamically allocated"},
106 { 6, "Dynamically allocated"},
107 { 7, "Dynamically allocated"},
108 { 8, "Dynamically allocated"},
109 { 9, "Dynamically allocated"},
110 { 10, "Dynamically allocated"},
111 { 11, "Dynamically allocated"},
112 { 12, "Dynamically allocated"},
113 { 13, "Dynamically allocated"},
114 { 14, "Dynamically allocated"},
115 { 15, "Dynamically allocated"},
119 static const value_string nsapi_abrv
[] = {
139 static const value_string compression_vals
[] = {
140 { 0, "No compression"},
141 { 1, "Pointer to selected protocol/data compression mechanism" },
142 { 2, "Pointer to selected protocol/data compression mechanism" },
143 { 3, "Pointer to selected protocol/data compression mechanism" },
144 { 4, "Pointer to selected protocol/data compression mechanism" },
145 { 5, "Pointer to selected protocol/data compression mechanism" },
146 { 6, "Pointer to selected protocol/data compression mechanism" },
147 { 7, "Pointer to selected protocol/data compression mechanism" },
148 { 8, "Pointer to selected protocol/data compression mechanism" },
149 { 9, "Pointer to selected protocol/data compression mechanism" },
150 { 10, "Pointer to selected protocol/data compression mechanism" },
151 { 11, "Pointer to selected protocol/data compression mechanism" },
152 { 12, "Pointer to selected protocol/data compression mechanism" },
153 { 13, "Pointer to selected protocol/data compression mechanism" },
154 { 14, "Pointer to selected protocol/data compression mechanism" },
155 { 15, "Pointer to selected protocol/data compression mechanism" },
159 static const true_false_string x_bit
= {
161 "Set to 0 by transmitting SNDCP entity (ignored by receiver)"
163 static const true_false_string f_bit
= {
164 "This SN-PDU is the first segment of an N-PDU",
165 "This SN-PDU is not the first segment of an N-PDU"
167 static const true_false_string t_bit
= {
171 static const true_false_string m_bit
= {
172 "Not the last segment of N-PDU, more segments to follow",
173 "Last segment of N-PDU"
176 /* Code to actually dissect the packets
179 dissect_sndcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
181 uint8_t addr_field
, comp_field
, npdu_field1
, dcomp
=0, pcomp
=0;
182 uint16_t offset
=0, npdu
=0, segment
=0, npdu_field2
;
183 tvbuff_t
*next_tvb
, *npdu_tvb
;
185 bool first
, more_frags
, unack
;
186 static int * const addr_fields
[] = {
195 /* Set up structures needed to add the protocol subtree and manage it
198 proto_tree
*sndcp_tree
, *compression_field_tree
, *npdu_field_tree
;
200 /* Make entries in Protocol column and clear Info column on summary display
202 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "SNDCP");
203 col_clear(pinfo
->cinfo
, COL_INFO
);
205 /* create display subtree for the protocol
207 ti
= proto_tree_add_item(tree
, proto_sndcp
, tvb
, 0, -1, ENC_NA
);
208 sndcp_tree
= proto_item_add_subtree(ti
, ett_sndcp
);
210 /* get address field from next byte
212 addr_field
= tvb_get_uint8(tvb
,offset
);
213 first
= addr_field
& MASK_F
;
214 more_frags
= addr_field
& MASK_M
;
215 unack
= addr_field
& MASK_T
;
217 /* add subtree for the address field
219 proto_tree_add_bitmask_with_flags(sndcp_tree
, tvb
, offset
, hf_sndcp_nsapi
,
220 ett_sndcp_address_field
, addr_fields
, ENC_NA
, BMT_NO_APPEND
);
223 /* get compression pointers from next byte if this is the first segment
226 comp_field
= tvb_get_uint8(tvb
,offset
);
227 dcomp
= comp_field
& 0xF0;
228 pcomp
= comp_field
& 0x0F;
230 /* add subtree for the compression field
235 compression_field_tree
= proto_tree_add_subtree(sndcp_tree
, tvb
, offset
, 1, ett_sndcp_compression_field
, NULL
, "No compression");
238 compression_field_tree
= proto_tree_add_subtree(sndcp_tree
, tvb
, offset
, 1, ett_sndcp_compression_field
, NULL
, "Data compression");
243 compression_field_tree
= proto_tree_add_subtree(sndcp_tree
, tvb
, offset
, 1, ett_sndcp_compression_field
, NULL
, "Protocol compression");
246 compression_field_tree
= proto_tree_add_subtree(sndcp_tree
, tvb
, offset
, 1, ett_sndcp_compression_field
, NULL
, "Data and Protocol compression");
249 proto_tree_add_uint(compression_field_tree
, hf_sndcp_dcomp
, tvb
, offset
, 1, comp_field
);
250 proto_tree_add_uint(compression_field_tree
, hf_sndcp_pcomp
, tvb
, offset
, 1, comp_field
);
254 /* get N-PDU number from next byte for acknowledged mode (only for first segment)
257 npdu
= npdu_field1
= tvb_get_uint8(tvb
,offset
);
258 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "SN-DATA N-PDU %d", npdu_field1
);
260 npdu_field_tree
= proto_tree_add_subtree_format(sndcp_tree
, tvb
, offset
, 1, ett_sndcp_npdu_field
, NULL
, "Acknowledged mode, N-PDU %d", npdu_field1
);
261 proto_tree_add_uint(npdu_field_tree
, hf_sndcp_npdu1
, tvb
, offset
, 1, npdu_field1
);
267 /* get segment and N-PDU number from next two bytes for unacknowledged mode
270 npdu_field2
= tvb_get_ntohs(tvb
, offset
);
271 segment
= (npdu_field2
& 0xF000) >> 12;
272 npdu
= (npdu_field2
& 0x0FFF);
273 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "SN-UNITDATA N-PDU %d (segment %d)", npdu
, segment
);
275 npdu_field_tree
= proto_tree_add_subtree_format(sndcp_tree
, tvb
, offset
, 2, ett_sndcp_npdu_field
, NULL
,
276 "Unacknowledged mode, N-PDU %d (segment %d)", npdu
, segment
);
277 proto_tree_add_uint(npdu_field_tree
, hf_sndcp_segment
, tvb
, offset
, 2, npdu_field2
);
278 proto_tree_add_uint(npdu_field_tree
, hf_sndcp_npdu2
, tvb
, offset
, 2, npdu_field2
);
283 /* handle N-PDU data, reassemble if necessary
285 if (first
&& !more_frags
) {
286 next_tvb
= tvb_new_subset_remaining (tvb
, offset
);
288 if (!dcomp
&& !pcomp
) {
289 call_dissector(ip_handle
, next_tvb
, pinfo
, tree
);
292 call_data_dissector(next_tvb
, pinfo
, tree
);
296 /* Try reassembling fragments
298 fragment_head
*fd_npdu
= NULL
;
299 uint32_t reassembled_in
= 0;
300 bool save_fragmented
= pinfo
->fragmented
;
302 len
= tvb_captured_length_remaining(tvb
, offset
);
307 pinfo
->fragmented
= true;
310 fd_npdu
= fragment_add_seq_check(&npdu_reassembly_table
, tvb
, offset
,
311 pinfo
, npdu
, NULL
, segment
, len
, more_frags
);
313 fd_npdu
= fragment_add(&npdu_reassembly_table
, tvb
, offset
, pinfo
, npdu
, NULL
,
314 offset
, len
, more_frags
);
316 npdu_tvb
= process_reassembled_data(tvb
, offset
, pinfo
,
317 "Reassembled N-PDU", fd_npdu
, &npdu_frag_items
,
322 reassembled_in
= fd_npdu
->reassembled_in
;
323 if (pinfo
->num
== reassembled_in
) {
324 /* Reassembled in this very packet:
325 * We can safely hand the tvb to the IP dissector
327 call_dissector(ip_handle
, npdu_tvb
, pinfo
, tree
);
330 /* Not reassembled in this packet
332 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
333 " (N-PDU payload reassembled in packet %u)",
334 fd_npdu
->reassembled_in
);
335 proto_tree_add_item(sndcp_tree
, hf_sndcp_payload
, tvb
, offset
, -1, ENC_NA
);
338 /* Not reassembled yet, or not reassembled at all
341 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (Unreassembled fragment %u)", segment
);
343 col_append_str(pinfo
->cinfo
, COL_INFO
, " (Unreassembled fragment)");
345 proto_tree_add_item(sndcp_tree
, hf_sndcp_payload
, tvb
, offset
, -1, ENC_NA
);
347 /* Now reset fragmentation information in pinfo
349 pinfo
->fragmented
= save_fragmented
;
351 return tvb_captured_length(tvb
);
355 /* Register the protocol with Wireshark
356 this format is required because a script is used to build the C function
357 that calls all the protocol registration.
361 proto_register_sndcp(void)
363 /* Setup list of header fields
365 static hf_register_info hf
[] = {
367 { "Address field NSAPI",
369 FT_UINT8
, BASE_DEC
, VALS(nsapi_abrv
), 0x0,
370 "Network Layer Service Access Point Identifier", HFILL
376 FT_BOOLEAN
,8, TFS(&x_bit
), MASK_X
,
377 "Spare bit (should be 0)", HFILL
381 { "First segment indicator bit",
383 FT_BOOLEAN
,8, TFS(&f_bit
), MASK_F
,
390 FT_BOOLEAN
,8, TFS(&t_bit
), MASK_T
,
397 FT_BOOLEAN
,8, TFS(&m_bit
), MASK_M
,
404 FT_UINT8
, BASE_DEC
, VALS(compression_vals
), 0xF0,
405 "Data compression coding", HFILL
411 FT_UINT8
, BASE_DEC
, VALS(compression_vals
), 0x0F,
412 "Protocol compression coding", HFILL
418 FT_UINT8
, BASE_DEC
, VALS(nsapi_t
), 0xf,
419 "Network Layer Service Access Point Identifier",HFILL
425 FT_UINT16
, BASE_DEC
, NULL
, 0xF000,
426 "Segment number", HFILL
432 FT_UINT8
, BASE_DEC
, NULL
, 0,
439 FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF,
446 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
453 { &hf_npdu_fragment_overlap
,
454 { "Fragment overlap",
455 "sndcp.npdu.fragment.overlap",
456 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
457 "Fragment overlaps with other fragments", HFILL
460 { &hf_npdu_fragment_overlap_conflict
,
461 { "Conflicting data in fragment overlap",
462 "sndcp.npdu.fragment.overlap.conflict",
463 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
464 "Overlapping fragments contained conflicting data", HFILL
467 { &hf_npdu_fragment_multiple_tails
,
468 { "Multiple tail fragments found",
469 "sndcp.npdu.fragment.multipletails",
470 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
471 "Several tails were found when defragmenting the packet", HFILL
474 { &hf_npdu_fragment_too_long_fragment
,
475 { "Fragment too long",
476 "sndcp.npdu.fragment.toolongfragment",
477 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
478 "Fragment contained data past end of packet", HFILL
481 { &hf_npdu_fragment_error
,
482 { "Defragmentation error",
483 "sndcp.npdu.fragment.error",
484 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
485 "Defragmentation error due to illegal fragments", HFILL
488 { &hf_npdu_fragment_count
,
490 "sndcp.npdu.fragment.count",
491 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
495 { &hf_npdu_reassembled_in
,
497 "sndcp.npdu.reassembled.in",
498 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
499 "N-PDU fragments are reassembled in the given packet", HFILL
502 { &hf_npdu_reassembled_length
,
503 { "Reassembled N-PDU length",
504 "sndcp.npdu.reassembled.length",
505 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
506 "The total length of the reassembled payload", HFILL
511 "sndcp.npdu.fragment",
512 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
516 { &hf_npdu_fragments
,
518 "sndcp.npdu.fragments",
519 FT_NONE
, BASE_NONE
, NULL
, 0x0,
525 /* Setup protocol subtree array */
526 static int *ett
[] = {
528 &ett_sndcp_address_field
,
529 &ett_sndcp_compression_field
,
530 &ett_sndcp_npdu_field
,
535 /* Register the protocol name and description */
536 proto_sndcp
= proto_register_protocol("Subnetwork Dependent Convergence Protocol",
539 /* Required function calls to register the header fields and subtrees used */
540 proto_register_field_array(proto_sndcp
, hf
, array_length(hf
));
541 proto_register_subtree_array(ett
, array_length(ett
));
542 sndcp_handle
= register_dissector("sndcp", dissect_sndcp
, proto_sndcp
);
543 reassembly_table_register(&npdu_reassembly_table
, &addresses_reassembly_table_functions
);
546 /* If this dissector uses sub-dissector registration add a registration routine.
547 This format is required because a script is used to find these routines and
548 create the code that calls these routines.
551 proto_reg_handoff_sndcp(void)
553 /* Register SNDCP dissector with LLC layer for SAPI 3,5,9 and 11
555 dissector_add_uint("llcgprs.sapi", 3, sndcp_handle
);
556 dissector_add_uint("llcgprs.sapi", 5, sndcp_handle
);
557 dissector_add_uint("llcgprs.sapi", 9, sndcp_handle
);
558 dissector_add_uint("llcgprs.sapi", 11, sndcp_handle
);
560 /* Find IP and data handle for upper layer dissectors
562 ip_handle
= find_dissector_add_dependency("ip", proto_sndcp
);
566 * Editor modelines - https://www.wireshark.org/tools/modelines.html
571 * indent-tabs-mode: nil
574 * ex: set shiftwidth=2 tabstop=8 expandtab:
575 * :indentSize=2:tabSize=8:noTabs=true: