2 * Routines for Subnetwork Dependent Convergence Protocol (SNDCP) dissection
3 * Copyright 2000, Christian Falckenberg <christian.falckenberg@nortelnetworks.com>
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 #ifdef NEED_SNPRINTF_H
37 # include "snprintf.h"
40 #include <epan/packet.h>
41 #include "reassemble.h"
43 /* Bitmasks for the bits in the address field
50 /* Initialize the protocol and registered fields
52 static int proto_sndcp = -1;
53 static int hf_sndcp_x = -1;
54 static int hf_sndcp_f = -1;
55 static int hf_sndcp_t = -1;
56 static int hf_sndcp_m = -1;
57 static int hf_sndcp_nsapi = -1;
58 static int hf_sndcp_nsapib = -1;
59 static int hf_sndcp_dcomp = -1;
60 static int hf_sndcp_pcomp = -1;
61 static int hf_sndcp_segment = -1;
62 static int hf_sndcp_npdu1 = -1;
63 static int hf_sndcp_npdu2 = -1;
65 /* These fields are used when reassembling N-PDU fragments
67 static int hf_npdu_fragments = -1;
68 static int hf_npdu_fragment = -1;
69 static int hf_npdu_fragment_overlap = -1;
70 static int hf_npdu_fragment_overlap_conflict = -1;
71 static int hf_npdu_fragment_multiple_tails = -1;
72 static int hf_npdu_fragment_too_long_fragment = -1;
73 static int hf_npdu_fragment_error = -1;
74 static int hf_npdu_reassembled_in = -1;
76 /* Initialize the subtree pointers
78 static gint ett_sndcp = -1;
79 static gint ett_sndcp_address_field = -1;
80 static gint ett_sndcp_compression_field = -1;
81 static gint ett_sndcp_npdu_field = -1;
82 static gint ett_npdu_fragment = -1;
83 static gint ett_npdu_fragments = -1;
85 /* Structure needed for the fragmentation routines in reassemble.c
87 static const fragment_items npdu_frag_items = {
92 &hf_npdu_fragment_overlap,
93 &hf_npdu_fragment_overlap_conflict,
94 &hf_npdu_fragment_multiple_tails,
95 &hf_npdu_fragment_too_long_fragment,
96 &hf_npdu_fragment_error,
97 &hf_npdu_reassembled_in,
101 /* dissectors for the data portion of this protocol
103 static dissector_handle_t data_handle;
104 static dissector_handle_t ip_handle;
106 /* reassembly of N-PDU
108 static GHashTable *npdu_fragment_table = NULL;
110 sndcp_defragment_init(void)
112 fragment_table_init(&npdu_fragment_table);
117 static const value_string nsapi_t[] = {
118 { 0, "Escape mechanism for future extensions"},
119 { 1, "Point-to-Multipoint (PTM-M) Information" },
120 { 2, "Reserved for future use" },
121 { 3, "Reserved for future use" },
122 { 4, "Reserved for future use" },
123 { 5, "Dynamically allocated"},
124 { 6, "Dynamically allocated"},
125 { 7, "Dynamically allocated"},
126 { 8, "Dynamically allocated"},
127 { 9, "Dynamically allocated"},
128 { 10, "Dynamically allocated"},
129 { 11, "Dynamically allocated"},
130 { 12, "Dynamically allocated"},
131 { 13, "Dynamically allocated"},
132 { 14, "Dynamically allocated"},
133 { 15, "Dynamically allocated"},
137 static const value_string nsapi_abrv[] = {
157 static const value_string compression_vals[] = {
158 { 0, "No compression"},
159 { 1, "Pointer to selected protocol/data compression mechanism" },
160 { 2, "Pointer to selected protocol/data compression mechanism" },
161 { 3, "Pointer to selected protocol/data compression mechanism" },
162 { 4, "Pointer to selected protocol/data compression mechanism" },
163 { 5, "Pointer to selected protocol/data compression mechanism" },
164 { 6, "Pointer to selected protocol/data compression mechanism" },
165 { 7, "Pointer to selected protocol/data compression mechanism" },
166 { 8, "Pointer to selected protocol/data compression mechanism" },
167 { 9, "Pointer to selected protocol/data compression mechanism" },
168 { 10, "Pointer to selected protocol/data compression mechanism" },
169 { 11, "Pointer to selected protocol/data compression mechanism" },
170 { 12, "Pointer to selected protocol/data compression mechanism" },
171 { 13, "Pointer to selected protocol/data compression mechanism" },
172 { 14, "Pointer to selected protocol/data compression mechanism" },
173 { 15, "Pointer to selected protocol/data compression mechanism" },
177 static const true_false_string x_bit = {
179 "Set to 0 by transmitting SNDCP entity (ignored by receiver)"
181 static const true_false_string f_bit = {
182 "This SN-PDU is the first segment of an N-PDU",
183 "This SN-PDU is not the first segment of an N-PDU"
185 static const true_false_string t_bit = {
189 static const true_false_string m_bit = {
190 "Not the last segment of N-PDU, more segments to follow",
191 "Last segment of N-PDU"
194 /* Code to actually dissect the packets
197 dissect_sndcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
199 guint8 addr_field, comp_field, npdu_field1, nsapi, dcomp=0, pcomp=0;
200 guint16 offset=0, npdu=0, segment=0, npdu_field2;
201 tvbuff_t *next_tvb, *npdu_tvb;
203 gboolean first, more_frags, unack;
205 /* Set up structures needed to add the protocol subtree and manage it
207 proto_item *ti, *address_field_item, *compression_field_item, *npdu_field_item;
208 proto_tree *sndcp_tree = NULL, *address_field_tree, *compression_field_tree, *npdu_field_tree;
210 /* Make entries in Protocol column and clear Info column on summary display
212 if (check_col(pinfo->cinfo, COL_PROTOCOL))
213 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SNDCP");
214 if (check_col(pinfo->cinfo, COL_INFO))
215 col_clear(pinfo->cinfo, COL_INFO);
217 /* create display subtree for the protocol
220 ti = proto_tree_add_item(tree, proto_sndcp, tvb, 0, -1, FALSE);
221 sndcp_tree = proto_item_add_subtree(ti, ett_sndcp);
224 /* get address field from next byte
226 addr_field = tvb_get_guint8(tvb,offset);
227 nsapi = addr_field & 0xF;
228 first = addr_field & MASK_F;
229 more_frags = addr_field & MASK_M;
230 unack = addr_field & MASK_T;
232 /* add subtree for the address field
235 address_field_item = proto_tree_add_uint_format(sndcp_tree,hf_sndcp_nsapi,
236 tvb, offset,1, nsapi,
237 "Address field NSAPI: %d", nsapi );
238 address_field_tree = proto_item_add_subtree(address_field_item, ett_sndcp_address_field);
239 proto_tree_add_boolean(address_field_tree, hf_sndcp_x, tvb,offset,1, addr_field );
240 proto_tree_add_boolean(address_field_tree, hf_sndcp_f, tvb,offset,1, addr_field );
241 proto_tree_add_boolean(address_field_tree, hf_sndcp_t, tvb,offset,1, addr_field );
242 proto_tree_add_boolean(address_field_tree, hf_sndcp_m, tvb,offset,1, addr_field );
243 proto_tree_add_uint(address_field_tree, hf_sndcp_nsapib, tvb, offset, 1, addr_field );
247 /* get compression pointers from next byte if this is the first segment
250 comp_field = tvb_get_guint8(tvb,offset);
251 dcomp = comp_field & 0xF0;
252 pcomp = comp_field & 0x0F;
254 /* add subtree for the compression field
259 compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "No compression");
262 compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Data compression");
267 compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Protocol compression");
270 compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Data and Protocol compression");
273 compression_field_tree = proto_item_add_subtree(compression_field_item, ett_sndcp_compression_field);
274 proto_tree_add_uint(compression_field_tree, hf_sndcp_dcomp, tvb, offset, 1, comp_field );
275 proto_tree_add_uint(compression_field_tree, hf_sndcp_pcomp, tvb, offset, 1, comp_field );
279 /* get N-PDU number from next byte for acknowledged mode (only for first segment)
282 npdu = npdu_field1 = tvb_get_guint8(tvb,offset);
283 if (check_col(pinfo->cinfo, COL_INFO))
284 col_add_fstr(pinfo->cinfo, COL_INFO, "SN-DATA N-PDU %d", npdu_field1);
286 npdu_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Acknowledged mode, N-PDU %d", npdu_field1 );
287 npdu_field_tree = proto_item_add_subtree(npdu_field_item, ett_sndcp_npdu_field);
288 proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu1, tvb, offset, 1, npdu_field1 );
294 /* get segment and N-PDU number from next two bytes for unacknowledged mode
297 npdu_field2 = tvb_get_ntohs(tvb, offset);
298 segment = (npdu_field2 & 0xF000) >> 12;
299 npdu = (npdu_field2 & 0x0FFF);
300 if (check_col(pinfo->cinfo, COL_INFO))
301 col_add_fstr(pinfo->cinfo, COL_INFO, "SN-UNITDATA N-PDU %d (segment %d)", npdu, segment);
303 npdu_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,2, "Unacknowledged mode, N-PDU %d (segment %d)", npdu, segment );
304 npdu_field_tree = proto_item_add_subtree(npdu_field_item, ett_sndcp_npdu_field);
305 proto_tree_add_uint(npdu_field_tree, hf_sndcp_segment, tvb, offset, 2, npdu_field2 );
306 proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu2, tvb, offset, 2, npdu_field2 );
311 /* handle N-PDU data, reassemble if necessary
313 if (first && !more_frags) {
314 next_tvb = tvb_new_subset (tvb, offset, -1, -1);
316 if (!dcomp && !pcomp) {
317 call_dissector(ip_handle, next_tvb, pinfo, tree);
320 call_dissector(data_handle, next_tvb, pinfo, tree);
324 /* Try reassembling fragments
326 fragment_data *fd_npdu = NULL;
327 guint32 reassembled_in = 0;
328 gboolean save_fragmented = pinfo->fragmented;
330 len = tvb_length_remaining(tvb, offset);
331 pinfo->fragmented = TRUE;
334 fd_npdu = fragment_add_seq(tvb, offset, pinfo, npdu,
335 npdu_fragment_table, segment, len, more_frags);
337 fd_npdu = fragment_add(tvb, offset, pinfo, npdu,
338 npdu_fragment_table, offset, len, more_frags);
340 npdu_tvb = process_reassembled_data(tvb, offset, pinfo,
341 "Reassembled N-PDU", fd_npdu, &npdu_frag_items,
346 reassembled_in = fd_npdu->reassembled_in;
347 if (pinfo->fd->num == reassembled_in) {
348 /* Reassembled in this very packet:
349 * We can safely hand the tvb to the IP dissector
351 call_dissector(ip_handle, npdu_tvb, pinfo, tree);
354 /* Not reassembled in this packet
356 if (check_col(pinfo->cinfo, COL_INFO)) {
357 col_append_fstr(pinfo->cinfo, COL_INFO,
358 " (N-PDU payload reassembled in packet %u)",
359 fd_npdu->reassembled_in);
362 proto_tree_add_text(sndcp_tree, tvb, offset, -1, "Payload");
366 /* Not reassembled yet, or not reassembled at all
368 if (check_col(pinfo->cinfo, COL_INFO)) {
370 col_append_fstr(pinfo->cinfo, COL_INFO, " (Unreassembled fragment %u)", segment);
372 col_append_str(pinfo->cinfo, COL_INFO, " (Unreassembled fragment)");
375 proto_tree_add_text(sndcp_tree, tvb, offset, -1, "Payload");
378 /* Now reset fragmentation information in pinfo
380 pinfo->fragmented = save_fragmented;
385 /* Register the protocol with Ethereal
386 this format is required because a script is used to build the C function
387 that calls all the protocol registration.
391 proto_register_sndcp(void)
393 /* Setup list of header fields
395 static hf_register_info hf[] = {
399 FT_UINT8, BASE_DEC, VALS(nsapi_abrv), 0x0,
400 "Network Layer Service Access Point Identifier", HFILL
406 FT_BOOLEAN,8, TFS(&x_bit), MASK_X,
407 "Spare bit (should be 0)", HFILL
411 { "First segment indicator bit",
413 FT_BOOLEAN,8, TFS(&f_bit), MASK_F,
414 "First segment indicator bit", HFILL
420 FT_BOOLEAN,8, TFS(&t_bit), MASK_T,
427 FT_BOOLEAN,8, TFS(&m_bit), MASK_M,
434 FT_UINT8, BASE_DEC, VALS(compression_vals), 0xF0,
435 "Data compression coding", HFILL
441 FT_UINT8, BASE_DEC, VALS(compression_vals), 0x0F,
442 "Protocol compression coding", HFILL
448 FT_UINT8, BASE_DEC , VALS(nsapi_t), 0xf,
449 "Network Layer Service Access Point Identifier ",HFILL
455 FT_UINT16, BASE_DEC, NULL, 0xF000,
456 "Segment number", HFILL
462 FT_UINT8, BASE_DEC, NULL, 0,
469 FT_UINT16, BASE_DEC, NULL, 0x0FFF,
476 { &hf_npdu_fragment_overlap,
477 { "Fragment overlap",
478 "npdu.fragment.overlap",
479 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
480 "Fragment overlaps with other fragments", HFILL
483 { &hf_npdu_fragment_overlap_conflict,
484 { "Conflicting data in fragment overlap",
485 "npdu.fragment.overlap.conflict",
486 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
487 "Overlapping fragments contained conflicting data", HFILL
490 { &hf_npdu_fragment_multiple_tails,
491 { "Multiple tail fragments found",
492 "npdu.fragment.multipletails",
493 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
494 "Several tails were found when defragmenting the packet", HFILL
497 { &hf_npdu_fragment_too_long_fragment,
498 { "Fragment too long",
499 "npdu.fragment.toolongfragment",
500 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
501 "Fragment contained data past end of packet", HFILL
504 { &hf_npdu_fragment_error,
505 { "Defragmentation error",
506 "npdu.fragment.error",
507 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
508 "Defragmentation error due to illegal fragments", HFILL
511 { &hf_npdu_reassembled_in,
513 "npdu.reassembled.in",
514 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
515 "N-PDU fragments are reassembled in the given packet", HFILL
521 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
522 "N-PDU Fragment", HFILL
525 { &hf_npdu_fragments,
528 FT_NONE, BASE_NONE, NULL, 0x0,
529 "N-PDU Fragments", HFILL
534 /* Setup protocol subtree array */
535 static gint *ett[] = {
537 &ett_sndcp_address_field,
538 &ett_sndcp_compression_field,
539 &ett_sndcp_npdu_field,
544 /* Register the protocol name and description */
545 proto_sndcp = proto_register_protocol("Subnetwork Dependent Convergence Protocol",
548 /* Required function calls to register the header fields and subtrees used */
549 proto_register_field_array(proto_sndcp, hf, array_length(hf));
550 proto_register_subtree_array(ett, array_length(ett));
551 register_dissector("sndcp", dissect_sndcp, proto_sndcp);
552 register_init_routine(sndcp_defragment_init);
555 /* If this dissector uses sub-dissector registration add a registration routine.
556 This format is required because a script is used to find these routines and
557 create the code that calls these routines.
560 proto_reg_handoff_sndcp(void)
562 dissector_handle_t sndcp_handle;
564 sndcp_handle = create_dissector_handle(dissect_sndcp, proto_sndcp);
566 /* Register SNDCP dissector with LLC layer for SAPI 3,5,9 and 11
568 dissector_add("llcgprs.sapi", 3, sndcp_handle);
569 dissector_add("llcgprs.sapi", 5, sndcp_handle);
570 dissector_add("llcgprs.sapi", 9, sndcp_handle);
571 dissector_add("llcgprs.sapi", 11, sndcp_handle);
573 /* Find IP and data handle for upper layer dissectors
575 ip_handle = find_dissector("ip");
576 data_handle = find_dissector("data");