some compilers dont like unnamed unions and structs
[obnox/wireshark/wip.git] / epan / dissectors / packet-gprs-llc.c
1 /* packet-llcgprs.c
2  * Routines for Logical Link Control GPRS dissection ETSI 4.64
3  * Copyright 2000, Josef Korelus <jkor@quick.cz>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  * 
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.
15  * 
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.
20  * 
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.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <glib.h>
35
36 #include <epan/packet.h>
37 #include "prefs.h"
38
39 #define I_FORMAT        1
40 #define S_FORMAT        2
41 #define UI_FORMAT       3
42 #define U_FORMAT        4
43 #define I_SACK          5
44 #define S_SACK          6
45 #define UI_MASK_FMT    0xe000
46 #define UI_MASK_SPB    0x1800
47 #define UI_MASK_NU     0x07fc
48 #define UI_MASK_E      0x0002
49 #define UI_MASK_PM     0x0001
50
51 /* Initialize the protocol and registered fields */
52 static int proto_llcgprs       = -1;
53 static int hf_llcgprs_pd       = -1;
54 static int hf_llcgprs_cr       = -1;
55 static int hf_llcgprs_sapi     = -1;
56 static int hf_llcgprs_sapib    = -1;
57 static int hf_llcgprs_U_fmt    = -1;/* 3 upper bits in controlfield (UI format) */
58 static int hf_llcgprs_sp_bits  = -1; /*Spare bits in control field*/
59 static int hf_llcgprs_NU       = -1; /*Transmited unconfirmed sequence number*/
60 static int hf_llcgprs_E_bit    = -1;/* Encryption mode bit*/
61 static int hf_llcgprs_PM_bit   = -1;
62 static int hf_llcgprs_Un       = -1;
63 static int hf_llcgprs_As      = -1;
64 static int hf_llcgprs_ucom     = -1;
65 static int hf_llcgprs_PF        = -1;
66 static int hf_llcgprs_S_fmt     = -1;
67 static int hf_llcgprs_NR        = -1;
68 static int hf_llcgprs_sjsd      = -1;
69 /* MLT CHANGES - Additional display masks */
70 static int hf_llcgprs_k = -1;
71 static int hf_llcgprs_isack_ns = -1;
72 static int hf_llcgprs_isack_nr = -1;
73 static int hf_llcgprs_isack_sfb = -1;
74 static int hf_llcgprs_rbyte = -1;
75 static int hf_llcgprs_kmask = -1;
76 static int hf_llcgprs_ifmt = -1;
77 static int hf_llcgprs_ia = -1;
78 static int hf_llcgprs_izerobit = -1;
79 static int hf_llcgprs_sspare = -1;
80 static int hf_llcgprs_xid_xl = -1;
81 static int hf_llcgprs_xid_type = -1;
82 static int hf_llcgprs_xid_len1 = -1;
83 static int hf_llcgprs_xid_len2 = -1;
84 static int hf_llcgprs_xid_spare = -1;
85 static int hf_llcgprs_xid_byte = -1;
86 static int hf_llcgprs_frmr_cf = -1;
87 static int hf_llcgprs_frmr_spare = -1;
88 static int hf_llcgprs_frmr_vs = -1;
89 static int hf_llcgprs_frmr_vr = -1;
90 static int hf_llcgprs_frmr_cr = -1;
91 static int hf_llcgprs_frmr_w4 = -1;
92 static int hf_llcgprs_frmr_w3 = -1;
93 static int hf_llcgprs_frmr_w2 = -1;
94 static int hf_llcgprs_frmr_w1 = -1;
95 static int hf_llcgprs_tom_rl = -1;
96 static int hf_llcgprs_tom_pd = -1;
97 static int hf_llcgprs_tom_header = -1;
98 static int hf_llcgprs_tom_data = -1;
99
100 /* Unnumbered Commands and Responses (U Frames) */
101 #define U_DM    0x01
102 #define U_DISC  0x04
103 #define U_UA    0x06
104 #define U_SABM  0x07
105 #define U_FRMR  0x08
106 #define U_XID   0x0B
107 #define U_NULL  0x00
108
109 /* SAPI value constants */
110 #define SAPI_LLGMM      0x01
111 #define SAPI_TOM2       0x02
112 #define SAPI_LL3        0x03
113 #define SAPI_LL5        0x05
114 #define SAPI_LLSMS      0x07
115 #define SAPI_TOM8       0x08
116 #define SAPI_LL9        0x09
117 #define SAPI_LL11       0x0B
118
119 /* END MLT CHANGES */
120
121 /* Initialize the subtree pointers */
122 static gint ett_llcgprs = -1;
123 static gint ett_llcgprs_adf = -1;
124 static gint ett_llcgprs_ctrlf = -1;
125 static gint ett_ui = -1;
126 static gint ett_llcgprs_sframe = -1;
127
128 static dissector_handle_t data_handle;
129
130 static gboolean ignore_cipher_bit = FALSE;
131
132 static dissector_table_t llcgprs_subdissector_table;
133 static const value_string sapi_t[] = {
134         {  0, "Reserved"},
135         {  1, "GPRS Mobility Management" },
136         {  2, "Tunnelling of messages 2" },
137         {  3, "User data 3"},
138         {  4, "Reserved" },
139         {  5, "User data 5" },
140         {  6, "Reserved" },
141         {  7, "SMS" },
142         {  8, "Tunneling of messages 8" },
143         {  9, "User data 9" },
144         { 10, "Reserved" },
145         { 11, "User data 11" },
146         { 12, "Reserved" },
147         { 13, "Reserved" },
148         { 14, "Reserved" },
149         { 15, "Reserved" },
150         {  0, NULL },
151 };
152
153 static const value_string sapi_abrv[] = {
154         {  0, "Reserved 0"},
155         {  1, "LLGMM" },
156         {  2, "TOM2" },
157         {  3, "LL3"},
158         {  4, "Reserved 4" },
159         {  5, "LL5" },
160         {  6, "Reserved 6" },
161         {  7, "LLSMS" },
162         {  8, "TOM8" },
163         {  9, "LL9" },
164         { 10, "Reserved 10" },
165         { 11, "LL11" },
166         { 12, "Reserved 12" },
167         { 13, "Reserved 13" },
168         { 14, "Reserved 14" },
169         { 15, "Reserved 15" },
170         { 0, NULL }
171 };
172 static const true_false_string a_bit = {
173         "To solicit an acknowledgement from the peer LLE. ",
174         "The peer LLE is not requested to send an acknowledgment."
175 };
176
177 static const true_false_string pd_bit = {
178         "Invalid frame PD=1",
179         "OK"
180 };
181 static const true_false_string e_bit = {
182         " encrypted frame",
183         " non encrypted frame"  
184 };
185 static const true_false_string pm_bit = {
186         "FCS covers the frame header and information fields",
187         "FCS covers only the frame header and first N202 octets of the information field"
188 };
189 static const true_false_string cr_bit = {
190         "DownLink/UpLink = Command/Response",
191         "DownLink/UpLink = Response/Command"
192 };
193 /* bits are swaped comparing with "Table 3" in ETSI document*/
194 static const value_string pme[] = {
195         { 0, "unprotected,non-ciphered information" },
196         { 1, "protected, non-ciphered information" },
197         { 2, "unprotected,ciphered information"},
198         { 3, "protected, ciphered information" },
199         { 0, NULL},
200 };
201
202 /* MLT CHANGES - adding XID parameter types & TOM protocols */
203 static const value_string xid_param_type_str[] = {
204         {0x0, "Version (LLC version number)"},
205         {0x1, "IOV-UI (ciphering Input offset value for UI frames)"},
206         {0x2, "IOV-I (ciphering Input offset value for I frames)"},
207         {0x3, "T200 (retransmission timeout)"},
208         {0x4, "N200 (max number of retransmissions)"},
209         {0x5, "N201-U (max info field length for U and UI frames)"},
210         {0x6, "N201-I (max info field length for I frames)"},
211         {0x7, "mD (I frame buffer size in the DL direction)"},
212         {0x8, "mU (I frame buffer size in the UL direction)"},
213         {0x9, "kD (window size in the DL direction)"},
214         {0xA, "kU (window size in the UL direction)"},
215         {0xB, "Layer-3 Parameters"},
216         {0xC, "Reset"},
217         {0, NULL}
218 };
219
220 static const value_string tompd_formats[] = {
221         {0x0, "Not specified"},
222         {0x1, "TIA/EIA-136"},
223         {0x2, "RRLP"},
224         {0x3, "Reserved value 3"},
225         {0x4, "Reserved value 4"},
226         {0x5, "Reserved value 5"},
227         {0x6, "Reserved value 6"},
228         {0x7, "Reserved value 7"},
229         {0x8, "Reserved value 8"},
230         {0x9, "Reserved value 9"},
231         {0xA, "Reserved value 10"},
232         {0xB, "Reserved value 11"},
233         {0xC, "Reserved value 12"},
234         {0xD, "Reserved value 13"},
235         {0xE, "Reserved value 14"},
236         {0xF, "Reserved for extension"},
237         {0, NULL}
238 };
239 /* END MLT CHANGES */
240
241 static const value_string cr_formats_unnumb[]= {
242         {  0x1, "DM-response" },
243         {  0x4, "DISC-command" },
244         {  0x6, "UA-response" },
245         {  0x7, "SABM" },
246         {  0x8, "FRMR" },
247         { 0xb, "XID" },
248         { 0, NULL },
249 };
250 static const value_string cr_formats_ipluss[] = {
251         { 0x0,"RR" },
252         { 0x1,"ACK" },
253         { 0x2,"RNR" },
254         { 0x3,"SACK" },
255         { 0, NULL },
256 };
257
258 /* CRC24 table - FCS */
259 guint32 tbl_crc24[256] = {
260         0x00000000, 0x00d6a776, 0x00f64557, 0x0020e221, 0x00b78115, 0x00612663, 0x0041c442, 0x00976334, 
261         0x00340991, 0x00e2aee7, 0x00c24cc6, 0x0014ebb0, 0x00838884, 0x00552ff2, 0x0075cdd3, 0x00a36aa5, 
262         0x00681322, 0x00beb454, 0x009e5675, 0x0048f103, 0x00df9237, 0x00093541, 0x0029d760, 0x00ff7016, 
263         0x005c1ab3, 0x008abdc5, 0x00aa5fe4, 0x007cf892, 0x00eb9ba6, 0x003d3cd0, 0x001ddef1, 0x00cb7987, 
264         0x00d02644, 0x00068132, 0x00266313, 0x00f0c465, 0x0067a751, 0x00b10027, 0x0091e206, 0x00474570, 
265         0x00e42fd5, 0x003288a3, 0x00126a82, 0x00c4cdf4, 0x0053aec0, 0x008509b6, 0x00a5eb97, 0x00734ce1, 
266         0x00b83566, 0x006e9210, 0x004e7031, 0x0098d747, 0x000fb473, 0x00d91305, 0x00f9f124, 0x002f5652, 
267         0x008c3cf7, 0x005a9b81, 0x007a79a0, 0x00acded6, 0x003bbde2, 0x00ed1a94, 0x00cdf8b5, 0x001b5fc3, 
268         0x00fb4733, 0x002de045, 0x000d0264, 0x00dba512, 0x004cc626, 0x009a6150, 0x00ba8371, 0x006c2407, 
269         0x00cf4ea2, 0x0019e9d4, 0x00390bf5, 0x00efac83, 0x0078cfb7, 0x00ae68c1, 0x008e8ae0, 0x00582d96, 
270         0x00935411, 0x0045f367, 0x00651146, 0x00b3b630, 0x0024d504, 0x00f27272, 0x00d29053, 0x00043725, 
271         0x00a75d80, 0x0071faf6, 0x005118d7, 0x0087bfa1, 0x0010dc95, 0x00c67be3, 0x00e699c2, 0x00303eb4, 
272         0x002b6177, 0x00fdc601, 0x00dd2420, 0x000b8356, 0x009ce062, 0x004a4714, 0x006aa535, 0x00bc0243, 
273         0x001f68e6, 0x00c9cf90, 0x00e92db1, 0x003f8ac7, 0x00a8e9f3, 0x007e4e85, 0x005eaca4, 0x00880bd2, 
274         0x00437255, 0x0095d523, 0x00b53702, 0x00639074, 0x00f4f340, 0x00225436, 0x0002b617, 0x00d41161, 
275         0x00777bc4, 0x00a1dcb2, 0x00813e93, 0x005799e5, 0x00c0fad1, 0x00165da7, 0x0036bf86, 0x00e018f0, 
276         0x00ad85dd, 0x007b22ab, 0x005bc08a, 0x008d67fc, 0x001a04c8, 0x00cca3be, 0x00ec419f, 0x003ae6e9, 
277         0x00998c4c, 0x004f2b3a, 0x006fc91b, 0x00b96e6d, 0x002e0d59, 0x00f8aa2f, 0x00d8480e, 0x000eef78, 
278         0x00c596ff, 0x00133189, 0x0033d3a8, 0x00e574de, 0x007217ea, 0x00a4b09c, 0x008452bd, 0x0052f5cb, 
279         0x00f19f6e, 0x00273818, 0x0007da39, 0x00d17d4f, 0x00461e7b, 0x0090b90d, 0x00b05b2c, 0x0066fc5a, 
280         0x007da399, 0x00ab04ef, 0x008be6ce, 0x005d41b8, 0x00ca228c, 0x001c85fa, 0x003c67db, 0x00eac0ad, 
281         0x0049aa08, 0x009f0d7e, 0x00bfef5f, 0x00694829, 0x00fe2b1d, 0x00288c6b, 0x00086e4a, 0x00dec93c, 
282         0x0015b0bb, 0x00c317cd, 0x00e3f5ec, 0x0035529a, 0x00a231ae, 0x007496d8, 0x005474f9, 0x0082d38f, 
283         0x0021b92a, 0x00f71e5c, 0x00d7fc7d, 0x00015b0b, 0x0096383f, 0x00409f49, 0x00607d68, 0x00b6da1e, 
284         0x0056c2ee, 0x00806598, 0x00a087b9, 0x007620cf, 0x00e143fb, 0x0037e48d, 0x001706ac, 0x00c1a1da, 
285         0x0062cb7f, 0x00b46c09, 0x00948e28, 0x0042295e, 0x00d54a6a, 0x0003ed1c, 0x00230f3d, 0x00f5a84b, 
286         0x003ed1cc, 0x00e876ba, 0x00c8949b, 0x001e33ed, 0x008950d9, 0x005ff7af, 0x007f158e, 0x00a9b2f8, 
287         0x000ad85d, 0x00dc7f2b, 0x00fc9d0a, 0x002a3a7c, 0x00bd5948, 0x006bfe3e, 0x004b1c1f, 0x009dbb69, 
288         0x0086e4aa, 0x005043dc, 0x0070a1fd, 0x00a6068b, 0x003165bf, 0x00e7c2c9, 0x00c720e8, 0x0011879e, 
289         0x00b2ed3b, 0x00644a4d, 0x0044a86c, 0x00920f1a, 0x00056c2e, 0x00d3cb58, 0x00f32979, 0x00258e0f, 
290         0x00eef788, 0x003850fe, 0x0018b2df, 0x00ce15a9, 0x0059769d, 0x008fd1eb, 0x00af33ca, 0x007994bc, 
291         0x00dafe19, 0x000c596f, 0x002cbb4e, 0x00fa1c38, 0x006d7f0c, 0x00bbd87a, 0x009b3a5b, 0x004d9d2d
292 };
293
294 #define INIT_CRC24      0xffffff
295
296 static guint32 crc_calc(guint32 fcs, tvbuff_t *tvb, guint len)
297 {
298         const guchar *cp;
299
300         cp = tvb_get_ptr(tvb, 0, len);
301         while (len--)
302                 fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff];
303         return fcs;
304 }
305
306 typedef enum {
307         FCS_VALID,
308         FCS_NOT_VALID,
309         FCS_NOT_COMPUTED
310 } fcs_status_t;
311
312 /* Code to actually dissect the packets */
313 static void
314 dissect_llcgprs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
315 {
316         guint8 addr_fld=0, sapi=0, ctrl_fld_fb=0, frame_format, tmp=0 ;
317         guint16 offset=0 , epm = 0, nu=0,ctrl_fld_ui_s=0,crc_start=0 ;
318         proto_item *ti, *addres_field_item, *ctrl_field_item, *ui_ti;
319         proto_tree *llcgprs_tree=NULL , *ad_f_tree =NULL, *ctrl_f_tree=NULL, *ui_tree=NULL;
320         tvbuff_t *next_tvb;
321         guint length;
322         guint32 fcs, fcs_calc;
323         fcs_status_t fcs_status;
324
325         /* MLT CHANGES - additional variables */
326         guint16 ns = 0;
327         guint16 nr = 0;
328         guint8 k = 0;
329         guint8 m_bits = 0;
330         guint8 info_len = 0;
331         proto_item *uinfo_field = NULL;
332         proto_tree *uinfo_tree = NULL;
333         /* END MLT CHANGES */
334
335         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
336         {
337                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "GPRS-LLC");
338         }
339         
340     addr_fld = tvb_get_guint8(tvb,offset);
341         offset++;
342         
343         if (addr_fld > 128 ) 
344         {
345                 if (check_col(pinfo->cinfo,COL_INFO))
346                 {
347                        col_add_str(pinfo->cinfo,COL_INFO,"Invalid packet - Protocol Discriminator bit is set to 1");
348                 }
349                 return;
350         }
351         
352         sapi = addr_fld & 0xF;
353         
354         if (check_col(pinfo->cinfo, COL_INFO)) 
355         {
356                 col_add_fstr(pinfo->cinfo, COL_INFO, "SAPI: %s", match_strval(sapi,sapi_abrv));
357         }
358         
359           
360         length = tvb_reported_length(tvb);
361         if (tvb_bytes_exist(tvb, 0, length) && length >= 3)
362         {
363                 /*
364                  * We have all the packet data, including the full FCS,
365                  * so we can compute the FCS.
366                  *
367                  * XXX - do we need to check the PM bit?
368                  */
369             crc_start = length-3;
370                 fcs_calc = crc_calc ( INIT_CRC24 , tvb, crc_start );
371                 fcs_calc = ~fcs_calc;
372                 fcs_calc &= 0xffffff;
373
374                 fcs = tvb_get_letoh24(tvb, crc_start);
375                 if ( fcs_calc == fcs )
376                 {
377                         fcs_status = FCS_VALID;
378                 }
379                 else
380                 {
381                         fcs_status = FCS_NOT_VALID;
382                 }
383         } 
384         else
385         {
386                 /* We don't have enough data to compute the FCS. */
387                 fcs_status = FCS_NOT_COMPUTED;
388
389                 /* Squelch compiler warnings. */
390                 fcs = 0;
391                 fcs_calc = 0;
392                 crc_start = 0;
393         }
394         
395         /* In the interest of speed, if "tree" is NULL, don't do any work not
396                 necessary to generate protocol tree items. */
397         
398         if (tree) 
399         {
400
401                 ti = proto_tree_add_protocol_format(tree, proto_llcgprs, tvb, 0, -1,"MS-SGSN LLC (Mobile Station - Serving GPRS Support Node Logical Link Control)  SAPI: %s", match_strval(sapi,sapi_t));
402
403                 llcgprs_tree = proto_item_add_subtree(ti, ett_llcgprs);
404
405                 /* add an item to the subtree, see section 1.6 for more information */
406                 switch (fcs_status) {
407
408                 case FCS_VALID:
409                         proto_tree_add_text (llcgprs_tree, tvb, crc_start, 3, 
410                                 "FCS: 0x%06x (correct)", fcs_calc&0xffffff);
411                         break;
412
413                 case FCS_NOT_VALID:
414                         proto_tree_add_text (llcgprs_tree, tvb,crc_start, 3,
415                                 "FCS: 0x%06x  (incorrect, should be 0x%06x)", fcs, fcs_calc );
416                         break;
417
418                 case FCS_NOT_COMPUTED:
419                         break;  /* FCS not present */
420                 }
421
422                 addres_field_item = proto_tree_add_uint_format(llcgprs_tree,hf_llcgprs_sapi,
423                      tvb, 0,1, sapi, "Address field  SAPI: %s", match_strval(sapi,sapi_abrv));
424
425                 ad_f_tree = proto_item_add_subtree(addres_field_item, ett_llcgprs_adf);
426         proto_tree_add_boolean(ad_f_tree, hf_llcgprs_pd, tvb, 0, 1, addr_fld );
427         proto_tree_add_boolean(ad_f_tree, hf_llcgprs_cr, tvb, 0, 1, addr_fld );
428         proto_tree_add_uint(ad_f_tree, hf_llcgprs_sapib, tvb, 0, 1, addr_fld );
429         }       
430
431                           
432
433         ctrl_fld_fb = tvb_get_guint8(tvb,offset);
434         if (ctrl_fld_fb < 0xC0)
435         {
436                 frame_format = (ctrl_fld_fb < 0x80)? I_FORMAT : S_FORMAT;
437         }
438         else 
439         {
440                frame_format = (ctrl_fld_fb < 0xe0 )? UI_FORMAT : U_FORMAT;
441         }         
442
443         switch (frame_format)
444         {
445                 case I_FORMAT:
446                         if (check_col(pinfo->cinfo,COL_INFO))
447                         {
448                                 col_append_str(pinfo->cinfo,COL_INFO, ", I, ");
449                         }
450
451                         /* MLT CHANGES - additional parsing code */
452                         ns = tvb_get_ntohs(tvb, offset);
453                         ns = (ns >> 4)& 0x01FF;
454                         nr = ctrl_fld_ui_s = tvb_get_ntohs(tvb, offset + 1);
455                         nr = (nr >> 2) & 0x01FF;
456
457                         epm = ctrl_fld_ui_s & 0x3;
458
459                         /* advance to either R Bitmap or Payload */
460                         offset += 3;
461
462                         if (check_col(pinfo->cinfo, COL_INFO))
463                         {
464                                 col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm, cr_formats_ipluss));
465                                 col_append_fstr(pinfo->cinfo, COL_INFO, ", N(S) = %u", ns);
466                                 col_append_fstr(pinfo->cinfo, COL_INFO, ", N(R) = %u", nr);
467                         }
468
469                         if (tree)
470                         {
471                                 guint32 tmp;
472
473                                 ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, (offset-3), 
474                                         3,"Information format: %s: N(S) = %u,  N(R) = %u", 
475                                         match_strval(epm, cr_formats_ipluss), ns, nr);
476                                 ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
477
478                                 /* retrieve the second octet */
479                                 tmp = tvb_get_ntohs(tvb, (offset-3))  << 16;
480                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_ifmt, tvb, offset-3, 3, tmp);
481                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_ia, tvb, offset-3, 3, tmp);
482                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_izerobit, tvb, offset-3, 3, tmp);
483
484                                 tmp = ns << 12;
485                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_isack_ns, tvb, offset-3, 3, tmp);
486
487                                 tmp = nr << 2;
488                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_isack_nr, tvb, offset-3, 3, tmp);
489                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_isack_sfb, tvb, offset-3, 3, ctrl_fld_ui_s);
490                         }
491                         
492                         /* check to see if epm is SACK - meaning this is an ISACK frame */
493                         if (epm == 0x03)
494                         {
495                                 guint8 kmask;
496                                 /* SACK Frame */
497                                 k = kmask = tvb_get_guint8(tvb, offset);
498                                 k = k & 0x1F;
499
500                                 /* advance past the k field */
501                                 offset++;
502
503                                 /* the real value of k is actually k + 1 */
504                                 /* account for the off by one representation */
505                                 k++;
506
507                                 if (check_col(pinfo->cinfo, COL_INFO))
508                                 {
509                                         col_append_fstr(pinfo->cinfo, COL_INFO, ", k = %u", k);
510                                 }
511
512                                 if (tree)
513                                 {
514                                         guint8 loop_count = 0;
515                                         guint8 r_byte = 0;
516                                         guint16 location = offset;
517
518                                         ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, (offset-1), 
519                                                 (k+1), "SACK FRAME: k = %u", k);
520
521                                         ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
522                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_kmask, tvb, offset-1, 1, kmask);
523                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_k, tvb, offset-1, 1, k);
524
525                                         /* display the R Bitmap */
526                                         for (loop_count = 0; loop_count < k; loop_count++)
527                                         {
528                                                 r_byte = tvb_get_guint8(tvb, location);
529                                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_rbyte, tvb, location, 1, r_byte);
530                                                 location++;
531                                         }
532                                 }
533
534                                 /* step past the R Bitmap */
535                                 offset += k;
536                         }
537         
538                         if ((sapi == SAPI_TOM2) || (sapi == SAPI_TOM8))
539                         {
540                                 /* if SAPI is TOM do other parsing */   
541                                 if (tree)
542                                 {
543                                         guint8 tom_byte = 0;
544                                         guint8 remaining_length = 0;
545                                         guint8 tom_pd = 0;
546                                         int loop_counter = 0;
547
548                                         tom_byte = tvb_get_guint8(tvb, offset);
549                                         remaining_length = (tom_byte >> 4) & 0x0F;
550                                         tom_pd = tom_byte & 0x0F;
551
552                                         ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
553                                                 (crc_start-offset), "TOM Envelope - Protocol: %s", 
554                                                 match_strval(tom_pd, tompd_formats));
555
556                                         ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
557
558                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_rl, tvb, offset, 1, tom_byte);
559                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_pd, tvb, offset, 1, tom_byte);
560
561                                         /* step past the TOM header first byte */
562                                         offset++;
563
564                                         /* TOM remaining length field value 0x0F is reserved for extension */
565                                         if (remaining_length != 0x0F)
566                                         {
567                                                 /* parse the rest of the TOM header */
568                                                 for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
569                                                 {
570                                                         tom_byte = tvb_get_guint8(tvb, offset);
571
572                                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_header, tvb, 
573                                                                 offset, 1, tom_byte);
574
575                                                         /* step to the next byte */
576                                                         offset++;
577                                                 }
578
579                                                 remaining_length = crc_start - offset;
580
581                                                 /* parse the TOM message capsule */
582                                                 for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
583                                                 {
584                                                         tom_byte = tvb_get_guint8(tvb, offset);
585
586                                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_data, tvb, 
587                                                                 offset, 1, tom_byte);
588
589                                                         /* step to the next byte */
590                                                         offset++;
591                                                 }
592                                         }
593                                 }
594                         }
595                         else
596                         {
597                                 /* otherwise - call a subdissector */
598                                 next_tvb = tvb_new_subset(tvb, offset, (crc_start-offset), -1);
599                                 if (!dissector_try_port(llcgprs_subdissector_table,sapi, next_tvb, pinfo, tree))
600                                 /* if no subdissector is found, call the data dissector */
601                                 {
602                                         call_dissector(data_handle, next_tvb, pinfo, tree);
603                                 }
604                         }
605                         /* END MLT CHANGES */
606                                 
607                         break;
608                 case S_FORMAT:
609                 case UI_FORMAT:
610                         nu = ctrl_fld_ui_s = tvb_get_ntohs(tvb, offset);
611                         offset +=2;
612                         epm = ctrl_fld_ui_s & 0x3;
613                         nu = (nu >>2)&0x01FF;
614
615                         if (frame_format == S_FORMAT)
616                         {
617 /* S format */
618                                 if (check_col(pinfo->cinfo, COL_INFO))
619                                 {
620                                         col_append_str(pinfo->cinfo, COL_INFO, ", S, ");
621                                         col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm,cr_formats_ipluss));
622                                         col_append_fstr(pinfo->cinfo, COL_INFO, ", N(R) = %u", nu);
623                                 }
624                           
625                                 if (tree)
626                                 {
627                                         ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2, 2,
628                                                 "Supervisory format: %s: N(R) = %u",
629                                                 match_strval(epm,cr_formats_ipluss), nu);
630
631                                         ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
632                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_S_fmt, tvb, offset-2,
633                                                 2, ctrl_fld_ui_s);
634                                         proto_tree_add_boolean(ctrl_f_tree, hf_llcgprs_As, tvb, offset-2, 
635                                                 2, ctrl_fld_ui_s);
636
637                                         /* MLT CHANGES - added spare bits */
638                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sspare, tvb, offset-2, 
639                                                 2, ctrl_fld_ui_s);
640                                         /* END MLT CHANGES */
641                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_NR, tvb, offset-2, 
642                                                 2, ctrl_fld_ui_s);
643                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sjsd, tvb, offset-2, 
644                                                 2, ctrl_fld_ui_s);
645                                 }
646
647                                 /* MLT CHANGES - additional parsing code to handle SACK */
648                                 if ((ctrl_fld_ui_s & 0x03) == 0x03)
649                                 /* It is a SACK frame */
650                                 {
651                                         /* TODO: length is fudged - it is not correct */
652                                         guint32 sack_length = crc_start - offset;
653
654                                         if (tree)
655                                         {
656                                                 guint8 loop_count = 0;
657                                                 guint8 r_byte = 0;
658                                                 guint16 location = offset;
659
660                                                 ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
661                                                         sack_length, "SACK FRAME: length = %u", sack_length);
662                                         
663                                                 /* display the R Bitmap */
664                                                 for (loop_count = 0; loop_count < sack_length; loop_count++)
665                                                 {
666                                                         r_byte = tvb_get_guint8(tvb, location);
667                                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_rbyte, tvb, 
668                                                                 location, 1, r_byte);
669                                                         
670                                                         location++;
671                                                 }
672
673                                                 /* step past the r bitmap */
674                                                 offset += sack_length;
675                                         }
676                                 }
677
678                                 /* should parse the rest of the supervisory message based on type */
679                                 /* if SAPI is TOM do other parsing */
680                                 if ((sapi == SAPI_TOM2) || (sapi == SAPI_TOM8))
681                                 {
682                                         if (tree)
683                                         {
684                                                 guint8 tom_byte = 0;
685                                                 guint8 remaining_length = 0;
686                                                 guint8 tom_pd = 0;
687                                                 int loop_counter = 0;
688
689                                                 tom_byte = tvb_get_guint8(tvb, offset);
690                                                 remaining_length = (tom_byte >> 4) & 0x0F;
691                                                 tom_pd = tom_byte & 0x0F;
692
693                                                 ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
694                                                         (crc_start-offset), "TOM Envelope - Protocol: %s", 
695                                                         match_strval(tom_pd, tompd_formats));
696
697                                                 ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
698
699                                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_rl, tvb, offset, 1, tom_byte);
700                                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_pd, tvb, offset, 1, tom_byte);
701
702                                                 /* step past the TOM header first byte */
703                                                 offset++;
704
705                                                 /* TOM remaining length field value 0x0F is reserved for extension */
706                                                 if (remaining_length != 0x0F)
707                                                 {
708                                                         /* parse the rest of the TOM header */
709                                                         for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
710                                                         {
711                                                                 tom_byte = tvb_get_guint8(tvb, offset);
712
713                                                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_header, tvb, 
714                                                                         offset, 1, tom_byte);
715
716                                                                 /* step to the next byte */
717                                                                 offset++;
718                                                         }
719
720                                                         /* Amount of frame left from offset to crc */
721                                                         remaining_length = crc_start - offset;
722
723                                                         /* parse the TOM message capsule */
724                                                         for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
725                                                         {
726                                                                 tom_byte = tvb_get_guint8(tvb, offset);
727
728                                                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_data, tvb, 
729                                                                         offset, 1, tom_byte);
730
731                                                                 /* step to the next byte */
732                                                                 offset++;
733                                                         }
734                                                 }
735                                         }
736                                 }
737                                 else
738                                 {
739                                         /* otherwise - call a subdissector */
740                                         next_tvb = tvb_new_subset(tvb, offset, (crc_start-offset), -1 );
741                                         if (!dissector_try_port(llcgprs_subdissector_table,sapi, next_tvb, pinfo, tree))
742                                         {
743                                                 call_dissector(data_handle, next_tvb, pinfo, tree);
744                                         }
745                                 }
746                                 /* END MLT CHANGES */
747                         }
748                         else
749                         {
750 /*UI format*/
751                                 if (check_col(pinfo->cinfo, COL_INFO)) 
752                                 {
753                                         col_append_str(pinfo->cinfo, COL_INFO, ", UI, ");
754                                         col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm, pme ));
755                                         col_append_fstr(pinfo->cinfo,COL_INFO, ", N(U) = %u", nu);
756                                 }
757                         
758                                 if (tree)
759                                 {       
760                                         ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2, 
761                                                 2, "Unnumbered Information format - UI, N(U) = %u", nu);
762                                         ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_ctrlf);
763
764                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_U_fmt, tvb, offset-2, 
765                                                 2, ctrl_fld_ui_s);
766                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sp_bits, tvb, offset-2,
767                                                 2, ctrl_fld_ui_s);
768                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_NU, tvb, offset-2, 2, 
769                                                 ctrl_fld_ui_s);
770                                         proto_tree_add_boolean(ctrl_f_tree, hf_llcgprs_E_bit, tvb, offset-2,
771                                                 2, ctrl_fld_ui_s);
772                                         proto_tree_add_boolean(ctrl_f_tree, hf_llcgprs_PM_bit, tvb, offset-2,
773                                                 2, ctrl_fld_ui_s);
774                         }
775
776                                 /* MLT CHANGES - TOM parsing added */
777                                 next_tvb = tvb_new_subset(tvb, offset, (crc_start-offset), -1);
778
779                                 if ((ignore_cipher_bit && (fcs_status == FCS_VALID)) || !(epm & 0x2))
780                                 {
781                                         /* Either we're ignoring the cipher bit
782                                         * (because the bit is set but the
783                                         * data is unciphered), and the data has
784                                         * a valid FCS, or the cipher 
785                                         * bit isn't set (indicating that the
786                                         * data is unciphered).  Try dissecting
787                                         * it with a subdissector. */
788
789                                         /* if SAPI is TOM do other parsing */
790                                         if ((sapi == SAPI_TOM2) || (sapi == SAPI_TOM8))
791                                         {
792                                                 if (tree)
793                                                 {
794                                                         guint8 tom_byte = 0;
795                                                         guint8 remaining_length = 0;
796                                                         guint8 tom_pd = 0;
797                                                         int loop_counter = 0;
798
799                                                         tom_byte = tvb_get_guint8(tvb, offset);
800                                                         remaining_length = (tom_byte >> 4) & 0x0F;
801                                                         tom_pd = tom_byte & 0x0F;
802
803                                                         ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
804                                                                 (crc_start-offset), "TOM Envelope - Protocol: %s", 
805                                                                 match_strval(tom_pd, tompd_formats));
806
807                                                         ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
808
809                                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_rl, tvb, offset, 1, tom_byte);
810                                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_pd, tvb, offset, 1, tom_byte);
811
812                                                         /* step past the TOM header first byte */
813                                                         offset++;
814
815                                                         /* TOM remaining length field value 0x0F is reserved for extension */
816                                                         if (remaining_length != 0x0F)
817                                                         {
818                                                                 /* parse the rest of the TOM header */
819                                                                 for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
820                                                                 {
821                                                                         tom_byte = tvb_get_guint8(tvb, offset);
822
823                                                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_header, tvb, 
824                                                                                 offset, 1, tom_byte);
825
826                                                                         /* step to the next byte */
827                                                                         offset++;
828                                                                 }
829
830                                                                 /* Amount of frame left from offset to crc */
831                                                                 remaining_length = crc_start - offset;
832
833                                                                 /* parse the TOM message capsule */
834                                                                 for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
835                                                                 {
836                                                                         tom_byte = tvb_get_guint8(tvb, offset);
837
838                                                                         proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_data, tvb, 
839                                                                                 offset, 1, tom_byte);
840
841                                                                         /* step to the next byte */
842                                                                         offset++;
843                                                                 }
844                                                         }
845                                                 }
846                                         }
847                                         else
848                                         {
849                                                 /* otherwise - call a subdissector */
850                                                 if (!dissector_try_port(llcgprs_subdissector_table, sapi, next_tvb, pinfo, tree))
851                                                 {
852                                                         call_dissector(data_handle, next_tvb, pinfo, tree);
853                                                 }
854                                         }
855                                 }
856                                 else
857                                 {
858                                         /* ciphered information - just parse it as data */
859                                         call_dissector(data_handle, next_tvb, pinfo, tree);
860                                 }
861
862                                 /* END MLT CHANGES */
863                         }
864                         break;
865                 case U_FORMAT:
866                      offset +=1;
867                      tmp = 0;
868                      tmp =  ctrl_fld_fb & 0xf;
869
870                         if (check_col(pinfo->cinfo, COL_INFO)) 
871                         {
872                                 col_append_str(pinfo->cinfo, COL_INFO, ", U, ");
873                                 col_append_str(pinfo->cinfo, COL_INFO, 
874                                         val_to_str(tmp, cr_formats_unnumb,"Unknown/invalid code:%X"));
875                         }
876
877                         if(tree){
878                                 ui_ti = proto_tree_add_text(llcgprs_tree, tvb, (offset-1), (crc_start-1),
879                                         "Unnumbered frame: %s", 
880                                         val_to_str(tmp,cr_formats_unnumb, "Unknown/invalid code:%X"));
881
882                                 ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
883                                 proto_tree_add_uint(ui_tree, hf_llcgprs_Un, tvb, (offset-1), 1, ctrl_fld_fb);
884                                 proto_tree_add_boolean(ui_tree, hf_llcgprs_PF, tvb, (offset-1), 1, ctrl_fld_fb);
885                                 proto_tree_add_uint(ui_tree, hf_llcgprs_ucom, tvb, (offset-1), 1, ctrl_fld_fb);
886
887                         }
888
889                         /* MLT CHANGES - parse rest of the message based on type (M Bits) */
890                         m_bits = ctrl_fld_fb & 0x0F;
891
892                         info_len = crc_start - offset;
893
894                         switch (m_bits)
895                         {
896                         case U_DM:
897                         case U_DISC:
898                         case U_NULL:
899                                 /* These frames SHOULD NOT have an info field */
900                                 if (tree)
901                                 {
902                                         ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
903                                                 "No Information Field");
904                                         ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
905                                 }
906                                 break;
907                         case U_UA:
908                                 /* This frame MAY or MAY NOT have an info field */
909                                 /* Info field, if it exists, consists of XID parameters */
910                                 if (tree)
911                                 {
912                                         if (info_len > 0)
913                                         {
914                                                 guint8 xid_param_len = 0;
915                                                 guint16 location = offset;
916                                                 guint8 byte1 = 0;
917                                                 guint8 byte2 = 0;
918                                                 guint8 ending = 0;
919                                                 int loop_counter = 0;
920
921                                                 ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
922                                                         "Information Field: Length = %u", info_len);
923                                                 ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
924
925                                                 while (location < (offset + info_len))
926                                                 {
927                                                         /* parse the XID parameters */
928                                                         byte1 = tvb_get_guint8(tvb, location);
929                                                         
930                                                         if (byte1 & 0x80) 
931                                                         {
932                                                                 guint8 xid_param_len_high = 0;
933                                                                 guint8 xid_param_len_low = 0;
934
935                                                                 byte2 = tvb_get_guint8(tvb, location + 1);
936
937                                                                 /* XL bit is set - length is continued in second byte */
938                                                                 xid_param_len_high = byte1 & 0x03;
939                                                                 xid_param_len_low = byte2 & 0xFC;
940
941                                                                 /* bit shift the rest of the length */
942                                                                 xid_param_len_low = xid_param_len_low >> 2;
943                                                                 xid_param_len_low = xid_param_len_low & 0x3F;
944
945                                                                 xid_param_len_high = xid_param_len_high << 6;
946                                                                 xid_param_len_high = xid_param_len_high & 0xC0;
947
948                                                                 /* combine the two */
949                                                                 xid_param_len = xid_param_len_high | xid_param_len_low;
950
951                                                         }
952                                                         else
953                                                         {
954                                                                 xid_param_len = byte1 & 0x3;
955                                                         }
956
957                                                         ending = location + xid_param_len;
958
959                                                         tmp =  byte1 & 0x7C;
960                                                         tmp = tmp >> 2;
961                                                         uinfo_field = proto_tree_add_text(ui_tree, tvb, location, 
962                                                                 (ending - 1), "XID Parameter Type: %s", 
963                                                                 val_to_str(tmp, xid_param_type_str,"Reserved Type:%X"));
964
965                                                         uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
966                                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_xl, tvb, 
967                                                                 location, 1, byte1);
968                                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_type, tvb, 
969                                                                 location, 1, byte1);
970                                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len1, tvb, 
971                                                                 location, 1, byte1);
972
973                                                         if (byte1 & 0x80) {
974                                                                 /* length continued into byte 2 */
975                                                                 proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len2, tvb, 
976                                                                         location, 1, byte2);
977                                                                 proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_spare, tvb, 
978                                                                         location, 1, byte2);
979
980                                                                 /* be sure to account for the second byte of length */
981                                                                 location++;
982                                                         }
983
984                                                         location++;
985                                                         for (loop_counter = 0; loop_counter < xid_param_len; loop_counter++)
986                                                         {
987                                                                 /* grab the information in the XID param */
988                                                                 byte2 = tvb_get_guint8(tvb, location);
989                                                                 proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_byte, tvb, 
990                                                                         location, 1, byte2);
991
992                                                                 location++;
993                                                         }
994                                                 }
995                                         }
996                                         else
997                                         {
998                                                 ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
999                                                         "No Information Field");
1000                                                 ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
1001                                         }
1002                                 }
1003                                 break;
1004                         case U_SABM:
1005                         case U_XID:
1006                                 /* These frames do have info fields consisting of XID parameters */
1007                                 /* Info field consists of XID parameters */
1008                                 if (tree)
1009                                 {
1010                                         guint8 xid_param_len = 0;
1011                                         guint16 location = offset;
1012                                         guint8 byte1 = 0;
1013                                         guint8 byte2 = 0;
1014                                         guint8 ending = 0;
1015                                         int loop_counter = 0;
1016
1017                                         ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
1018                                                 "Information Field: Length = %u", info_len);
1019                                         ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
1020
1021                                         while (location < (offset + info_len))
1022                                         {
1023                                                 /* parse the XID parameters */
1024                                                 byte1 = tvb_get_guint8(tvb, location);
1025                                                 
1026                                                 if (byte1 & 0x80) 
1027                                                 {
1028                                                         guint8 xid_param_len_high = 0;
1029                                                         guint8 xid_param_len_low = 0;
1030
1031                                                         byte2 = tvb_get_guint8(tvb, location + 1);
1032
1033                                                         /* XL bit is set - length is continued in second byte */
1034                                                         xid_param_len_high = byte1 & 0x03;
1035                                                         xid_param_len_low = byte2 & 0xFC;
1036
1037                                                         /* bit shift the rest of the length */
1038                                                         xid_param_len_low = xid_param_len_low >> 2;
1039                                                         xid_param_len_low = xid_param_len_low & 0x3F;
1040
1041                                                         xid_param_len_high = xid_param_len_high << 6;
1042                                                         xid_param_len_high = xid_param_len_high & 0xC0;
1043
1044                                                         /* combine the two */
1045                                                         xid_param_len = xid_param_len_high | xid_param_len_low;
1046
1047                                                 }
1048                                                 else
1049                                                 {
1050                                                         xid_param_len = byte1 & 0x3;
1051                                                 }
1052
1053                                                 ending = location + xid_param_len;
1054
1055                                                 tmp =  byte1 & 0x7C;
1056                                                 tmp = tmp >> 2;
1057
1058                                                 if (( xid_param_len > 0 ) && ( xid_param_len <=4 ))
1059                                                 {
1060                                                         unsigned long value = 0;
1061                                                         int i;
1062                                                         for (i=1;i<=xid_param_len;i++) {
1063                                                                 value <<= 8;
1064                                                                 value |= (unsigned long)tvb_get_guint8(tvb, location+i );
1065                                                         }
1066                                                         uinfo_field = proto_tree_add_text(ui_tree, tvb, location, (ending - 1), 
1067                                                                 "XID Parameter Type: %s - Value: %lu", 
1068                                                                 val_to_str(tmp, xid_param_type_str,"Reserved Type:%X"),value);
1069                                                 }
1070                                                 else
1071                                                         uinfo_field = proto_tree_add_text(ui_tree, tvb, location, (ending - 1), 
1072                                                                 "XID Parameter Type: %s", 
1073                                                                 val_to_str(tmp, xid_param_type_str,"Reserved Type:%X"));
1074
1075                                                 uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
1076                                                 proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_xl, tvb, location, 
1077                                                         1, byte1);
1078                                                 proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_type, tvb, location, 
1079                                                         1, byte1);
1080                                                 proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len1, tvb, location, 
1081                                                         1, byte1);
1082
1083                                                 if (byte1 & 0x80) {
1084                                                         /* length continued into byte 2 */
1085                                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len2, tvb, location, 
1086                                                                 1, byte2);
1087                                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_spare, tvb, location, 
1088                                                                 1, byte2);
1089
1090                                                         /* be sure to account for the second byte of length */
1091                                                         location++;
1092                                                 }
1093
1094                                                 location++;
1095                                                 for (loop_counter = 0; loop_counter < xid_param_len; loop_counter++)
1096                                                 {
1097                                                         /* grab the information in the XID param */
1098                                                         byte2 = tvb_get_guint8(tvb, location);
1099                                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_byte, tvb, location, 
1100                                                                 1, byte2);
1101
1102                                                         location++;
1103                                                 }
1104                                         }
1105                                 }
1106                                 break;
1107                         case U_FRMR:
1108                                 /* This frame has a special format info field */
1109                                 if (tree)
1110                                 {
1111                                         guint32 fld_vars = 0;
1112                                         guint16 cf_byte = 0;
1113                                         int loop_counter = 0;
1114                                         int location = 0;
1115
1116                                         ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
1117                                                 "Information Field: Length = %u", info_len);
1118                                         ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
1119
1120                                         uinfo_field = proto_tree_add_text(ui_tree, tvb, offset, 6, 
1121                                                 "Rejected Frame Control Field");
1122                                         uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
1123
1124                                         location = offset;
1125                                         for (loop_counter = 0; loop_counter < 3; loop_counter++)
1126                                         {
1127                                                 /* display the rejected frame control field */
1128                                                 cf_byte = tvb_get_ntohs(tvb, location);
1129                                                 proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_cf, tvb, location, 
1130                                                         2, cf_byte);
1131
1132                                                 location += 2;
1133                                         }
1134
1135                                         uinfo_field = proto_tree_add_text(ui_tree, tvb, location, 4, 
1136                                                 "Information Field Data");
1137                                         uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
1138
1139                                         fld_vars = tvb_get_ntohl(tvb, location);
1140                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_spare, tvb, location, 
1141                                                 4, fld_vars);
1142                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_vs, tvb, location, 
1143                                                 2, fld_vars);
1144                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_vr, tvb, (location + 1), 
1145                                                 2, fld_vars);
1146                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_cr, tvb, (location + 2), 
1147                                                 1, fld_vars);
1148                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w4, tvb, (location + 3), 
1149                                                 1, fld_vars);
1150                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w3, tvb, (location + 3), 
1151                                                 1, fld_vars);
1152                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w2, tvb, (location + 3), 
1153                                                 1, fld_vars);
1154                                         proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w1, tvb, (location + 3), 
1155                                                 1, fld_vars);
1156                                 }
1157                                 break;
1158                         default:
1159                                 break;
1160                         }
1161                         /* END MLT CHANGES */
1162                         break;
1163                 }               
1164 }
1165
1166
1167 /* Register the protocol with Wireshark */
1168 /* this format is require because a script is used to build the C function */
1169 /* that calls all the protocol registration. */
1170
1171 void
1172 proto_register_llcgprs(void)
1173 {                 
1174 /* Setup list of header fields  See Section 1.6.1 for details*/
1175         static hf_register_info hf[] = {
1176                 { &hf_llcgprs_sapi,
1177                         { "SAPI", "llcgprs.sapi", FT_UINT8, BASE_DEC, VALS(sapi_abrv), 0x0,"Service Access Point Identifier", HFILL }},
1178                 { &hf_llcgprs_pd, 
1179                         { "Protocol Discriminator_bit", "llcgprs.pd", FT_BOOLEAN,8, TFS(&pd_bit), 0x80, " Protocol Discriminator bit (should be 0)", HFILL }},
1180                 {&hf_llcgprs_sjsd,
1181                         { "Supervisory function bits","llcgprs.s1s2", FT_UINT16, BASE_HEX, VALS(cr_formats_ipluss),0x3, "Supervisory functions bits",HFILL }},
1182                 { &hf_llcgprs_cr, 
1183                         { "Command/Response bit", "llcgprs.cr", FT_BOOLEAN, 8, TFS(&cr_bit), 0x40, " Command/Response bit", HFILL}},
1184                 { &hf_llcgprs_sapib,
1185                         { "SAPI", "llcgprs.sapib", FT_UINT8, BASE_DEC , VALS(sapi_t), 0xf, "Service Access Point Identifier ",HFILL }}, 
1186                 { &hf_llcgprs_U_fmt,
1187                         { "UI format", "llcgprs.ui", FT_UINT16, BASE_HEX, NULL, UI_MASK_FMT, "UI frame format",HFILL}},
1188                 { &hf_llcgprs_Un,
1189                         { "U format", "llcgprs.u", FT_UINT8, BASE_DEC, NULL, 0xe0, " U frame format", HFILL}},
1190                 { &hf_llcgprs_sp_bits,
1191                         { "Spare bits", "llcgprs.ui_sp_bit", FT_UINT16, BASE_HEX, NULL, UI_MASK_SPB, "Spare bits", HFILL}},
1192                 { &hf_llcgprs_NU,
1193                         { "N(U)", "llcgprs.nu", FT_UINT16, BASE_DEC, NULL, UI_MASK_NU, "Transmited unconfirmed sequence number", HFILL}},
1194                 { &hf_llcgprs_E_bit,
1195                         { "E bit", "llcgprs.e", FT_BOOLEAN, 16, TFS(&e_bit), UI_MASK_E,"Encryption mode bit",HFILL }},
1196                 { &hf_llcgprs_PM_bit,
1197                         { "PM bit", "llcgprs.pm", FT_BOOLEAN, 16, TFS(&pm_bit), UI_MASK_PM, "Protected mode bit",HFILL}},
1198                 { &hf_llcgprs_As,
1199                         { "Ackn request bit", "llcgprs.as", FT_BOOLEAN, 16, TFS(&a_bit), 0x2000 ,"Acknowledgement request bit A", HFILL}},
1200                 { &hf_llcgprs_PF,
1201                         { "P/F bit", "llcgprs.pf", FT_BOOLEAN, 8, NULL, 0x10,"Poll /Finall bit", HFILL}},
1202                 { &hf_llcgprs_ucom,
1203                         { "Command/Response","llcgprs.ucom", FT_UINT8, BASE_HEX, VALS(cr_formats_unnumb),0xf,"Commands and Responses",HFILL }}, 
1204                 { &hf_llcgprs_NR,
1205                         { "Receive sequence number", "llcgprs.nr",FT_UINT16, BASE_DEC, NULL, UI_MASK_NU,"Receive sequence number N(R)",HFILL }},
1206                 {&hf_llcgprs_S_fmt,
1207                         { "S format", "llcgprs.s", FT_UINT16, BASE_DEC, NULL, 0xc000,"Supervisory format S", HFILL}},
1208                 /* MLT CHANGES - additional masks*/
1209                 {&hf_llcgprs_kmask,
1210                         { "ignored", "llcgprs.kmask", FT_UINT8, BASE_DEC, NULL, 0xE0, "ignored", HFILL}},
1211                 {&hf_llcgprs_k,
1212                         { "k", "llcgprs.k", FT_UINT8, BASE_DEC, NULL, 0x1F, "k counter", HFILL}},
1213                 {&hf_llcgprs_isack_ns,
1214                         { "N(S)", "llcgprs.sackns", FT_UINT24, BASE_DEC, NULL, 0x1FF000, "N(S)", HFILL}},
1215                 {&hf_llcgprs_isack_nr,
1216                         { "N(R)", "llcgprs.sacknr", FT_UINT24, BASE_DEC, NULL, 0x0007FC, "N(R)", HFILL}},
1217                 {&hf_llcgprs_isack_sfb,
1218                         { "Supervisory function bits","llcgprs.sacksfb", FT_UINT24, BASE_HEX, VALS(cr_formats_ipluss),0x000003, "Supervisory functions bits",HFILL }},
1219                 {&hf_llcgprs_ifmt,
1220                         { "I Format", "llcgprs.ifmt", FT_UINT24, BASE_DEC, NULL, 0x800000, "I Fmt Bit", HFILL}},
1221                 {&hf_llcgprs_ia,
1222                         { "Ack Bit", "llcgprs.ia", FT_UINT24, BASE_DEC, NULL, 0x400000, "I A Bit", HFILL}},
1223                 {&hf_llcgprs_izerobit,
1224                         { "Spare", "llcgprs.iignore", FT_UINT24, BASE_DEC, NULL, 0x200000, "Ignore Bit", HFILL}},
1225                 {&hf_llcgprs_sspare,
1226                         { "Spare", "llcgprs.sspare", FT_UINT16, BASE_DEC, NULL, 0x1800, "Ignore Bit", HFILL}},
1227                 {&hf_llcgprs_rbyte,
1228                                 { "R Bitmap Bits","llcgprs.sackrbits", FT_UINT8, BASE_HEX, NULL, 0xFF, "R Bitmap", HFILL}},
1229                 /* XID Parameter Parsing Info */
1230                 {&hf_llcgprs_xid_xl,
1231                                 { "XL Bit","llcgprs.xidxl", FT_UINT8, BASE_HEX, NULL, 0x80, "XL", HFILL}},
1232                 {&hf_llcgprs_xid_type,
1233                                 { "Type","llcgprs.xidtype", FT_UINT8, BASE_DEC, NULL, 0x7C, "Type", HFILL}},
1234                 {&hf_llcgprs_xid_len1,
1235                                 { "Length","llcgprs.xidlen1", FT_UINT8, BASE_DEC, NULL, 0x03, "Len", HFILL}},
1236                 {&hf_llcgprs_xid_len2,
1237                                 { "Length continued","llcgprs.xidlen2", FT_UINT8, BASE_DEC, NULL, 0xFC, "Len", HFILL}},
1238                 {&hf_llcgprs_xid_spare,
1239                                 { "Spare","llcgprs.xidspare", FT_UINT8, BASE_HEX, NULL, 0x03, "Ignore", HFILL}},
1240                 {&hf_llcgprs_xid_byte,
1241                                 { "Parameter Byte","llcgprs.xidbyte", FT_UINT8, BASE_HEX, NULL, 0xFF, "Data", HFILL}},
1242                 /* FRMR Parsing Information */
1243                 {&hf_llcgprs_frmr_cf,
1244                                 { "Control Field Octet","llcgprs.frmrrfcf", FT_UINT16, BASE_DEC, NULL, 
1245                                         0xFFFF, "Rejected Frame CF", HFILL}},
1246                 {&hf_llcgprs_frmr_spare,
1247                                 { "X","llcgprs.frmrspare", FT_UINT32, BASE_HEX, NULL, 0xF00400F0, 
1248                                         "Filler", HFILL}},
1249                 {&hf_llcgprs_frmr_vs,
1250                                 { "V(S)","llcgprs.frmrvs", FT_UINT32, BASE_DEC, NULL, 0x0FF80000, 
1251                                         "Current send state variable", HFILL}},
1252                 {&hf_llcgprs_frmr_vr,
1253                                 { "V(R)","llcgprs.frmrvr", FT_UINT32, BASE_DEC, NULL, 0x0003FE00, 
1254                                         "Current receive state variable", HFILL}},
1255                 {&hf_llcgprs_frmr_cr,
1256                                 { "C/R","llcgprs.frmrcr", FT_UINT32, BASE_DEC, NULL, 0x00000100, 
1257                                         "Rejected command response", HFILL}},
1258                 {&hf_llcgprs_frmr_w4,
1259                                 { "W4","llcgprs.frmrw4", FT_UINT32, BASE_DEC, NULL, 0x00000008, 
1260                                         "LLE was in ABM when rejecting", HFILL}},
1261                 {&hf_llcgprs_frmr_w3,
1262                                 { "W3","llcgprs.frmrw3", FT_UINT32, BASE_DEC, NULL, 0x00000004, 
1263                                         "Undefined control field", HFILL}},
1264                 {&hf_llcgprs_frmr_w2,
1265                                 { "W2","llcgprs.frmrw2", FT_UINT32, BASE_DEC, NULL, 0x00000002, 
1266                                         "Info exceeded N201", HFILL}},
1267                 {&hf_llcgprs_frmr_w1,
1268                                 { "W1","llcgprs.frmrw1", FT_UINT32, BASE_DEC, NULL, 0x00000001, 
1269                                         "Invalid - info not permitted", HFILL}},
1270                 {&hf_llcgprs_tom_rl,
1271                                 { "Remaining Length of TOM Protocol Header","llcgprs.romrl", FT_UINT8,
1272                                         BASE_DEC, NULL, 0xF0, "RL", HFILL}},
1273                 {&hf_llcgprs_tom_pd,
1274                                 { "TOM Protocol Discriminator","llcgprs.tompd", FT_UINT8, BASE_HEX, 
1275                                         NULL, 0x0F, "TPD", HFILL}},
1276                 {&hf_llcgprs_tom_header,
1277                                 { "TOM Header Byte","llcgprs.tomhead", FT_UINT8, BASE_HEX, NULL, 0xFF, 
1278                                         "thb", HFILL}},
1279                 {&hf_llcgprs_tom_data,
1280                                 { "TOM Message Capsule Byte","llcgprs.tomdata", FT_UINT8, BASE_HEX, NULL, 
1281                                         0xFF, "tdb", HFILL}},
1282                 /* END MLT CHANGES */
1283         };
1284
1285 /* Setup protocol subtree array */
1286         static gint *ett[] = {
1287                 &ett_llcgprs,
1288                 &ett_llcgprs_adf,
1289                 &ett_llcgprs_ctrlf,
1290                 &ett_ui,
1291                 &ett_llcgprs_sframe,
1292         };
1293
1294         module_t *llcgprs_module;
1295         
1296 /* Register the protocol name and description */
1297         proto_llcgprs = proto_register_protocol("Logical Link Control GPRS",
1298             "GPRS-LLC", "llcgprs");
1299         llcgprs_subdissector_table = register_dissector_table("llcgprs.sapi","GPRS LLC SAPI", FT_UINT8,BASE_HEX);
1300 /* Required function calls to register the header fields and subtrees used */
1301         proto_register_field_array(proto_llcgprs, hf, array_length(hf));
1302         proto_register_subtree_array(ett, array_length(ett));
1303         register_dissector("llcgprs", dissect_llcgprs, proto_llcgprs);
1304         
1305         llcgprs_module = prefs_register_protocol ( proto_llcgprs, NULL );
1306         prefs_register_bool_preference ( llcgprs_module, "autodetect_cipher_bit",
1307             "Autodetect cipher bit", 
1308             "Whether to autodetect the cipher bit (because it might be set on unciphered data)",
1309             &ignore_cipher_bit );
1310 }
1311
1312
1313 /* If this dissector uses sub-dissector registration add a registration routine. */
1314 /* This format is required because a script is used to find these routines and */
1315 /* create the code that calls these routines. */
1316 void
1317 proto_reg_handoff_llcgprs(void)
1318 {
1319         dissector_handle_t gprs_llc_handle;
1320
1321         /* make sure that the top level can call this dissector */
1322         gprs_llc_handle = create_dissector_handle(dissect_llcgprs, proto_llcgprs);
1323         dissector_add("wtap_encap", WTAP_ENCAP_GPRS_LLC, gprs_llc_handle);
1324
1325         data_handle = find_dissector("data");
1326 }