Revert "Fixup: tvb_* -> tvb_captured"
[metze/wireshark/wip.git] / epan / dissectors / packet-sndcp.c
1 /* packet-sndcp.c
2  * Routines for Subnetwork Dependent Convergence Protocol (SNDCP) dissection
3  * Copyright 2000, Christian Falckenberg <christian.falckenberg@nortelnetworks.com>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <glib.h>
27
28 #include <epan/packet.h>
29 #include <epan/reassemble.h>
30
31 /* Bitmasks for the bits in the address field
32 */
33 #define MASK_X      0x80
34 #define MASK_F      0x40
35 #define MASK_T      0x20
36 #define MASK_M      0x10
37
38 void proto_register_sndcp(void);
39 void proto_reg_handoff_sndcp(void);
40
41 /* Initialize the protocol and registered fields
42 */
43 static int proto_sndcp       = -1;
44 static int hf_sndcp_x        = -1;
45 static int hf_sndcp_f        = -1;
46 static int hf_sndcp_t        = -1;
47 static int hf_sndcp_m        = -1;
48 static int hf_sndcp_nsapi    = -1;
49 static int hf_sndcp_nsapib   = -1;
50 static int hf_sndcp_dcomp    = -1;
51 static int hf_sndcp_pcomp    = -1;
52 static int hf_sndcp_segment  = -1;
53 static int hf_sndcp_npdu1    = -1;
54 static int hf_sndcp_npdu2    = -1;
55
56 /* These fields are used when reassembling N-PDU fragments
57 */
58 static int hf_npdu_fragments                    = -1;
59 static int hf_npdu_fragment                     = -1;
60 static int hf_npdu_fragment_overlap             = -1;
61 static int hf_npdu_fragment_overlap_conflict    = -1;
62 static int hf_npdu_fragment_multiple_tails      = -1;
63 static int hf_npdu_fragment_too_long_fragment   = -1;
64 static int hf_npdu_fragment_error               = -1;
65 static int hf_npdu_fragment_count               = -1;
66 static int hf_npdu_reassembled_in               = -1;
67 static int hf_npdu_reassembled_length           = -1;
68
69 /* Initialize the subtree pointers
70 */
71 static gint ett_sndcp                   = -1;
72 static gint ett_sndcp_address_field     = -1;
73 static gint ett_sndcp_compression_field = -1;
74 static gint ett_sndcp_npdu_field        = -1;
75 static gint ett_npdu_fragment           = -1;
76 static gint ett_npdu_fragments          = -1;
77
78 /* Structure needed for the fragmentation routines in reassemble.c
79 */
80 static const fragment_items npdu_frag_items = {
81     &ett_npdu_fragment,
82     &ett_npdu_fragments,
83     &hf_npdu_fragments,
84     &hf_npdu_fragment,
85     &hf_npdu_fragment_overlap,
86     &hf_npdu_fragment_overlap_conflict,
87     &hf_npdu_fragment_multiple_tails,
88     &hf_npdu_fragment_too_long_fragment,
89     &hf_npdu_fragment_error,
90     &hf_npdu_fragment_count,
91     &hf_npdu_reassembled_in,
92     &hf_npdu_reassembled_length,
93     /* Reassembled data field */
94     NULL,
95     "fragments"
96 };
97
98 /* dissectors for the data portion of this protocol
99  */
100 static dissector_handle_t data_handle;
101 static dissector_handle_t ip_handle;
102
103 /* reassembly of N-PDU
104  */
105 static reassembly_table npdu_reassembly_table;
106
107 static void
108 sndcp_defragment_init(void)
109 {
110   reassembly_table_init(&npdu_reassembly_table, &addresses_reassembly_table_functions);
111 }
112
113 /* value strings
114  */
115 static const value_string nsapi_t[] = {
116   {  0, "Escape mechanism for future extensions"},
117   {  1, "Point-to-Multipoint (PTM-M) Information" },
118   {  2, "Reserved for future use" },
119   {  3, "Reserved for future use" },
120   {  4, "Reserved for future use" },
121   {  5, "Dynamically allocated"},
122   {  6, "Dynamically allocated"},
123   {  7, "Dynamically allocated"},
124   {  8, "Dynamically allocated"},
125   {  9, "Dynamically allocated"},
126   { 10, "Dynamically allocated"},
127   { 11, "Dynamically allocated"},
128   { 12, "Dynamically allocated"},
129   { 13, "Dynamically allocated"},
130   { 14, "Dynamically allocated"},
131   { 15, "Dynamically allocated"},
132   {  0, NULL },
133 };
134
135 static const value_string nsapi_abrv[] = {
136   {  0, "0"},
137   {  1, "PTM-M" },
138   {  2, "2" },
139   {  3, "3"},
140   {  4, "4" },
141   {  5, "DYN5" },
142   {  6, "DYN6" },
143   {  7, "DYN7" },
144   {  8, "DYN8" },
145   {  9, "DYN9" },
146   { 10, "DYN10" },
147   { 11, "DYN11" },
148   { 12, "DYN12" },
149   { 13, "DYN13" },
150   { 14, "DYN14" },
151   { 15, "DYN15" },
152   {  0, NULL },
153 };
154
155 static const value_string compression_vals[] = {
156   {  0, "No compression"},
157   {  1, "Pointer to selected protocol/data compression mechanism" },
158   {  2, "Pointer to selected protocol/data compression mechanism" },
159   {  3, "Pointer to selected protocol/data compression mechanism" },
160   {  4, "Pointer to selected protocol/data compression mechanism" },
161   {  5, "Pointer to selected protocol/data compression mechanism" },
162   {  6, "Pointer to selected protocol/data compression mechanism" },
163   {  7, "Pointer to selected protocol/data compression mechanism" },
164   {  8, "Pointer to selected protocol/data compression mechanism" },
165   {  9, "Pointer to selected protocol/data compression mechanism" },
166   { 10, "Pointer to selected protocol/data compression mechanism" },
167   { 11, "Pointer to selected protocol/data compression mechanism" },
168   { 12, "Pointer to selected protocol/data compression mechanism" },
169   { 13, "Pointer to selected protocol/data compression mechanism" },
170   { 14, "Pointer to selected protocol/data compression mechanism" },
171   { 15, "Pointer to selected protocol/data compression mechanism" },
172   { 0, NULL },
173 };
174
175 static const true_false_string x_bit = {
176   "Invalid",
177   "Set to 0 by transmitting SNDCP entity (ignored by receiver)"
178 };
179 static const true_false_string f_bit = {
180   "This SN-PDU is the first segment of an N-PDU",
181   "This SN-PDU is not the first segment of an N-PDU"
182 };
183 static const true_false_string t_bit = {
184   "SN-UNITDATA PDU",
185   "SN-DATA PDU"
186 };
187 static const true_false_string m_bit = {
188   "Not the last segment of N-PDU, more segments to follow",
189   "Last segment of N-PDU"
190 };
191
192 /* Code to actually dissect the packets
193 */
194 static void
195 dissect_sndcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
196 {
197   guint8         addr_field, comp_field, npdu_field1, nsapi, dcomp=0, pcomp=0;
198   guint16        offset=0, npdu=0, segment=0, npdu_field2;
199   tvbuff_t      *next_tvb, *npdu_tvb;
200   gint           len;
201   gboolean       first, more_frags, unack;
202
203   /* Set up structures needed to add the protocol subtree and manage it
204    */
205   proto_item *ti, *address_field_item, *compression_field_item, *npdu_field_item;
206   proto_tree *sndcp_tree = NULL, *address_field_tree, *compression_field_tree, *npdu_field_tree;
207
208   /* Make entries in Protocol column and clear Info column on summary display
209    */
210   col_set_str(pinfo->cinfo, COL_PROTOCOL, "SNDCP");
211   col_clear(pinfo->cinfo, COL_INFO);
212
213   /* create display subtree for the protocol
214    */
215   if (tree) {
216     ti         = proto_tree_add_item(tree, proto_sndcp, tvb, 0, -1, ENC_NA);
217     sndcp_tree = proto_item_add_subtree(ti, ett_sndcp);
218   }
219
220   /* get address field from next byte
221    */
222   addr_field = tvb_get_guint8(tvb,offset);
223   nsapi      = addr_field & 0xF;
224   first      = addr_field & MASK_F;
225   more_frags = addr_field & MASK_M;
226   unack      = addr_field & MASK_T;
227
228   /* add subtree for the address field
229    */
230   if (tree) {
231     address_field_item = proto_tree_add_uint_format(sndcp_tree,hf_sndcp_nsapi,
232                                                     tvb, offset,1, nsapi,
233                                                     "Address field  NSAPI: %d", nsapi );
234     address_field_tree = proto_item_add_subtree(address_field_item, ett_sndcp_address_field);
235     proto_tree_add_boolean(address_field_tree, hf_sndcp_x, tvb,offset,1, addr_field );
236     proto_tree_add_boolean(address_field_tree, hf_sndcp_f, tvb,offset,1, addr_field );
237     proto_tree_add_boolean(address_field_tree, hf_sndcp_t, tvb,offset,1, addr_field );
238     proto_tree_add_boolean(address_field_tree, hf_sndcp_m, tvb,offset,1, addr_field );
239     proto_tree_add_uint(address_field_tree, hf_sndcp_nsapib, tvb, offset, 1, addr_field );
240   }
241   offset++;
242
243   /* get compression pointers from next byte if this is the first segment
244    */
245   if (first) {
246     comp_field = tvb_get_guint8(tvb,offset);
247     dcomp      = comp_field & 0xF0;
248     pcomp      = comp_field & 0x0F;
249
250     /* add subtree for the compression field
251      */
252     if (tree) {
253       if (!pcomp) {
254         if (!dcomp) {
255           compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "No compression");
256         }
257         else {
258           compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Data compression");
259         }
260       }
261       else {
262         if (!dcomp) {
263           compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Protocol compression");
264         }
265         else {
266           compression_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Data and Protocol compression");
267         }
268       }
269       compression_field_tree = proto_item_add_subtree(compression_field_item, ett_sndcp_compression_field);
270       proto_tree_add_uint(compression_field_tree, hf_sndcp_dcomp, tvb, offset, 1, comp_field );
271       proto_tree_add_uint(compression_field_tree, hf_sndcp_pcomp, tvb, offset, 1, comp_field );
272     }
273     offset++;
274
275     /* get N-PDU number from next byte for acknowledged mode (only for first segment)
276      */
277     if (!unack) {
278       npdu = npdu_field1 = tvb_get_guint8(tvb,offset);
279       col_add_fstr(pinfo->cinfo, COL_INFO, "SN-DATA N-PDU %d", npdu_field1);
280       if (tree) {
281         npdu_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,1, "Acknowledged mode, N-PDU %d", npdu_field1 );
282         npdu_field_tree = proto_item_add_subtree(npdu_field_item, ett_sndcp_npdu_field);
283         proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu1, tvb, offset, 1, npdu_field1 );
284       }
285       offset++;
286     }
287   }
288
289   /* get segment and N-PDU number from next two bytes for unacknowledged mode
290    */
291   if (unack) {
292     npdu_field2     = tvb_get_ntohs(tvb, offset);
293     segment         = (npdu_field2 & 0xF000) >> 12;
294     npdu            = (npdu_field2 & 0x0FFF);
295     col_add_fstr(pinfo->cinfo, COL_INFO, "SN-UNITDATA N-PDU %d (segment %d)", npdu, segment);
296     if (tree) {
297       npdu_field_item = proto_tree_add_text(sndcp_tree, tvb, offset,2, "Unacknowledged mode, N-PDU %d (segment %d)", npdu, segment );
298       npdu_field_tree = proto_item_add_subtree(npdu_field_item, ett_sndcp_npdu_field);
299       proto_tree_add_uint(npdu_field_tree, hf_sndcp_segment, tvb, offset, 2, npdu_field2 );
300       proto_tree_add_uint(npdu_field_tree, hf_sndcp_npdu2, tvb, offset, 2, npdu_field2 );
301     }
302     offset         += 2;
303   }
304
305   /* handle N-PDU data, reassemble if necessary
306    */
307   if (first && !more_frags) {
308     next_tvb = tvb_new_subset_remaining (tvb, offset);
309
310     if (!dcomp && !pcomp) {
311       call_dissector(ip_handle, next_tvb, pinfo, tree);
312     }
313     else {
314       call_dissector(data_handle, next_tvb, pinfo, tree);
315     }
316   }
317   else {
318     /* Try reassembling fragments
319      */
320     fragment_head  *fd_npdu         = NULL;
321     guint32         reassembled_in  = 0;
322     gboolean        save_fragmented = pinfo->fragmented;
323
324     len = tvb_length_remaining(tvb, offset);
325     if(len<=0){
326         return;
327     }
328
329     pinfo->fragmented = TRUE;
330
331     if (unack)
332       fd_npdu  = fragment_add_seq_check(&npdu_reassembly_table, tvb, offset,
333                                         pinfo, npdu, NULL, segment, len, more_frags);
334     else
335       fd_npdu  = fragment_add(&npdu_reassembly_table, tvb, offset, pinfo, npdu, NULL,
336                               offset, len, more_frags);
337
338     npdu_tvb = process_reassembled_data(tvb, offset, pinfo,
339                                         "Reassembled N-PDU", fd_npdu, &npdu_frag_items,
340                                         NULL, sndcp_tree);
341     if (fd_npdu) {
342       /* Reassembled
343        */
344       reassembled_in = fd_npdu->reassembled_in;
345       if (pinfo->fd->num == reassembled_in) {
346         /* Reassembled in this very packet:
347          * We can safely hand the tvb to the IP dissector
348          */
349         call_dissector(ip_handle, npdu_tvb, pinfo, tree);
350       }
351       else {
352         /* Not reassembled in this packet
353          */
354         col_append_fstr(pinfo->cinfo, COL_INFO,
355                           " (N-PDU payload reassembled in packet %u)",
356                           fd_npdu->reassembled_in);
357         if (tree) {
358           proto_tree_add_text(sndcp_tree, tvb, offset, -1, "Payload");
359         }
360       }
361     } else {
362       /* Not reassembled yet, or not reassembled at all
363        */
364       if (unack)
365         col_append_fstr(pinfo->cinfo, COL_INFO, " (Unreassembled fragment %u)", segment);
366       else
367         col_append_str(pinfo->cinfo, COL_INFO, " (Unreassembled fragment)");
368
369       if (tree) {
370         proto_tree_add_text(sndcp_tree, tvb, offset, -1, "Payload");
371       }
372     }
373     /* Now reset fragmentation information in pinfo
374      */
375     pinfo->fragmented = save_fragmented;
376   }
377 }
378
379
380 /* Register the protocol with Wireshark
381    this format is required because a script is used to build the C function
382    that calls all the protocol registration.
383 */
384
385 void
386 proto_register_sndcp(void)
387 {
388   /* Setup list of header fields
389    */
390   static hf_register_info hf[] = {
391     { &hf_sndcp_nsapi,
392       { "NSAPI",
393         "sndcp.nsapi",
394         FT_UINT8, BASE_DEC, VALS(nsapi_abrv), 0x0,
395         "Network Layer Service Access Point Identifier", HFILL
396       }
397     },
398     { &hf_sndcp_x,
399       { "Spare bit",
400         "sndcp.x",
401         FT_BOOLEAN,8, TFS(&x_bit), MASK_X,
402         "Spare bit (should be 0)", HFILL
403       }
404     },
405     { &hf_sndcp_f,
406       { "First segment indicator bit",
407         "sndcp.f",
408         FT_BOOLEAN,8, TFS(&f_bit), MASK_F,
409         NULL, HFILL
410       }
411     },
412     { &hf_sndcp_t,
413       { "Type",
414         "sndcp.t",
415         FT_BOOLEAN,8, TFS(&t_bit), MASK_T,
416         "SN-PDU Type", HFILL
417       }
418     },
419     { &hf_sndcp_m,
420       { "More bit",
421         "sndcp.m",
422         FT_BOOLEAN,8, TFS(&m_bit), MASK_M,
423         NULL, HFILL
424       }
425     },
426     { &hf_sndcp_dcomp,
427       { "DCOMP",
428         "sndcp.dcomp",
429         FT_UINT8, BASE_DEC, VALS(compression_vals), 0xF0,
430         "Data compression coding", HFILL
431       }
432     },
433     { &hf_sndcp_pcomp,
434       { "PCOMP",
435         "sndcp.pcomp",
436         FT_UINT8, BASE_DEC, VALS(compression_vals), 0x0F,
437         "Protocol compression coding", HFILL
438       }
439     },
440     { &hf_sndcp_nsapib,
441       { "NSAPI",
442         "sndcp.nsapib",
443         FT_UINT8, BASE_DEC , VALS(nsapi_t), 0xf,
444         "Network Layer Service Access Point Identifier",HFILL
445       }
446     },
447     { &hf_sndcp_segment,
448       { "Segment",
449         "sndcp.segment",
450         FT_UINT16, BASE_DEC, NULL, 0xF000,
451         "Segment number", HFILL
452       }
453     },
454     { &hf_sndcp_npdu1,
455       { "N-PDU",
456         "sndcp.npdu",
457         FT_UINT8, BASE_DEC, NULL, 0,
458         NULL, HFILL
459       }
460     },
461     { &hf_sndcp_npdu2,
462       { "N-PDU",
463         "sndcp.npdu",
464         FT_UINT16, BASE_DEC, NULL, 0x0FFF,
465         NULL, HFILL
466       }
467     },
468
469     /* Fragment fields
470      */
471     { &hf_npdu_fragment_overlap,
472       { "Fragment overlap",
473         "npdu.fragment.overlap",
474         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
475         "Fragment overlaps with other fragments", HFILL
476       }
477     },
478     { &hf_npdu_fragment_overlap_conflict,
479       { "Conflicting data in fragment overlap",
480         "npdu.fragment.overlap.conflict",
481         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
482         "Overlapping fragments contained conflicting data", HFILL
483       }
484     },
485     { &hf_npdu_fragment_multiple_tails,
486       { "Multiple tail fragments found",
487         "npdu.fragment.multipletails",
488         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
489         "Several tails were found when defragmenting the packet", HFILL
490       }
491     },
492     { &hf_npdu_fragment_too_long_fragment,
493       { "Fragment too long",
494         "npdu.fragment.toolongfragment",
495         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
496         "Fragment contained data past end of packet", HFILL
497       }
498     },
499     { &hf_npdu_fragment_error,
500       { "Defragmentation error",
501         "npdu.fragment.error",
502         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
503         "Defragmentation error due to illegal fragments", HFILL
504       }
505     },
506     { &hf_npdu_fragment_count,
507       { "Fragment count",
508         "npdu.fragment.count",
509         FT_UINT32, BASE_DEC, NULL, 0x0,
510         NULL, HFILL
511       }
512     },
513     { &hf_npdu_reassembled_in,
514       { "Reassembled in",
515         "npdu.reassembled.in",
516         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
517         "N-PDU fragments are reassembled in the given packet", HFILL
518       }
519     },
520     { &hf_npdu_reassembled_length,
521       { "Reassembled N-PDU length",
522         "npdu.reassembled.length",
523         FT_UINT32, BASE_DEC, NULL, 0x0,
524         "The total length of the reassembled payload", HFILL
525       }
526     },
527     { &hf_npdu_fragment,
528       { "N-PDU Fragment",
529         "npdu.fragment",
530         FT_FRAMENUM, BASE_NONE, NULL, 0x0,
531         NULL, HFILL
532       }
533     },
534     { &hf_npdu_fragments,
535       { "N-PDU Fragments",
536         "npdu.fragments",
537         FT_NONE, BASE_NONE, NULL, 0x0,
538         NULL, HFILL
539       }
540     }
541   };
542
543     /* Setup protocol subtree array */
544   static gint *ett[] = {
545     &ett_sndcp     ,
546     &ett_sndcp_address_field,
547     &ett_sndcp_compression_field,
548     &ett_sndcp_npdu_field,
549     &ett_npdu_fragment,
550     &ett_npdu_fragments,
551   };
552
553   /* Register the protocol name and description */
554   proto_sndcp = proto_register_protocol("Subnetwork Dependent Convergence Protocol",
555                                         "SNDCP", "sndcp");
556
557   /* Required function calls to register the header fields and subtrees used */
558   proto_register_field_array(proto_sndcp, hf, array_length(hf));
559   proto_register_subtree_array(ett, array_length(ett));
560   register_dissector("sndcp", dissect_sndcp, proto_sndcp);
561   register_init_routine(sndcp_defragment_init);
562 }
563
564 /* If this dissector uses sub-dissector registration add a registration routine.
565    This format is required because a script is used to find these routines and
566    create the code that calls these routines.
567 */
568 void
569 proto_reg_handoff_sndcp(void)
570 {
571   dissector_handle_t sndcp_handle;
572
573   sndcp_handle = find_dissector("sndcp");
574
575   /* Register SNDCP dissector with LLC layer for SAPI 3,5,9 and 11
576    */
577   dissector_add_uint("llcgprs.sapi",  3, sndcp_handle);
578   dissector_add_uint("llcgprs.sapi",  5, sndcp_handle);
579   dissector_add_uint("llcgprs.sapi",  9, sndcp_handle);
580   dissector_add_uint("llcgprs.sapi", 11, sndcp_handle);
581
582   /* Find IP and data handle for upper layer dissectors
583    */
584   ip_handle   = find_dissector("ip");
585   data_handle = find_dissector("data");
586 }