2 * Routines for Subnetwork Dependent Convergence Protocol (SNDCP) dissection
3 * Copyright 2000, Christian Falckenberg <christian.falckenberg@nortelnetworks.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
31 #include <epan/reassemble.h>
33 /* Bitmasks for the bits in the address field
40 /* Initialize the protocol and registered fields
42 static int proto_sndcp
= -1;
43 static int hf_sndcp_x
= -1;
44 static int hf_sndcp_f
= -1;
45 static int hf_sndcp_t
= -1;
46 static int hf_sndcp_m
= -1;
47 static int hf_sndcp_nsapi
= -1;
48 static int hf_sndcp_nsapib
= -1;
49 static int hf_sndcp_dcomp
= -1;
50 static int hf_sndcp_pcomp
= -1;
51 static int hf_sndcp_segment
= -1;
52 static int hf_sndcp_npdu1
= -1;
53 static int hf_sndcp_npdu2
= -1;
55 /* These fields are used when reassembling N-PDU fragments
57 static int hf_npdu_fragments
= -1;
58 static int hf_npdu_fragment
= -1;
59 static int hf_npdu_fragment_overlap
= -1;
60 static int hf_npdu_fragment_overlap_conflict
= -1;
61 static int hf_npdu_fragment_multiple_tails
= -1;
62 static int hf_npdu_fragment_too_long_fragment
= -1;
63 static int hf_npdu_fragment_error
= -1;
64 static int hf_npdu_fragment_count
= -1;
65 static int hf_npdu_reassembled_in
= -1;
66 static int hf_npdu_reassembled_length
= -1;
68 /* Initialize the subtree pointers
70 static gint ett_sndcp
= -1;
71 static gint ett_sndcp_address_field
= -1;
72 static gint ett_sndcp_compression_field
= -1;
73 static gint ett_sndcp_npdu_field
= -1;
74 static gint ett_npdu_fragment
= -1;
75 static gint ett_npdu_fragments
= -1;
77 /* Structure needed for the fragmentation routines in reassemble.c
79 static const fragment_items npdu_frag_items
= {
84 &hf_npdu_fragment_overlap
,
85 &hf_npdu_fragment_overlap_conflict
,
86 &hf_npdu_fragment_multiple_tails
,
87 &hf_npdu_fragment_too_long_fragment
,
88 &hf_npdu_fragment_error
,
89 &hf_npdu_fragment_count
,
90 &hf_npdu_reassembled_in
,
91 &hf_npdu_reassembled_length
,
92 /* Reassembled data field */
97 /* dissectors for the data portion of this protocol
99 static dissector_handle_t data_handle
;
100 static dissector_handle_t ip_handle
;
102 /* reassembly of N-PDU
104 static reassembly_table npdu_reassembly_table
;
107 sndcp_defragment_init(void)
109 reassembly_table_init(&npdu_reassembly_table
, &addresses_reassembly_table_functions
);
114 static const value_string nsapi_t
[] = {
115 { 0, "Escape mechanism for future extensions"},
116 { 1, "Point-to-Multipoint (PTM-M) Information" },
117 { 2, "Reserved for future use" },
118 { 3, "Reserved for future use" },
119 { 4, "Reserved for future use" },
120 { 5, "Dynamically allocated"},
121 { 6, "Dynamically allocated"},
122 { 7, "Dynamically allocated"},
123 { 8, "Dynamically allocated"},
124 { 9, "Dynamically allocated"},
125 { 10, "Dynamically allocated"},
126 { 11, "Dynamically allocated"},
127 { 12, "Dynamically allocated"},
128 { 13, "Dynamically allocated"},
129 { 14, "Dynamically allocated"},
130 { 15, "Dynamically allocated"},
134 static const value_string nsapi_abrv
[] = {
154 static const value_string compression_vals
[] = {
155 { 0, "No compression"},
156 { 1, "Pointer to selected protocol/data compression mechanism" },
157 { 2, "Pointer to selected protocol/data compression mechanism" },
158 { 3, "Pointer to selected protocol/data compression mechanism" },
159 { 4, "Pointer to selected protocol/data compression mechanism" },
160 { 5, "Pointer to selected protocol/data compression mechanism" },
161 { 6, "Pointer to selected protocol/data compression mechanism" },
162 { 7, "Pointer to selected protocol/data compression mechanism" },
163 { 8, "Pointer to selected protocol/data compression mechanism" },
164 { 9, "Pointer to selected protocol/data compression mechanism" },
165 { 10, "Pointer to selected protocol/data compression mechanism" },
166 { 11, "Pointer to selected protocol/data compression mechanism" },
167 { 12, "Pointer to selected protocol/data compression mechanism" },
168 { 13, "Pointer to selected protocol/data compression mechanism" },
169 { 14, "Pointer to selected protocol/data compression mechanism" },
170 { 15, "Pointer to selected protocol/data compression mechanism" },
174 static const true_false_string x_bit
= {
176 "Set to 0 by transmitting SNDCP entity (ignored by receiver)"
178 static const true_false_string f_bit
= {
179 "This SN-PDU is the first segment of an N-PDU",
180 "This SN-PDU is not the first segment of an N-PDU"
182 static const true_false_string t_bit
= {
186 static const true_false_string m_bit
= {
187 "Not the last segment of N-PDU, more segments to follow",
188 "Last segment of N-PDU"
191 /* Code to actually dissect the packets
194 dissect_sndcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
196 guint8 addr_field
, comp_field
, npdu_field1
, nsapi
, dcomp
=0, pcomp
=0;
197 guint16 offset
=0, npdu
=0, segment
=0, npdu_field2
;
198 tvbuff_t
*next_tvb
, *npdu_tvb
;
200 gboolean first
, more_frags
, unack
;
202 /* Set up structures needed to add the protocol subtree and manage it
204 proto_item
*ti
, *address_field_item
, *compression_field_item
, *npdu_field_item
;
205 proto_tree
*sndcp_tree
= NULL
, *address_field_tree
, *compression_field_tree
, *npdu_field_tree
;
207 /* Make entries in Protocol column and clear Info column on summary display
209 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "SNDCP");
210 col_clear(pinfo
->cinfo
, COL_INFO
);
212 /* create display subtree for the protocol
215 ti
= proto_tree_add_item(tree
, proto_sndcp
, tvb
, 0, -1, ENC_NA
);
216 sndcp_tree
= proto_item_add_subtree(ti
, ett_sndcp
);
219 /* get address field from next byte
221 addr_field
= tvb_get_guint8(tvb
,offset
);
222 nsapi
= addr_field
& 0xF;
223 first
= addr_field
& MASK_F
;
224 more_frags
= addr_field
& MASK_M
;
225 unack
= addr_field
& MASK_T
;
227 /* add subtree for the address field
230 address_field_item
= proto_tree_add_uint_format(sndcp_tree
,hf_sndcp_nsapi
,
231 tvb
, offset
,1, nsapi
,
232 "Address field NSAPI: %d", nsapi
);
233 address_field_tree
= proto_item_add_subtree(address_field_item
, ett_sndcp_address_field
);
234 proto_tree_add_boolean(address_field_tree
, hf_sndcp_x
, tvb
,offset
,1, addr_field
);
235 proto_tree_add_boolean(address_field_tree
, hf_sndcp_f
, tvb
,offset
,1, addr_field
);
236 proto_tree_add_boolean(address_field_tree
, hf_sndcp_t
, tvb
,offset
,1, addr_field
);
237 proto_tree_add_boolean(address_field_tree
, hf_sndcp_m
, tvb
,offset
,1, addr_field
);
238 proto_tree_add_uint(address_field_tree
, hf_sndcp_nsapib
, tvb
, offset
, 1, addr_field
);
242 /* get compression pointers from next byte if this is the first segment
245 comp_field
= tvb_get_guint8(tvb
,offset
);
246 dcomp
= comp_field
& 0xF0;
247 pcomp
= comp_field
& 0x0F;
249 /* add subtree for the compression field
254 compression_field_item
= proto_tree_add_text(sndcp_tree
, tvb
, offset
,1, "No compression");
257 compression_field_item
= proto_tree_add_text(sndcp_tree
, tvb
, offset
,1, "Data compression");
262 compression_field_item
= proto_tree_add_text(sndcp_tree
, tvb
, offset
,1, "Protocol compression");
265 compression_field_item
= proto_tree_add_text(sndcp_tree
, tvb
, offset
,1, "Data and Protocol compression");
268 compression_field_tree
= proto_item_add_subtree(compression_field_item
, ett_sndcp_compression_field
);
269 proto_tree_add_uint(compression_field_tree
, hf_sndcp_dcomp
, tvb
, offset
, 1, comp_field
);
270 proto_tree_add_uint(compression_field_tree
, hf_sndcp_pcomp
, tvb
, offset
, 1, comp_field
);
274 /* get N-PDU number from next byte for acknowledged mode (only for first segment)
277 npdu
= npdu_field1
= tvb_get_guint8(tvb
,offset
);
278 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "SN-DATA N-PDU %d", npdu_field1
);
280 npdu_field_item
= proto_tree_add_text(sndcp_tree
, tvb
, offset
,1, "Acknowledged mode, N-PDU %d", npdu_field1
);
281 npdu_field_tree
= proto_item_add_subtree(npdu_field_item
, ett_sndcp_npdu_field
);
282 proto_tree_add_uint(npdu_field_tree
, hf_sndcp_npdu1
, tvb
, offset
, 1, npdu_field1
);
288 /* get segment and N-PDU number from next two bytes for unacknowledged mode
291 npdu_field2
= tvb_get_ntohs(tvb
, offset
);
292 segment
= (npdu_field2
& 0xF000) >> 12;
293 npdu
= (npdu_field2
& 0x0FFF);
294 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "SN-UNITDATA N-PDU %d (segment %d)", npdu
, segment
);
296 npdu_field_item
= proto_tree_add_text(sndcp_tree
, tvb
, offset
,2, "Unacknowledged mode, N-PDU %d (segment %d)", npdu
, segment
);
297 npdu_field_tree
= proto_item_add_subtree(npdu_field_item
, ett_sndcp_npdu_field
);
298 proto_tree_add_uint(npdu_field_tree
, hf_sndcp_segment
, tvb
, offset
, 2, npdu_field2
);
299 proto_tree_add_uint(npdu_field_tree
, hf_sndcp_npdu2
, tvb
, offset
, 2, npdu_field2
);
304 /* handle N-PDU data, reassemble if necessary
306 if (first
&& !more_frags
) {
307 next_tvb
= tvb_new_subset_remaining (tvb
, offset
);
309 if (!dcomp
&& !pcomp
) {
310 call_dissector(ip_handle
, next_tvb
, pinfo
, tree
);
313 call_dissector(data_handle
, next_tvb
, pinfo
, tree
);
317 /* Try reassembling fragments
319 fragment_head
*fd_npdu
= NULL
;
320 guint32 reassembled_in
= 0;
321 gboolean save_fragmented
= pinfo
->fragmented
;
323 len
= tvb_length_remaining(tvb
, offset
);
328 pinfo
->fragmented
= TRUE
;
331 fd_npdu
= fragment_add_seq_check(&npdu_reassembly_table
, tvb
, offset
,
332 pinfo
, npdu
, NULL
, segment
, len
, more_frags
);
334 fd_npdu
= fragment_add(&npdu_reassembly_table
, tvb
, offset
, pinfo
, npdu
, NULL
,
335 offset
, len
, more_frags
);
337 npdu_tvb
= process_reassembled_data(tvb
, offset
, pinfo
,
338 "Reassembled N-PDU", fd_npdu
, &npdu_frag_items
,
343 reassembled_in
= fd_npdu
->reassembled_in
;
344 if (pinfo
->fd
->num
== reassembled_in
) {
345 /* Reassembled in this very packet:
346 * We can safely hand the tvb to the IP dissector
348 call_dissector(ip_handle
, npdu_tvb
, pinfo
, tree
);
351 /* Not reassembled in this packet
353 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
354 " (N-PDU payload reassembled in packet %u)",
355 fd_npdu
->reassembled_in
);
357 proto_tree_add_text(sndcp_tree
, tvb
, offset
, -1, "Payload");
361 /* Not reassembled yet, or not reassembled at all
364 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (Unreassembled fragment %u)", segment
);
366 col_append_str(pinfo
->cinfo
, COL_INFO
, " (Unreassembled fragment)");
369 proto_tree_add_text(sndcp_tree
, tvb
, offset
, -1, "Payload");
372 /* Now reset fragmentation information in pinfo
374 pinfo
->fragmented
= save_fragmented
;
379 /* Register the protocol with Wireshark
380 this format is required because a script is used to build the C function
381 that calls all the protocol registration.
385 proto_register_sndcp(void)
387 /* Setup list of header fields
389 static hf_register_info hf
[] = {
393 FT_UINT8
, BASE_DEC
, VALS(nsapi_abrv
), 0x0,
394 "Network Layer Service Access Point Identifier", HFILL
400 FT_BOOLEAN
,8, TFS(&x_bit
), MASK_X
,
401 "Spare bit (should be 0)", HFILL
405 { "First segment indicator bit",
407 FT_BOOLEAN
,8, TFS(&f_bit
), MASK_F
,
414 FT_BOOLEAN
,8, TFS(&t_bit
), MASK_T
,
421 FT_BOOLEAN
,8, TFS(&m_bit
), MASK_M
,
428 FT_UINT8
, BASE_DEC
, VALS(compression_vals
), 0xF0,
429 "Data compression coding", HFILL
435 FT_UINT8
, BASE_DEC
, VALS(compression_vals
), 0x0F,
436 "Protocol compression coding", HFILL
442 FT_UINT8
, BASE_DEC
, VALS(nsapi_t
), 0xf,
443 "Network Layer Service Access Point Identifier",HFILL
449 FT_UINT16
, BASE_DEC
, NULL
, 0xF000,
450 "Segment number", HFILL
456 FT_UINT8
, BASE_DEC
, NULL
, 0,
463 FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF,
470 { &hf_npdu_fragment_overlap
,
471 { "Fragment overlap",
472 "npdu.fragment.overlap",
473 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
474 "Fragment overlaps with other fragments", HFILL
477 { &hf_npdu_fragment_overlap_conflict
,
478 { "Conflicting data in fragment overlap",
479 "npdu.fragment.overlap.conflict",
480 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
481 "Overlapping fragments contained conflicting data", HFILL
484 { &hf_npdu_fragment_multiple_tails
,
485 { "Multiple tail fragments found",
486 "npdu.fragment.multipletails",
487 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
488 "Several tails were found when defragmenting the packet", HFILL
491 { &hf_npdu_fragment_too_long_fragment
,
492 { "Fragment too long",
493 "npdu.fragment.toolongfragment",
494 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
495 "Fragment contained data past end of packet", HFILL
498 { &hf_npdu_fragment_error
,
499 { "Defragmentation error",
500 "npdu.fragment.error",
501 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
502 "Defragmentation error due to illegal fragments", HFILL
505 { &hf_npdu_fragment_count
,
507 "npdu.fragment.count",
508 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
512 { &hf_npdu_reassembled_in
,
514 "npdu.reassembled.in",
515 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
516 "N-PDU fragments are reassembled in the given packet", HFILL
519 { &hf_npdu_reassembled_length
,
520 { "Reassembled N-PDU length",
521 "npdu.reassembled.length",
522 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
523 "The total length of the reassembled payload", HFILL
529 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
533 { &hf_npdu_fragments
,
536 FT_NONE
, BASE_NONE
, NULL
, 0x0,
542 /* Setup protocol subtree array */
543 static gint
*ett
[] = {
545 &ett_sndcp_address_field
,
546 &ett_sndcp_compression_field
,
547 &ett_sndcp_npdu_field
,
552 /* Register the protocol name and description */
553 proto_sndcp
= proto_register_protocol("Subnetwork Dependent Convergence Protocol",
556 /* Required function calls to register the header fields and subtrees used */
557 proto_register_field_array(proto_sndcp
, hf
, array_length(hf
));
558 proto_register_subtree_array(ett
, array_length(ett
));
559 register_dissector("sndcp", dissect_sndcp
, proto_sndcp
);
560 register_init_routine(sndcp_defragment_init
);
563 /* If this dissector uses sub-dissector registration add a registration routine.
564 This format is required because a script is used to find these routines and
565 create the code that calls these routines.
568 proto_reg_handoff_sndcp(void)
570 dissector_handle_t sndcp_handle
;
572 sndcp_handle
= find_dissector("sndcp");
574 /* Register SNDCP dissector with LLC layer for SAPI 3,5,9 and 11
576 dissector_add_uint("llcgprs.sapi", 3, sndcp_handle
);
577 dissector_add_uint("llcgprs.sapi", 5, sndcp_handle
);
578 dissector_add_uint("llcgprs.sapi", 9, sndcp_handle
);
579 dissector_add_uint("llcgprs.sapi", 11, sndcp_handle
);
581 /* Find IP and data handle for upper layer dissectors
583 ip_handle
= find_dissector("ip");
584 data_handle
= find_dissector("data");