From THORNTON, MATT
authoretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 5 Aug 2005 19:16:29 +0000 (19:16 +0000)
committeretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 5 Aug 2005 19:16:29 +0000 (19:16 +0000)
Some changes that I made to flesh out GPRS message parsing.  More information is displayed about the various frame formats.  I have also added some code to parse XID parameters in the U frame.  I have also fixed a couple of display bugs in the GSM and GPRS LLC parser.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@15224 f5534014-38df-0310-8fa8-9805f1628bb7

AUTHORS
epan/dissectors/packet-gprs-llc.c
epan/dissectors/packet-gsm_a.c

diff --git a/AUTHORS b/AUTHORS
index c11f31b9190438b206deaa40d72d73e70d9a0823..00abea7b005950595cbc4ba37ddf3e4fc4d4406d 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -2481,6 +2481,7 @@ Dominik Kuhlen            <dkuhlen [AT] gmx.net>
 Karl Knoebl            <karl.knoebl [AT] siemens.com>
 Maria-Luiza Crivat     <luizacri [AT] gmail.com>
 Brice Augustin         <bricecotte [AT] gmail.com>
+Matt Thornton          <MATT_THORNTON [AT] appsig.com>
 
 
 Alain Magloire <alainm[AT]rcsm.ece.mcgill.ca> was kind enough to
index 00857e2c91fd89d300298a4db5e63330bca040a9..ed21f1a0cf12ef01d0014a8715907e69def58c30 100644 (file)
@@ -39,9 +39,7 @@
 
 #include <epan/packet.h>
 #include "prefs.h"
-/*
-#include "packet-llcgprs.h"
-*/
+
 #define I_FORMAT       1
 #define S_FORMAT       2
 #define UI_FORMAT      3
@@ -72,8 +70,58 @@ static int hf_llcgprs_PF     = -1;
 static int hf_llcgprs_S_fmt    = -1;
 static int hf_llcgprs_NR       = -1;
 static int hf_llcgprs_sjsd     = -1;
-/*static int hf_llcgprs_pd       = -1;
-*/
+/* MLT CHANGES - Additional display masks */
+static int hf_llcgprs_k = -1;
+static int hf_llcgprs_isack_ns = -1;
+static int hf_llcgprs_isack_nr = -1;
+static int hf_llcgprs_isack_sfb = -1;
+static int hf_llcgprs_rbyte = -1;
+static int hf_llcgprs_kmask = -1;
+static int hf_llcgprs_ifmt = -1;
+static int hf_llcgprs_ia = -1;
+static int hf_llcgprs_izerobit = -1;
+static int hf_llcgprs_sspare = -1;
+static int hf_llcgprs_xid_xl = -1;
+static int hf_llcgprs_xid_type = -1;
+static int hf_llcgprs_xid_len1 = -1;
+static int hf_llcgprs_xid_len2 = -1;
+static int hf_llcgprs_xid_spare = -1;
+static int hf_llcgprs_xid_byte = -1;
+static int hf_llcgprs_frmr_cf = -1;
+static int hf_llcgprs_frmr_spare = -1;
+static int hf_llcgprs_frmr_vs = -1;
+static int hf_llcgprs_frmr_vr = -1;
+static int hf_llcgprs_frmr_cr = -1;
+static int hf_llcgprs_frmr_w4 = -1;
+static int hf_llcgprs_frmr_w3 = -1;
+static int hf_llcgprs_frmr_w2 = -1;
+static int hf_llcgprs_frmr_w1 = -1;
+static int hf_llcgprs_tom_rl = -1;
+static int hf_llcgprs_tom_pd = -1;
+static int hf_llcgprs_tom_header = -1;
+static int hf_llcgprs_tom_data = -1;
+
+/* Unnumbered Commands and Responses (U Frames) */
+#define U_DM   0x01
+#define U_DISC 0x04
+#define U_UA   0x06
+#define U_SABM 0x07
+#define U_FRMR 0x08
+#define U_XID  0x0B
+#define U_NULL 0x00
+
+/* SAPI value constants */
+#define SAPI_LLGMM     0x01
+#define SAPI_TOM2      0x02
+#define SAPI_LL3       0x03
+#define SAPI_LL5       0x05
+#define SAPI_LLSMS     0x07
+#define SAPI_TOM8      0x08
+#define SAPI_LL9       0x09
+#define SAPI_LL11      0x0B
+
+/* END MLT CHANGES */
+
 /* Initialize the subtree pointers */
 static gint ett_llcgprs = -1;
 static gint ett_llcgprs_adf = -1;
@@ -107,23 +155,22 @@ static const value_string sapi_t[] = {
 };
 
 static const value_string sapi_abrv[] = {
-       {  0, "0"},
+       {  0, "Reserved 0"},
        {  1, "LLGMM" },
        {  2, "TOM2" },
        {  3, "LL3"},
-       {  4, "4" },
+       {  4, "Reserved 4" },
        {  5, "LL5" },
-       {  6, "6" },
+       {  6, "Reserved 6" },
        {  7, "LLSMS" },
        {  8, "TOM8" },
        {  9, "LL9" },
-       { 10, "10" },
+       { 10, "Reserved 10" },
        { 11, "LL11" },
-       { 12, "12" },
-       { 13, "13" },
-       { 14, "14" },
-       { 15, "15" },
-       {  0, NULL },
+       { 12, "Reserved 12" },
+       { 13, "Reserved 13" },
+       { 14, "Reserved 14" },
+       { 15, "Reserved 15" },
 };
 static const true_false_string a_bit = {
        "To solicit an acknowledgement from the peer LLE. ",
@@ -155,6 +202,43 @@ static const value_string pme[] = {
        { 0, NULL},
 };
 
+/* MLT CHANGES - adding XID parameter types & TOM protocols */
+static const value_string xid_param_type_str[] = {
+       {0x0, "Version (LLC version number)"},
+       {0x1, "IOV-UI (ciphering Input offset value for UI frames)"},
+       {0x2, "IOV-I (ciphering Input offset value for I frames)"},
+       {0x3, "T200 (retransmission timeout)"},
+       {0x4, "N200 (max number of retransmissions)"},
+       {0x5, "N201-U (max info field length for U and UI frames)"},
+       {0x6, "N201-I (max info field length for I frames)"},
+       {0x7, "mD (I frame buffer size in the DL direction)"},
+       {0x8, "mU (I frame buffer size in the UL direction)"},
+       {0x9, "kD (window size in the DL direction)"},
+       {0xA, "kU (window size in the UL direction)"},
+       {0xB, "Layer-3 Parameters"},
+       {0xC, "Reset"},
+};
+
+static const value_string tompd_formats[] = {
+       {0x0, "Not specified"},
+       {0x1, "TIA/EIA-136"},
+       {0x2, "Reserved value 2"},
+       {0x3, "Reserved value 3"},
+       {0x4, "Reserved value 4"},
+       {0x5, "Reserved value 5"},
+       {0x6, "Reserved value 6"},
+       {0x7, "Reserved value 7"},
+       {0x8, "Reserved value 8"},
+       {0x9, "Reserved value 9"},
+       {0xA, "Reserved value 10"},
+       {0xB, "Reserved value 11"},
+       {0xC, "Reserved value 12"},
+       {0xD, "Reserved value 13"},
+       {0xE, "Reserved value 14"},
+       {0xF, "Reserved for extension"},
+};
+/* END MLT CHANGES */
+
 static const value_string cr_formats_unnumb[]= {
        {  0x1, "DM-response" },
        {  0x4, "DISC-command" },
@@ -239,98 +323,287 @@ dissect_llcgprs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        guint32 fcs, fcs_calc;
        fcs_status_t fcs_status;
 
+       /* MLT CHANGES - additional variables */
+       guint16 ns = 0;
+       guint16 nr = 0;
+       guint8 k = 0;
+       guint8 m_bits = 0;
+       guint8 info_len = 0;
+       proto_item *uinfo_field = NULL;
+       proto_tree *uinfo_tree = NULL;
+       /* END MLT CHANGES */
+
        if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
+       {
                col_set_str(pinfo->cinfo, COL_PROTOCOL, "GPRS-LLC");
+       }
        
-        addr_fld = tvb_get_guint8(tvb,offset);
+    addr_fld = tvb_get_guint8(tvb,offset);
        offset++;
-       if (addr_fld > 128 ) {
+       
+       if (addr_fld > 128 ) 
+       {
                if (check_col(pinfo->cinfo,COL_INFO))
+               {
                       col_add_str(pinfo->cinfo,COL_INFO,"Invalid packet - Protocol Discriminator bit is set to 1");
+               }
                return;
        }
-       sapi = addr_fld & 0xF;
+       
+       sapi = addr_fld & 0xF;
+       
        if (check_col(pinfo->cinfo, COL_INFO)) 
+       {
                col_add_fstr(pinfo->cinfo, COL_INFO, "SAPI: %s", match_strval(sapi,sapi_abrv));
+       }
        
          
        length = tvb_reported_length(tvb);
-       if (tvb_bytes_exist(tvb, 0, length) && length >= 3) {
+       if (tvb_bytes_exist(tvb, 0, length) && length >= 3)
+       {
                /*
                 * We have all the packet data, including the full FCS,
                 * so we can compute the FCS.
                 *
                 * XXX - do we need to check the PM bit?
                 */
-               crc_start = length-3;
+           crc_start = length-3;
                fcs_calc = crc_calc ( INIT_CRC24 , tvb, crc_start );
                fcs_calc = ~fcs_calc;
                fcs_calc &= 0xffffff;
 
                fcs = tvb_get_letoh24(tvb, crc_start);
                if ( fcs_calc == fcs )
+               {
                        fcs_status = FCS_VALID;
+               }
                else
+               {
                        fcs_status = FCS_NOT_VALID;
-       } else {
-               /*
-                * We don't have enough data to compute the FCS.
-                */
+               }
+       } 
+       else
+       {
+               /* We don't have enough data to compute the FCS. */
                fcs_status = FCS_NOT_COMPUTED;
 
-               /*
-                * Squelch compiler warnings.
-                */
+               /* Squelch compiler warnings. */
                fcs = 0;
                fcs_calc = 0;
                crc_start = 0;
        }
         
-/* In the interest of speed, if "tree" is NULL, don't do any work not
-   necessary to generate protocol tree items. */
-       if (tree) {
+       /* In the interest of speed, if "tree" is NULL, don't do any work not
+               necessary to generate protocol tree items. */
+       
+       if (tree) 
+       {
 
                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));
 
                llcgprs_tree = proto_item_add_subtree(ti, ett_llcgprs);
 
-/* add an item to the subtree, see section 1.6 for more information */
-               switch ( fcs_status ) {
+               /* add an item to the subtree, see section 1.6 for more information */
+               switch (fcs_status) {
 
                case FCS_VALID:
-                       proto_tree_add_text ( llcgprs_tree , tvb , crc_start , 3 , "FCS: 0x%06x [correct]" , fcs_calc&0xffffff );
+                       proto_tree_add_text (llcgprs_tree, tvb, crc_start, 3, 
+                               "FCS: 0x%06x (correct)", fcs_calc&0xffffff);
                        break;
 
                case FCS_NOT_VALID:
-                       proto_tree_add_text ( llcgprs_tree , tvb , crc_start , 3 , "FCS: 0x%06x [incorrect, should be 0x%06x]",
-                               fcs,  fcs_calc );
+                       proto_tree_add_text (llcgprs_tree, tvb,crc_start, 3,
+                               "FCS: 0x%06x  (incorrect, should be 0x%06x)", fcs, fcs_calc );
                        break;
 
                case FCS_NOT_COMPUTED:
                        break;  /* FCS not present */
                }
+
                addres_field_item = proto_tree_add_uint_format(llcgprs_tree,hf_llcgprs_sapi,
                     tvb, 0,1, sapi, "Address field  SAPI: %s", match_strval(sapi,sapi_abrv));
+
                ad_f_tree = proto_item_add_subtree(addres_field_item, ett_llcgprs_adf);
-                proto_tree_add_boolean(ad_f_tree, hf_llcgprs_pd, tvb,0,1, addr_fld );
-                proto_tree_add_boolean(ad_f_tree, hf_llcgprs_cr, tvb,0,1, addr_fld );
-                proto_tree_add_uint(ad_f_tree, hf_llcgprs_sapib, tvb, 0, 1, addr_fld );
+        proto_tree_add_boolean(ad_f_tree, hf_llcgprs_pd, tvb, 0, 1, addr_fld );
+        proto_tree_add_boolean(ad_f_tree, hf_llcgprs_cr, tvb, 0, 1, addr_fld );
+        proto_tree_add_uint(ad_f_tree, hf_llcgprs_sapib, tvb, 0, 1, addr_fld );
        }       
 
                          
 
        ctrl_fld_fb = tvb_get_guint8(tvb,offset);
-       if ( ctrl_fld_fb < 0xc0 ){
-               frame_format = ( ctrl_fld_fb < 0x80)? I_FORMAT : S_FORMAT;
+       if (ctrl_fld_fb < 0xC0)
+       {
+               frame_format = (ctrl_fld_fb < 0x80)? I_FORMAT : S_FORMAT;
        }
-       else {
-               frame_format = ( ctrl_fld_fb < 0xe0 )? UI_FORMAT : U_FORMAT;
+       else 
+       {
+               frame_format = (ctrl_fld_fb < 0xe0 )? UI_FORMAT : U_FORMAT;
        }         
-       switch (frame_format){
+
+       switch (frame_format)
+       {
                case I_FORMAT:
-                       if (check_col(pinfo->cinfo,COL_INFO)){
-                               col_append_str(pinfo->cinfo,COL_INFO, ", I");
+                       if (check_col(pinfo->cinfo,COL_INFO))
+                       {
+                               col_append_str(pinfo->cinfo,COL_INFO, ", I, ");
+                       }
+
+                       /* MLT CHANGES - additional parsing code */
+                       ns = tvb_get_ntohs(tvb, offset);
+                       ns = (ns >> 4)& 0x01FF;
+                       nr = ctrl_fld_ui_s = tvb_get_ntohs(tvb, offset + 1);
+                       nr = (nr >> 2) & 0x01FF;
+
+                       epm = ctrl_fld_ui_s & 0x3;
+
+                       /* advance to either R Bitmap or Payload */
+                       offset += 3;
+
+                       if (check_col(pinfo->cinfo, COL_INFO))
+                       {
+                               col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm, cr_formats_ipluss));
+                               col_append_fstr(pinfo->cinfo, COL_INFO, ", N(S) = %u", ns);
+                               col_append_fstr(pinfo->cinfo, COL_INFO, ", N(R) = %u", nr);
+                       }
+
+                       if (tree)
+                       {
+                               guint32 tmp;
+
+                               ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, (offset-3), 
+                                       3,"Information format: %s: N(S) = %u,  N(R) = %u", 
+                                       match_strval(epm, cr_formats_ipluss), ns, nr);
+                               ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
+
+                               /* retrieve the second octet */
+                               tmp = tvb_get_ntohs(tvb, (offset-3))  << 16;
+                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_ifmt, tvb, offset-3, 3, tmp);
+                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_ia, tvb, offset-3, 3, tmp);
+                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_izerobit, tvb, offset-3, 3, tmp);
+
+                               tmp = ns << 12;
+                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_isack_ns, tvb, offset-3, 3, tmp);
+
+                               tmp = nr << 2;
+                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_isack_nr, tvb, offset-3, 3, tmp);
+                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_isack_sfb, tvb, offset-3, 3, ctrl_fld_ui_s);
                        }
+                       
+                       /* check to see if epm is SACK - meaning this is an ISACK frame */
+                       if (epm == 0x03)
+                       {
+                               guint8 kmask;
+                               /* SACK Frame */
+                               k = kmask = tvb_get_guint8(tvb, offset);
+                               k = k & 0x1F;
+
+                               /* advance past the k field */
+                               offset++;
+
+                               /* the real value of k is actually k + 1 */
+                               /* account for the off by one representation */
+                               k++;
+
+                               if (check_col(pinfo->cinfo, COL_INFO))
+                               {
+                                       col_append_fstr(pinfo->cinfo, COL_INFO, ", k = %u", k);
+                               }
+
+                               if (tree)
+                               {
+                                       guint8 loop_count = 0;
+                                       guint8 r_byte = 0;
+                                       guint16 location = offset;
+
+                                       ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, (offset-1), 
+                                               (k+1), "SACK FRAME: k = %u", k);
+
+                                       ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_kmask, tvb, offset-1, 1, kmask);
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_k, tvb, offset-1, 1, k);
+
+                                       /* display the R Bitmap */
+                                       for (loop_count = 0; loop_count < k; loop_count++)
+                                       {
+                                               r_byte = tvb_get_guint8(tvb, location);
+                                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_rbyte, tvb, location, 1, r_byte);
+                                               location++;
+                                       }
+                               }
+
+                               /* step past the R Bitmap */
+                               offset += k;
+                       }
+       
+                       if ((sapi == SAPI_TOM2) || (sapi == SAPI_TOM8))
+                       {
+                               /* if SAPI is TOM do other parsing */   
+                               if (tree)
+                               {
+                                       guint8 tom_byte = 0;
+                                       guint8 remaining_length = 0;
+                                       guint8 tom_pd = 0;
+                                       int loop_counter = 0;
+
+                                       tom_byte = tvb_get_guint8(tvb, offset);
+                                       remaining_length = (tom_byte >> 4) & 0x0F;
+                                       tom_pd = tom_byte & 0x0F;
+
+                                       ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
+                                               (crc_start-offset), "TOM Envelope - Protocol: %s", 
+                                               match_strval(tom_pd, tompd_formats));
+
+                                       ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
+
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_rl, tvb, offset, 1, tom_byte);
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_pd, tvb, offset, 1, tom_byte);
+
+                                       /* step past the TOM header first byte */
+                                       offset++;
+
+                                       /* TOM remaining length field value 0x0F is reserved for extension */
+                                       if (remaining_length != 0x0F)
+                                       {
+                                               /* parse the rest of the TOM header */
+                                               for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
+                                               {
+                                                       tom_byte = tvb_get_guint8(tvb, offset);
+
+                                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_header, tvb, 
+                                                               offset, 1, tom_byte);
+
+                                                       /* step to the next byte */
+                                                       offset++;
+                                               }
+
+                                               remaining_length = crc_start - offset;
+
+                                               /* parse the TOM message capsule */
+                                               for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
+                                               {
+                                                       tom_byte = tvb_get_guint8(tvb, offset);
+
+                                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_data, tvb, 
+                                                               offset, 1, tom_byte);
+
+                                                       /* step to the next byte */
+                                                       offset++;
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* otherwise - call a subdissector */
+                               next_tvb = tvb_new_subset(tvb, offset, (crc_start-offset), -1);
+                               if (!dissector_try_port(llcgprs_subdissector_table,sapi, next_tvb, pinfo, tree))
+                               /* if no subdissector is found, call the data dissector */
+                               {
+                                       call_dissector(data_handle, next_tvb, pinfo, tree);
+                               }
+                       }
+                       /* END MLT CHANGES */
                                
                        break;
                case S_FORMAT:
@@ -339,98 +612,552 @@ dissect_llcgprs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        offset +=2;
                        epm = ctrl_fld_ui_s & 0x3;
                        nu = (nu >>2)&0x01FF;
-                       if (frame_format == S_FORMAT){
-                         if (check_col(pinfo->cinfo, COL_INFO)){
-                               col_append_str(pinfo->cinfo, COL_INFO, ", S, ");
-                               col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm,cr_formats_ipluss));
-                               col_append_fstr(pinfo->cinfo, COL_INFO, ", N(R) = %u", nu);
-                         }
-                         if (tree){
-                               ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2,2,"Supervisory format: %s: N(R) = %u",match_strval(epm,cr_formats_ipluss), nu);
-                               ctrl_f_tree = proto_item_add_subtree( ctrl_field_item, ett_llcgprs_sframe);
-                               proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_S_fmt, tvb, offset-2,2, ctrl_fld_ui_s );
-                               proto_tree_add_boolean( ctrl_f_tree, hf_llcgprs_As, tvb, offset-2, 2, ctrl_fld_ui_s );
-                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_NR, tvb, offset-2, 2, ctrl_fld_ui_s );
-                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sjsd, tvb, offset-2, 2, ctrl_fld_ui_s );
-                         }
-                       }else{
-/*UI format*/
-                         if (check_col(pinfo->cinfo, COL_INFO)) {
-                               col_append_str(pinfo->cinfo, COL_INFO, ", UI, ");
-                               col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm, pme ));
-                               col_append_fstr(pinfo->cinfo,COL_INFO, ", N(U) = %u", nu);
-                         }
-                         if (tree){    
-                               ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2, 2, "Unnumbered Information format - UI, N(U) = %u", nu);
-                               ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_ctrlf);
-                               proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_U_fmt, tvb, offset-2, 2, ctrl_fld_ui_s);
-                               proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_sp_bits, tvb, offset-2,2,ctrl_fld_ui_s);
-                               proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_NU, tvb, offset-2, 2, ctrl_fld_ui_s);
-                               proto_tree_add_boolean( ctrl_f_tree, hf_llcgprs_E_bit, tvb, offset-2,2,ctrl_fld_ui_s);
-                               proto_tree_add_boolean( ctrl_f_tree, hf_llcgprs_PM_bit, tvb, offset-2,2,ctrl_fld_ui_s);
-                         }
 
+                       if (frame_format == S_FORMAT)
+                       {
+/* S format */
+                               if (check_col(pinfo->cinfo, COL_INFO))
+                               {
+                                       col_append_str(pinfo->cinfo, COL_INFO, ", S, ");
+                                       col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm,cr_formats_ipluss));
+                                       col_append_fstr(pinfo->cinfo, COL_INFO, ", N(R) = %u", nu);
+                               }
                          
-                         next_tvb = tvb_new_subset(tvb, offset,crc_start-3, -1 );
-                         if ((ignore_cipher_bit && (fcs_status == FCS_VALID)) || !(epm & 0x2)){
-                               /*
-                                * Either we're ignoring the cipher bit
-                                * (because the bit is set but the
-                                * data is unciphered), and the data has
-                                * a valid FCS, or the cipher 
-                                * bit isn't set (indicating that the
-                                * data is unciphered).  Try dissecting
-                                * it with a subdissector.
-                                */
-                           if  (!dissector_try_port(llcgprs_subdissector_table,sapi, next_tvb, pinfo, tree))
-                               call_dissector(data_handle, next_tvb, pinfo, tree);
-                         }
-                         else  call_dissector(data_handle, next_tvb, pinfo, tree);
+                               if (tree)
+                               {
+                                       ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2, 2,
+                                               "Supervisory format: %s: N(R) = %u",
+                                               match_strval(epm,cr_formats_ipluss), nu);
+
+                                       ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_S_fmt, tvb, offset-2,
+                                               2, ctrl_fld_ui_s);
+                                       proto_tree_add_boolean(ctrl_f_tree, hf_llcgprs_As, tvb, offset-2, 
+                                               2, ctrl_fld_ui_s);
+
+                                       /* MLT CHANGES - added spare bits */
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sspare, tvb, offset-2, 
+                                               2, ctrl_fld_ui_s);
+                                       /* END MLT CHANGES */
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_NR, tvb, offset-2, 
+                                               2, ctrl_fld_ui_s);
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sjsd, tvb, offset-2, 
+                                               2, ctrl_fld_ui_s);
+                               }
+
+                               /* MLT CHANGES - additional parsing code to handle SACK */
+                               if ((ctrl_fld_ui_s & 0x03) == 0x03)
+                               /* It is a SACK frame */
+                               {
+                                       /* TODO: length is fudged - it is not correct */
+                                       guint32 sack_length = crc_start - offset;
+
+                                       if (tree)
+                                       {
+                                               guint8 loop_count = 0;
+                                               guint8 r_byte = 0;
+                                               guint16 location = offset;
+
+                                               ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
+                                                       sack_length, "SACK FRAME: length = %u", sack_length);
+                                       
+                                               /* display the R Bitmap */
+                                               for (loop_count = 0; loop_count < sack_length; loop_count++)
+                                               {
+                                                       r_byte = tvb_get_guint8(tvb, location);
+                                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_rbyte, tvb, 
+                                                               location, 1, r_byte);
+                                                       
+                                                       location++;
+                                               }
+
+                                               /* step past the r bitmap */
+                                               offset += sack_length;
+                                       }
+                               }
+
+                               /* should parse the rest of the supervisory message based on type */
+                               /* if SAPI is TOM do other parsing */
+                               if ((sapi == SAPI_TOM2) || (sapi == SAPI_TOM8))
+                               {
+                                       if (tree)
+                                       {
+                                               guint8 tom_byte = 0;
+                                               guint8 remaining_length = 0;
+                                               guint8 tom_pd = 0;
+                                               int loop_counter = 0;
+
+                                               tom_byte = tvb_get_guint8(tvb, offset);
+                                               remaining_length = (tom_byte >> 4) & 0x0F;
+                                               tom_pd = tom_byte & 0x0F;
+
+                                               ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
+                                                       (crc_start-offset), "TOM Envelope - Protocol: %s", 
+                                                       match_strval(tom_pd, tompd_formats));
+
+                                               ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
+
+                                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_rl, tvb, offset, 1, tom_byte);
+                                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_pd, tvb, offset, 1, tom_byte);
+
+                                               /* step past the TOM header first byte */
+                                               offset++;
+
+                                               /* TOM remaining length field value 0x0F is reserved for extension */
+                                               if (remaining_length != 0x0F)
+                                               {
+                                                       /* parse the rest of the TOM header */
+                                                       for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
+                                                       {
+                                                               tom_byte = tvb_get_guint8(tvb, offset);
+
+                                                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_header, tvb, 
+                                                                       offset, 1, tom_byte);
+
+                                                               /* step to the next byte */
+                                                               offset++;
+                                                       }
+
+                                                       /* Amount of frame left from offset to crc */
+                                                       remaining_length = crc_start - offset;
+
+                                                       /* parse the TOM message capsule */
+                                                       for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
+                                                       {
+                                                               tom_byte = tvb_get_guint8(tvb, offset);
+
+                                                               proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_data, tvb, 
+                                                                       offset, 1, tom_byte);
+
+                                                               /* step to the next byte */
+                                                               offset++;
+                                                       }
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       /* otherwise - call a subdissector */
+                                       next_tvb = tvb_new_subset(tvb, offset, (crc_start-offset), -1 );
+                                       if (!dissector_try_port(llcgprs_subdissector_table,sapi, next_tvb, pinfo, tree))
+                                       {
+                                               call_dissector(data_handle, next_tvb, pinfo, tree);
+                                       }
+                               }
+                               /* END MLT CHANGES */
+                       }
+                       else
+                       {
+/*UI format*/
+                               if (check_col(pinfo->cinfo, COL_INFO)) 
+                               {
+                                       col_append_str(pinfo->cinfo, COL_INFO, ", UI, ");
+                                       col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm, pme ));
+                                       col_append_fstr(pinfo->cinfo,COL_INFO, ", N(U) = %u", nu);
+                               }
+                       
+                               if (tree)
+                               {       
+                                       ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2, 
+                                               2, "Unnumbered Information format - UI, N(U) = %u", nu);
+                                       ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_ctrlf);
+
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_U_fmt, tvb, offset-2, 
+                                               2, ctrl_fld_ui_s);
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sp_bits, tvb, offset-2,
+                                               2, ctrl_fld_ui_s);
+                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_NU, tvb, offset-2, 2, 
+                                               ctrl_fld_ui_s);
+                                       proto_tree_add_boolean(ctrl_f_tree, hf_llcgprs_E_bit, tvb, offset-2,
+                                               2, ctrl_fld_ui_s);
+                                       proto_tree_add_boolean(ctrl_f_tree, hf_llcgprs_PM_bit, tvb, offset-2,
+                                               2, ctrl_fld_ui_s);
+                       }
+
+                               /* MLT CHANGES - TOM parsing added */
+                               next_tvb = tvb_new_subset(tvb, offset, (crc_start-offset), -1);
+
+                               if ((ignore_cipher_bit && (fcs_status == FCS_VALID)) || !(epm & 0x2))
+                               {
+                                       /* Either we're ignoring the cipher bit
+                                       * (because the bit is set but the
+                                       * data is unciphered), and the data has
+                                       * a valid FCS, or the cipher 
+                                       * bit isn't set (indicating that the
+                                       * data is unciphered).  Try dissecting
+                                       * it with a subdissector. */
+
+                                       /* if SAPI is TOM do other parsing */
+                                       if ((sapi == SAPI_TOM2) || (sapi == SAPI_TOM8))
+                                       {
+                                               if (tree)
+                                               {
+                                                       guint8 tom_byte = 0;
+                                                       guint8 remaining_length = 0;
+                                                       guint8 tom_pd = 0;
+                                                       int loop_counter = 0;
+
+                                                       tom_byte = tvb_get_guint8(tvb, offset);
+                                                       remaining_length = (tom_byte >> 4) & 0x0F;
+                                                       tom_pd = tom_byte & 0x0F;
+
+                                                       ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset, 
+                                                               (crc_start-offset), "TOM Envelope - Protocol: %s", 
+                                                               match_strval(tom_pd, tompd_formats));
+
+                                                       ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_sframe);
+
+                                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_rl, tvb, offset, 1, tom_byte);
+                                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_pd, tvb, offset, 1, tom_byte);
+
+                                                       /* step past the TOM header first byte */
+                                                       offset++;
+
+                                                       /* TOM remaining length field value 0x0F is reserved for extension */
+                                                       if (remaining_length != 0x0F)
+                                                       {
+                                                               /* parse the rest of the TOM header */
+                                                               for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
+                                                               {
+                                                                       tom_byte = tvb_get_guint8(tvb, offset);
+
+                                                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_header, tvb, 
+                                                                               offset, 1, tom_byte);
+
+                                                                       /* step to the next byte */
+                                                                       offset++;
+                                                               }
+
+                                                               /* Amount of frame left from offset to crc */
+                                                               remaining_length = crc_start - offset;
+
+                                                               /* parse the TOM message capsule */
+                                                               for (loop_counter = 0; loop_counter < remaining_length; loop_counter++)
+                                                               {
+                                                                       tom_byte = tvb_get_guint8(tvb, offset);
+
+                                                                       proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_tom_data, tvb, 
+                                                                               offset, 1, tom_byte);
+
+                                                                       /* step to the next byte */
+                                                                       offset++;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* otherwise - call a subdissector */
+                                               if (!dissector_try_port(llcgprs_subdissector_table, sapi, next_tvb, pinfo, tree))
+                                               {
+                                                       call_dissector(data_handle, next_tvb, pinfo, tree);
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       /* ciphered information - just parse it as data */
+                                       call_dissector(data_handle, next_tvb, pinfo, tree);
+                               }
+
+                               /* END MLT CHANGES */
                        }
                        break;
                case U_FORMAT:
                     offset +=1;
                     tmp = 0;
                     tmp =  ctrl_fld_fb & 0xf;
-                       if (check_col(pinfo->cinfo, COL_INFO)) {
+
+                       if (check_col(pinfo->cinfo, COL_INFO)) 
+                       {
                                col_append_str(pinfo->cinfo, COL_INFO, ", U, ");
-                               col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, cr_formats_unnumb,"Unknown/invalid code:%X"));
+                               col_append_str(pinfo->cinfo, COL_INFO, 
+                                       val_to_str(tmp, cr_formats_unnumb,"Unknown/invalid code:%X"));
                        }
+
                        if(tree){
-                               ui_ti = proto_tree_add_text(llcgprs_tree,tvb,offset-1,crc_start-1,"Unnumbered frame: %s",val_to_str(tmp,cr_formats_unnumb,"Unknown/invalid code:%X"));
-                               ui_tree = proto_item_add_subtree( ui_ti, ett_ui);
-                               proto_tree_add_uint( ui_tree, hf_llcgprs_Un, tvb, offset-1, 1, ctrl_fld_fb);
-                               proto_tree_add_boolean( ui_tree, hf_llcgprs_PF, tvb, offset-1, 1, ctrl_fld_fb);
-                               proto_tree_add_uint( ui_tree, hf_llcgprs_ucom, tvb, offset-1, 1, ctrl_fld_fb);
+                               ui_ti = proto_tree_add_text(llcgprs_tree, tvb, (offset-1), (crc_start-1),
+                                       "Unnumbered frame: %s", 
+                                       val_to_str(tmp,cr_formats_unnumb, "Unknown/invalid code:%X"));
+
+                               ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
+                               proto_tree_add_uint(ui_tree, hf_llcgprs_Un, tvb, (offset-1), 1, ctrl_fld_fb);
+                               proto_tree_add_boolean(ui_tree, hf_llcgprs_PF, tvb, (offset-1), 1, ctrl_fld_fb);
+                               proto_tree_add_uint(ui_tree, hf_llcgprs_ucom, tvb, (offset-1), 1, ctrl_fld_fb);
+
                        }
-                       break;
-/*             case I_SACK:
-                       break;
-               case S_SACK:
-                       break;  
-*/
-               }               
-/*             proto_tree_add_item(llcgprs_tree,
-                   hf_llcgprs_FIELDABBREV, tvb, offset, len, FALSE)
-*/
-/* Continue adding tree items to process the packet here */
 
+                       /* MLT CHANGES - parse rest of the message based on type (M Bits) */
+                       m_bits = ctrl_fld_fb & 0x0F;
+
+                       info_len = crc_start - offset;
+                       
+                       switch (m_bits)
+                       {
+                       case U_DM:
+                       case U_DISC:
+                       case U_NULL:
+                               /* These frames SHOULD NOT have an info field */
+                               if (tree)
+                               {
+                                       ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
+                                               "No Information Field");
+                                       ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
+                               }
+                               break;
+                       case U_UA:
+                               /* This frame MAY or MAY NOT have an info field */
+                               /* Info field, if it exists, consists of XID parameters */
+                               if (tree)
+                               {
+                                       if (info_len > 0)
+                                       {
+                                               guint8 xid_param_len = 0;
+                                               guint16 location = offset;
+                                               guint8 byte1 = 0;
+                                               guint8 byte2 = 0;
+                                               guint8 ending = 0;
+                                               int loop_counter = 0;
+
+                                               ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
+                                                       "Information Field: Length = %u", info_len);
+                                               ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
+
+                                               while (location < (offset + info_len))
+                                               {
+                                                       /* parse the XID parameters */
+                                                       byte1 = tvb_get_guint8(tvb, location);
+                                                       
+                                                       if (byte1 & 0x80) 
+                                                       {
+                                                               guint8 xid_param_len_high = 0;
+                                                               guint8 xid_param_len_low = 0;
+
+                                                               byte2 = tvb_get_guint8(tvb, location + 1);
+
+                                                               /* XL bit is set - length is continued in second byte */
+                                                               xid_param_len_high = byte1 & 0x03;
+                                                               xid_param_len_low = byte2 & 0xFC;
 
+                                                               /* bit shift the rest of the length */
+                                                               xid_param_len_low = xid_param_len_low >> 2;
+                                                               xid_param_len_low = xid_param_len_low & 0x3F;
 
-/* If this protocol has a sub-dissector call it here, see section 1.8 */
+                                                               xid_param_len_high = xid_param_len_high << 6;
+                                                               xid_param_len_high = xid_param_len_high & 0xC0;
+
+                                                               /* combine the two */
+                                                               xid_param_len = xid_param_len_high | xid_param_len_low;
+
+                                                       }
+                                                       else
+                                                       {
+                                                               xid_param_len = byte1 & 0x3;
+                                                       }
+
+                                                       ending = location + xid_param_len;
+
+                                                       tmp =  byte1 & 0x7C;
+                                                       tmp = tmp >> 2;
+                                                       uinfo_field = proto_tree_add_text(ui_tree, tvb, location, 
+                                                               (ending - 1), "XID Parameter Type: %s", 
+                                                               val_to_str(tmp, xid_param_type_str,"Reserved Type:%X"));
+
+                                                       uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
+                                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_xl, tvb, 
+                                                               location, 1, byte1);
+                                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_type, tvb, 
+                                                               location, 1, byte1);
+                                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len1, tvb, 
+                                                               location, 1, byte1);
+
+                                                       if (byte1 & 0x80) {
+                                                               /* length continued into byte 2 */
+                                                               proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len2, tvb, 
+                                                                       location, 1, byte2);
+                                                               proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_spare, tvb, 
+                                                                       location, 1, byte2);
+
+                                                               /* be sure to account for the second byte of length */
+                                                               location++;
+                                                       }
+
+                                                       location++;
+                                                       for (loop_counter = 0; loop_counter < xid_param_len; loop_counter++)
+                                                       {
+                                                               /* grab the information in the XID param */
+                                                               byte2 = tvb_get_guint8(tvb, location);
+                                                               proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_byte, tvb, 
+                                                                       location, 1, byte2);
+
+                                                               location++;
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
+                                                       "No Information Field");
+                                               ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
+                                       }
+                               }
+                               break;
+                       case U_SABM:
+                       case U_XID:
+                               /* These frames do have info fields consisting of XID parameters */
+                               /* Info field consists of XID parameters */
+                               if (tree)
+                               {
+                                       guint8 xid_param_len = 0;
+                                       guint16 location = offset;
+                                       guint8 byte1 = 0;
+                                       guint8 byte2 = 0;
+                                       guint8 ending = 0;
+                                       int loop_counter = 0;
+
+                                       ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
+                                               "Information Field: Length = %u", info_len);
+                                       ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
+
+                                       while (location < (offset + info_len))
+                                       {
+                                               /* parse the XID parameters */
+                                               byte1 = tvb_get_guint8(tvb, location);
+                                               
+                                               if (byte1 & 0x80) 
+                                               {
+                                                       guint8 xid_param_len_high = 0;
+                                                       guint8 xid_param_len_low = 0;
+
+                                                       byte2 = tvb_get_guint8(tvb, location + 1);
+
+                                                       /* XL bit is set - length is continued in second byte */
+                                                       xid_param_len_high = byte1 & 0x03;
+                                                       xid_param_len_low = byte2 & 0xFC;
+
+                                                       /* bit shift the rest of the length */
+                                                       xid_param_len_low = xid_param_len_low >> 2;
+                                                       xid_param_len_low = xid_param_len_low & 0x3F;
+
+                                                       xid_param_len_high = xid_param_len_high << 6;
+                                                       xid_param_len_high = xid_param_len_high & 0xC0;
+
+                                                       /* combine the two */
+                                                       xid_param_len = xid_param_len_high | xid_param_len_low;
+
+                                               }
+                                               else
+                                               {
+                                                       xid_param_len = byte1 & 0x3;
+                                               }
+
+                                               ending = location + xid_param_len;
+
+                                               tmp =  byte1 & 0x7C;
+                                               tmp = tmp >> 2;
+                                               uinfo_field = proto_tree_add_text(ui_tree, tvb, location, (ending - 1), 
+                                                       "XID Parameter Type: %s", 
+                                                       val_to_str(tmp, xid_param_type_str,"Reserved Type:%X"));
+
+                                               uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
+                                               proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_xl, tvb, location, 
+                                                       1, byte1);
+                                               proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_type, tvb, location, 
+                                                       1, byte1);
+                                               proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len1, tvb, location, 
+                                                       1, byte1);
+
+                                               if (byte1 & 0x80) {
+                                                       /* length continued into byte 2 */
+                                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_len2, tvb, location, 
+                                                               1, byte2);
+                                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_spare, tvb, location, 
+                                                               1, byte2);
+
+                                                       /* be sure to account for the second byte of length */
+                                                       location++;
+                                               }
+
+                                               location++;
+                                               for (loop_counter = 0; loop_counter < xid_param_len; loop_counter++)
+                                               {
+                                                       /* grab the information in the XID param */
+                                                       byte2 = tvb_get_guint8(tvb, location);
+                                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_xid_byte, tvb, location, 
+                                                               1, byte2);
+
+                                                       location++;
+                                               }
+                                       }
+                               }
+                               break;
+                       case U_FRMR:
+                               /* This frame has a special format info field */
+                               if (tree)
+                               {
+                                       guint32 fld_vars = 0;
+                                       guint16 cf_byte = 0;
+                                       int loop_counter = 0;
+                                       int location = 0;
+
+                                       ui_ti = proto_tree_add_text(llcgprs_tree, tvb, offset, (crc_start-2), 
+                                               "Information Field: Length = %u", info_len);
+                                       ui_tree = proto_item_add_subtree(ui_ti, ett_ui);
+
+                                       uinfo_field = proto_tree_add_text(ui_tree, tvb, offset, 6, 
+                                               "Rejected Frame Control Field");
+                                       uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
+
+                                       location = offset;
+                                       for (loop_counter = 0; loop_counter < 3; loop_counter++)
+                                       {
+                                               /* display the rejected frame control field */
+                                               cf_byte = tvb_get_ntohs(tvb, location);
+                                               proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_cf, tvb, location, 
+                                                       2, cf_byte);
+
+                                               location += 2;
+                                       }
+
+                                       uinfo_field = proto_tree_add_text(ui_tree, tvb, location, 4, 
+                                               "Information Field Data");
+                                       uinfo_tree = proto_item_add_subtree(uinfo_field, ett_ui);
+
+                                       fld_vars = tvb_get_ntohl(tvb, location);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_spare, tvb, location, 
+                                               4, fld_vars);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_vs, tvb, location, 
+                                               2, fld_vars);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_vr, tvb, (location + 1), 
+                                               2, fld_vars);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_cr, tvb, (location + 2), 
+                                               1, fld_vars);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w4, tvb, (location + 3), 
+                                               1, fld_vars);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w3, tvb, (location + 3), 
+                                               1, fld_vars);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w2, tvb, (location + 3), 
+                                               1, fld_vars);
+                                       proto_tree_add_uint(uinfo_tree, hf_llcgprs_frmr_w1, tvb, (location + 3), 
+                                               1, fld_vars);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+                       /* END MLT CHANGES */
+                       break;
+               }               
 }
 
 
 /* Register the protocol with Ethereal */
-
-/* this format is require because a script is used to build the C function
-   that calls all the protocol registration.
-*/
+/* this format is require because a script is used to build the C function */
+/* that calls all the protocol registration. */
 
 void
 proto_register_llcgprs(void)
 {                 
-
 /* Setup list of header fields  See Section 1.6.1 for details*/
        static hf_register_info hf[] = {
                { &hf_llcgprs_sapi,
@@ -464,7 +1191,82 @@ proto_register_llcgprs(void)
                { &hf_llcgprs_NR,
                        { "Receive sequence number", "llcgprs.nr",FT_UINT16, BASE_DEC, NULL, UI_MASK_NU,"Receive sequence number N(R)",HFILL }},
                {&hf_llcgprs_S_fmt,
-                       { "S format", "llcgprs.s", FT_UINT16, BASE_DEC, NULL, 0xc000,"Supervisory format S", HFILL}}
+                       { "S format", "llcgprs.s", FT_UINT16, BASE_DEC, NULL, 0xc000,"Supervisory format S", HFILL}},
+               /* MLT CHANGES - additional masks*/
+               {&hf_llcgprs_kmask,
+                       { "ignored", "llcgprs.kmask", FT_UINT8, BASE_DEC, NULL, 0xE0, "ignored", HFILL}},
+               {&hf_llcgprs_k,
+                       { "k", "llcgprs.k", FT_UINT8, BASE_DEC, NULL, 0x1F, "k counter", HFILL}},
+               {&hf_llcgprs_isack_ns,
+                       { "N(S)", "llcgprs.sackns", FT_UINT24, BASE_DEC, NULL, 0x1FF000, "N(S)", HFILL}},
+               {&hf_llcgprs_isack_nr,
+                       { "N(R)", "llcgprs.sacknr", FT_UINT24, BASE_DEC, NULL, 0x0007FC, "N(R)", HFILL}},
+               {&hf_llcgprs_isack_sfb,
+                       { "Supervisory function bits","llcgprs.sacksfb", FT_UINT24, BASE_HEX, VALS(cr_formats_ipluss),0x000003, "Supervisory functions bits",HFILL }},
+               {&hf_llcgprs_ifmt,
+                       { "I Format", "llcgprs.ifmt", FT_UINT24, BASE_DEC, NULL, 0x800000, "I Fmt Bit", HFILL}},
+               {&hf_llcgprs_ia,
+                       { "Ack Bit", "llcgprs.ia", FT_UINT24, BASE_DEC, NULL, 0x400000, "I A Bit", HFILL}},
+               {&hf_llcgprs_izerobit,
+                       { "Spare", "llcgprs.iignore", FT_UINT24, BASE_DEC, NULL, 0x200000, "Ignore Bit", HFILL}},
+               {&hf_llcgprs_sspare,
+                       { "Spare", "llcgprs.sspare", FT_UINT16, BASE_DEC, NULL, 0x1800, "Ignore Bit", HFILL}},
+               {&hf_llcgprs_rbyte,
+                               { "R Bitmap Bits","llcgprs.sackrbits", FT_UINT8, BASE_HEX, NULL, 0xFF, "R Bitmap", HFILL}},
+               /* XID Parameter Parsing Info */
+               {&hf_llcgprs_xid_xl,
+                               { "XL Bit","llcgprs.xidxl", FT_UINT8, BASE_HEX, NULL, 0x80, "XL", HFILL}},
+               {&hf_llcgprs_xid_type,
+                               { "Type","llcgprs.xidtype", FT_UINT8, BASE_DEC, NULL, 0x7C, "Type", HFILL}},
+               {&hf_llcgprs_xid_len1,
+                               { "Length","llcgprs.xidlen1", FT_UINT8, BASE_DEC, NULL, 0x03, "Len", HFILL}},
+               {&hf_llcgprs_xid_len2,
+                               { "Length continued","llcgprs.xidlen2", FT_UINT8, BASE_DEC, NULL, 0xFC, "Len", HFILL}},
+               {&hf_llcgprs_xid_spare,
+                               { "Spare","llcgprs.xidspare", FT_UINT8, BASE_HEX, NULL, 0x03, "Ignore", HFILL}},
+               {&hf_llcgprs_xid_byte,
+                               { "Parameter Byte","llcgprs.xidbyte", FT_UINT8, BASE_HEX, NULL, 0xFF, "Data", HFILL}},
+               /* FRMR Parsing Information */
+               {&hf_llcgprs_frmr_cf,
+                               { "Control Field Octet","llcgprs.frmrrfcf", FT_UINT16, BASE_DEC, NULL, 
+                                       0xFFFF, "Rejected Frame CF", HFILL}},
+               {&hf_llcgprs_frmr_spare,
+                               { "X","llcgprs.frmrspare", FT_UINT32, BASE_HEX, NULL, 0xF00400F0, 
+                                       "Filler", HFILL}},
+               {&hf_llcgprs_frmr_vs,
+                               { "V(S)","llcgprs.frmrvs", FT_UINT32, BASE_DEC, NULL, 0x0FF80000, 
+                                       "Current send state variable", HFILL}},
+               {&hf_llcgprs_frmr_vr,
+                               { "V(R)","llcgprs.frmrvr", FT_UINT32, BASE_DEC, NULL, 0x0003FE00, 
+                                       "Current receive state variable", HFILL}},
+               {&hf_llcgprs_frmr_cr,
+                               { "C/R","llcgprs.frmrcr", FT_UINT32, BASE_DEC, NULL, 0x00000100, 
+                                       "Rejected command response", HFILL}},
+               {&hf_llcgprs_frmr_w4,
+                               { "W4","llcgprs.frmrw4", FT_UINT32, BASE_DEC, NULL, 0x00000008, 
+                                       "LLE was in ABM when rejecting", HFILL}},
+               {&hf_llcgprs_frmr_w3,
+                               { "W3","llcgprs.frmrw3", FT_UINT32, BASE_DEC, NULL, 0x00000004, 
+                                       "Undefined control field", HFILL}},
+               {&hf_llcgprs_frmr_w2,
+                               { "W2","llcgprs.frmrw2", FT_UINT32, BASE_DEC, NULL, 0x00000002, 
+                                       "Info exceeded N201", HFILL}},
+               {&hf_llcgprs_frmr_w1,
+                               { "W1","llcgprs.frmrw1", FT_UINT32, BASE_DEC, NULL, 0x00000001, 
+                                       "Invalid - info not permitted", HFILL}},
+               {&hf_llcgprs_tom_rl,
+                               { "Remaining Length of TOM Protocol Header","llcgprs.romrl", FT_UINT8,
+                                       BASE_DEC, NULL, 0xF0, "RL", HFILL}},
+               {&hf_llcgprs_tom_pd,
+                               { "TOM Protocol Discriminator","llcgprs.tompd", FT_UINT8, BASE_HEX, 
+                                       NULL, 0x0F, "TPD", HFILL}},
+               {&hf_llcgprs_tom_header,
+                               { "TOM Header Byte","llcgprs.tomhead", FT_UINT8, BASE_HEX, NULL, 0xFF, 
+                                       "thb", HFILL}},
+               {&hf_llcgprs_tom_data,
+                               { "TOM Message Capsule Byte","llcgprs.tomdata", FT_UINT8, BASE_HEX, NULL, 
+                                       0xFF, "tdb", HFILL}},
+               /* END MLT CHANGES */
        };
 
 /* Setup protocol subtree array */
@@ -485,7 +1287,7 @@ proto_register_llcgprs(void)
 /* Required function calls to register the header fields and subtrees used */
        proto_register_field_array(proto_llcgprs, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
-       register_dissector( "llcgprs", dissect_llcgprs, proto_llcgprs);
+       register_dissector("llcgprs", dissect_llcgprs, proto_llcgprs);
        
        llcgprs_module = prefs_register_protocol ( proto_llcgprs, NULL );
        prefs_register_bool_preference ( llcgprs_module, "autodetect_cipher_bit",
@@ -495,12 +1297,17 @@ proto_register_llcgprs(void)
 }
 
 
-/* If this dissector uses sub-dissector registration add a registration routine.
-   This format is required because a script is used to find these routines and
-   create the code that calls these routines.
-*/
+/* If this dissector uses sub-dissector registration add a registration routine. */
+/* This format is required because a script is used to find these routines and */
+/* create the code that calls these routines. */
 void
 proto_reg_handoff_llcgprs(void)
 {
+       dissector_handle_t gprs_llc_handle;
+
+       /* make sure that the top level can call this dissector */
+       gprs_llc_handle = create_dissector_handle(dissect_llcgprs, proto_llcgprs);
+       dissector_add("wtap_encap", WTAP_ENCAP_GPRS_LLC, gprs_llc_handle);
+
        data_handle = find_dissector("data");
 }
index d1f230a8409ce5a3c432d35039dbf547c5b455e2..35f034aa1cd165993623c59a45d772c02a908c1d 100644 (file)
@@ -10897,29 +10897,32 @@ de_sm_pco(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add
     guint      curr_len;
     guchar     oct;
     struct e_in6_addr ipv6_addr;
-    
+
     curr_len = len;
     curr_offset = offset;
-
+       
     oct = tvb_get_guint8(tvb, curr_offset);
     curr_len--;
     curr_offset++;
 
-    proto_tree_add_text(tree,tvb, curr_offset, 1, "Ext: 0x%02x (%u)",oct>>7,oct>>7);
-    proto_tree_add_text(tree,tvb, curr_offset, 1, "Configuration Protocol: PPP (%u)",oct&0x0f);
+       /* MLT - Possible bugs here */
+       /* made it (curr_offset - 1) instead of curr_offset in display since the line */
+       /* right before moves the current index */
+    proto_tree_add_text(tree,tvb, curr_offset-1, 1, "Ext: 0x%02x (%u)",oct>>7,oct>>7);
+    proto_tree_add_text(tree,tvb, curr_offset-1, 1, "Configuration Protocol: PPP (%u)",oct&0x0f);
 
     while ( curr_len > 0 )
     {
        guchar e_len;
        guint16 prot;
-       tvbuff_t *l3_tvb;
-       dissector_handle_t handle = NULL;
-       static packet_info p_info;
-       
-       prot = tvb_get_guint8(tvb, curr_offset);
-       prot <<= 8;
-       prot |= tvb_get_guint8(tvb, curr_offset+1);
-       e_len = tvb_get_guint8(tvb, curr_offset+2);
+               tvbuff_t *l3_tvb;
+               dissector_handle_t handle = NULL;
+               static packet_info p_info;
+
+               prot = tvb_get_guint8(tvb, curr_offset);
+               prot <<= 8;
+               prot |= tvb_get_guint8(tvb, curr_offset+1);
+               e_len = tvb_get_guint8(tvb, curr_offset+2);
        curr_len-=3;
        curr_offset+=3;
 
@@ -18538,5 +18541,23 @@ proto_reg_handoff_gsm_a(void)
     dissector_add("bssap.pdu_type",  BSSAP_PDU_TYPE_DTAP, dtap_handle);
     dissector_add("ranap.nas_pdu",  BSSAP_PDU_TYPE_DTAP, dtap_handle);
     dissector_add("llcgprs.sapi", 1 , dtap_handle);
+       /* MLT CHANGES - add other GPRS subprotocols */
+       dissector_add("llcgprs.sapi", 0, dtap_handle); /* Reserved */
+       dissector_add("llcgprs.sapi", 2, dtap_handle); /* TOM2 */
+       dissector_add("llcgprs.sapi", 3, dtap_handle); /* LL3 */
+       dissector_add("llcgprs.sapi", 4, dtap_handle); /* Reserved */
+       dissector_add("llcgprs.sapi", 5, dtap_handle); /* LL5 */
+       dissector_add("llcgprs.sapi", 6, dtap_handle); /* Reserved */
+       dissector_add("llcgprs.sapi", 7, dtap_handle); /* LLSMS */
+       dissector_add("llcgprs.sapi", 8, dtap_handle); /* TOM8 */
+       dissector_add("llcgprs.sapi", 9, dtap_handle); /* LL9 */
+       dissector_add("llcgprs.sapi", 10, dtap_handle); /* Reserved */
+       dissector_add("llcgprs.sapi", 11, dtap_handle); /* LL 11 */
+       dissector_add("llcgprs.sapi", 12, dtap_handle); /* Reserved */
+       dissector_add("llcgprs.sapi", 13, dtap_handle); /* Reserved */
+       dissector_add("llcgprs.sapi", 14, dtap_handle); /* Reserved */
+       dissector_add("llcgprs.sapi", 15, dtap_handle); /* Reserved */
+       /* END MLT CHANGES */
+
     data_handle = find_dissector("data");
 }