Wireshark-dev: [Wireshark-dev] AMR dissector improvements

From: Stefan Wenk <stefan.wenk@xxxxxx>
Date: Sun, 27 May 2007 09:17:01 +0200
Below you find improvements for the AMR dissector.
Following items are changed:
*) Bandwidth efficient decoding re-implemented with expert-info support. 
    The old implementation supported a single frame only.
*) Support for AMR-WB added
*) Fixes for IF1 and IF2 decoding

Index: packet-amr.c
===================================================================
--- packet-amr.c (revision 21958)
+++ packet-amr.c (working copy)
@@ -24,7 +24,7 @@
  *
  * References:
  * RFC 3267  http://www.ietf.org/rfc/rfc3267.txt?number=3267
- * 3GPP TS 26.101
+ * 3GPP TS 26.101 for AMR-NB, 3GPP TS 26.201 for AMR-WB
  */
 
 #ifdef HAVE_CONFIG_H
@@ -39,35 +39,46 @@
 
 #include <epan/packet.h>
 #include <epan/proto.h>
+#include <epan/expert.h>
 
+
 #include "prefs.h"
 
-#define AMR_SID 8
+#define AMR_NB_SID 8
+#define AMR_WB_SID 9
 #define AMR_NO_TRANS 15
 
+#define AMR_NB 0
+#define AMR_WB 1
+
 /* Initialize the protocol and registered fields */
 static int proto_amr  = -1;
-static int hf_amr_cmr  = -1;
+static int hf_amr_nb_cmr = -1;
+static int hf_amr_wb_cmr = -1;
 static int hf_amr_reserved = -1;
 static int hf_amr_toc_f  = -1;
-static int hf_amr_toc_ft = -1;
+static int hf_amr_nb_toc_ft = -1;
+static int hf_amr_wb_toc_ft = -1;
 static int hf_amr_toc_q  = -1;
 
-static int hf_amr_if1_ft = -1;
+static int hf_amr_nb_if1_ft = -1;
+static int hf_amr_wb_if1_ft = -1;
 static int hf_amr_if1_fqi = -1;
-static int hf_amr_if1_mode_req = -1;
+static int hf_amr_nb_if1_mode_req = -1;
+static int hf_amr_wb_if1_mode_req = -1;
 static int hf_amr_if1_sti = -1;
-static int hf_amr_if1_mode_ind = -1;
-static int hf_amr_if1_sti_mode_ind = -1;
-static int hf_amr_sti = -1;
+static int hf_amr_nb_if1_mode_ind = -1;
+static int hf_amr_wb_if1_mode_ind = -1;
+static int hf_amr_nb_if1_sti_mode_ind = -1;
+static int hf_amr_wb_if1_sti_mode_ind = -1;
+static int hf_amr_if2_sti = -1;
+static int hf_amr_nb_if2_sti_mode_ind = -1;
+static int hf_amr_wb_if2_sti_mode_ind = -1;
 
-static int hf_amr_if2_ft = -1;
+static int hf_amr_nb_if2_ft = -1;
+static int hf_amr_wb_if2_ft = -1;
 
-static int hf_amr_be_reserved = -1;
-static int hf_amr_be_ft = -1;
-static int hf_amr_be_reserved2 = -1;
 
-
 /* Initialize the subtree pointers */
 static int ett_amr = -1;
 static int ett_amr_toc = -1;
@@ -77,7 +88,9 @@
 static guint dynamic_payload_type = 0;
 static guint temp_dynamic_payload_type = 0;
 gint amr_encoding_type = 0;
+gint amr_mode = AMR_NB;
 
+
 /* Currently only octet aligned works */
 /* static gboolean octet_aligned = TRUE; */
 
@@ -89,21 +102,61 @@
  { 0, NULL }
 };
 
-static const value_string amr_codec_mode_vals[] = {
- {0,   "AMR 4,75 kbit/s"}, 
- {1,   "AMR 5,15 kbit/s"},
- {2,   "AMR 5,90 kbit/s"},
- {3,   "AMR 6,70 kbit/s (PDC-EFR)"},
- {4,   "AMR 7,40 kbit/s (TDMA-EFR)"},
- {5,   "AMR 7,95 kbit/s"},
- {6,   "AMR 10,2 kbit/s"},
- {7,   "AMR 12,2 kbit/s (GSM-EFR)"},
+
+/* Table 1a of 3GPP TS 26.201*/
+static const value_string amr_nb_codec_mode_vals[] = {
+ {0,  "AMR 4,75 kbit/s"}, 
+ {1,  "AMR 5,15 kbit/s"},
+ {2,  "AMR 5,90 kbit/s"},
+ {3,  "AMR 6,70 kbit/s (PDC-EFR)"},
+ {4,  "AMR 7,40 kbit/s (TDMA-EFR)"},
+ {5,  "AMR 7,95 kbit/s"},
+ {6,  "AMR 10,2 kbit/s"},
+ {7,  "AMR 12,2 kbit/s (GSM-EFR)"},
+ {AMR_NB_SID, "AMR SID (Comfort Noise Frame)"},
+ {9,  "GSM-EFR SID"},
+ {10,  "TDMA-EFR SID "},
+ {11,  "PDC-EFR SID"},
+ {12,  "Illegal Frametype - for future use"},
+ {13,  "Illegal Frametype - for future use"},
+ {14,  "Illegal Frametype - for future use"},
+ {AMR_NO_TRANS, "No Data (No transmission/No reception)"},
  { 0, NULL }
 };
 
-/* Ref 3GPP TS 26.101 table 1a */
-static const value_string amr_codec_mode_request_vals[] = {
- {0,   "AMR 4,75 kbit/s"}, 
+static const value_string amr_wb_codec_mode_vals[] = {
+ {0, "AMR-WB 6.60 kbit/s"},
+ {1, "AMR-WB 8.85 kbit/s"},
+ {2, "AMR-WB 12.65 kbit/s"},
+ {3, "AMR-WB 14.25 kbit/s"},
+ {4, "AMR-WB 15.85 kbit/s"},
+ {5, "AMR-WB 18.25 kbit/s"},
+ {6, "AMR-WB 19.85 kbit/s"},
+ {7, "AMR-WB 23.05 kbit/s"},
+ {8, "AMR-WB 23.85 kbit/s"},
+ {AMR_WB_SID, "AMR-WB SID (Comfort Noise Frame)"},
+ {10,  "Illegal Frametype"},
+ {11,  "Illegal Frametype"},
+ {12,  "Illegal Frametype"},
+ {13,  "Illegal Frametype"},
+ {14,  "Speech lost"},
+ {AMR_NO_TRANS, "No Data (No transmission/No reception)"},
+ { 0, NULL }
+};
+
+/* Ref 3GPP TS 26.101 table 1a for AMR-NB*/
+
+/* From RFC3267 chapter 4.3.1 
+CMR (4 bits): Indicates a codec mode request sent to the speech
+      encoder at the site of the receiver of this payload.  The value of
+      the CMR field is set to the frame type index of the corresponding
+      speech mode being requested.  The frame type index may be 0-7 for
+      AMR, as defined in Table 1a in [2], or 0-8 for AMR-WB, as defined
+      in Table 1a in [3GPP TS 26.201].  CMR value 15 indicates that no 
+      mode request is present, and other values are for future use.
+*/
+static const value_string amr_nb_codec_mode_request_vals[] = {
+ {0,   "AMR 4,75 kbit/s"},
  {1,   "AMR 5,15 kbit/s"},
  {2,   "AMR 5,90 kbit/s"},
  {3,   "AMR 6,70 kbit/s (PDC-EFR)"},
@@ -111,17 +164,38 @@
  {5,   "AMR 7,95 kbit/s"},
  {6,   "AMR 10,2 kbit/s"},
  {7,   "AMR 12,2 kbit/s (GSM-EFR)"},
- {AMR_SID, "AMR SID"},
- {9,   "GSM-EFR SID"},
- {10,  "TDMA-EFR SID"},
- {11,  "PDC-EFR SID"},
- /*
- {12-14 - - For future use
- */
- {AMR_NO_TRANS, "No Data (No transmission/No reception)"}, 
+ {8,  "Illegal Frametype - For future us"},
+ {8,  "Illegal Frametype - For future us"},
+ {10,  "Illegal Frametype - For future us"},
+ {11,  "Illegal Frametype - For future us"},
+ {12,  "Illegal Frametype - For future use"},
+ {13,  "Illegal Frametype - For future use"},
+ {14,  "Illegal Frametype - For future use"},
+ {15,  "No mode request"}, 
  { 0, NULL }
 };
 
+/* Ref 3GPP TS 26.201 table 1a for AMR-WB*/
+static const value_string amr_wb_codec_mode_request_vals[] = {
+ {0, "AMR-WB 6.60 kbit/s"},
+ {1, "AMR-WB 8.85 kbit/s"},
+ {2, "AMR-WB 12.65 kbit/s"},
+ {3, "AMR-WB 14.25 kbit/s"},
+ {4, "AMR-WB 15.85 kbit/s"},
+ {5, "AMR-WB 18.25 kbit/s"},
+ {6, "AMR-WB 19.85 kbit/s"},
+ {7, "AMR-WB 23.05 kbit/s"},
+ {8, "AMR-WB 23.85 kbit/s"},
+ {9, "Illegal Frametype - For future use"},
+ {10,"Illegal Frametype - For future use"},
+ {11,"Illegal Frametype - For future use"},
+ {12,"Illegal Frametype - For future use"},
+ {13,"Illegal Frametype - For future use"},
+ {14,"Illegal Frametype - For future us"},
+ {15,"No mode request"}, 
+ { 0, NULL }
+};
+
 static const true_false_string toc_f_bit_vals = {
   "Followed by another speech frame",
   "Last frame in this payload"
@@ -136,41 +210,75 @@
   "SID_UPDATE",
   "SID_FIRST"
 };
+
+/* See 3GPP TS 26.101 chapter 4 for AMR-NB IF1 */
 static void
-dissect_amr_if1(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree){
+dissect_amr_nb_if1(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree){
  int offset =0;
  guint8 octet;
 
- proto_tree_add_item(tree, hf_amr_if1_ft, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_amr_nb_if1_ft, tvb, offset, 1, FALSE);
  proto_tree_add_item(tree, hf_amr_if1_fqi, tvb, offset, 1, FALSE);
- octet = tvb_get_guint8(tvb,offset) & 0x0f;
- if (octet == AMR_SID){
-  proto_tree_add_item(tree, hf_amr_if1_mode_req, tvb, offset+1, 1, FALSE);
+ octet = (tvb_get_guint8(tvb,offset) & 0xf0) >> 4;
+ if (octet == AMR_NB_SID){
+  proto_tree_add_item(tree, hf_amr_nb_if1_mode_req, tvb, offset+1, 1, FALSE);
+  if (tvb_get_guint8(tvb,offset+1) & 0x1f)
+      proto_tree_add_text(tree, tvb, offset+1, 1, "Error:Spare bits not 0");
+  proto_tree_add_text(tree, tvb, offset+2, 5, "Speech data");
+  proto_tree_add_item(tree, hf_amr_if1_sti, tvb, offset+7, 1, FALSE);
+  proto_tree_add_item(tree, hf_amr_nb_if1_sti_mode_ind, tvb, offset+7, 1, FALSE);
+  return;
+ }
+
+ proto_tree_add_item(tree, hf_amr_nb_if1_mode_ind, tvb, offset, 1, FALSE);
+ offset++;
+ proto_tree_add_item(tree, hf_amr_nb_if1_mode_req, tvb, offset, 1, FALSE);
+ if (tvb_get_guint8(tvb,offset) & 0x1f)
+  proto_tree_add_text(tree, tvb, offset, 1, "Error:Spare bits not 0");
+ offset++;
+ proto_tree_add_text(tree, tvb, offset, -1, "Speech data");
+
+}
+
+/* See 3GPP TS 26.201 for AMR-WB */
+static void
+dissect_amr_wb_if1(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree){
+ int offset =0;
+ guint8 octet;
+ proto_tree_add_item(tree, hf_amr_wb_if1_ft, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_amr_if1_fqi, tvb, offset, 1, FALSE);
+ if (tvb_get_guint8(tvb,offset) & 0x03)
+     proto_tree_add_text(tree, tvb, offset, 1, "Error:Spare bits not 0");
+ octet = (tvb_get_guint8(tvb,offset) & 0xf0) >> 4;
+ if (octet == AMR_WB_SID){
+  proto_tree_add_item(tree, hf_amr_wb_if1_mode_req, tvb, offset+1, 1, FALSE);
   proto_tree_add_text(tree, tvb, offset+2, 4, "Speech data");
   proto_tree_add_item(tree, hf_amr_if1_sti, tvb, offset+7, 1, FALSE);
-  proto_tree_add_item(tree, hf_amr_if1_sti_mode_ind, tvb, offset+7, 1, FALSE);
+  proto_tree_add_item(tree, hf_amr_wb_if1_sti_mode_ind, tvb, offset+7, 1, FALSE);
   return;
  }
 
- proto_tree_add_item(tree, hf_amr_if1_mode_ind, tvb, offset, 1, FALSE);
  offset++;
- proto_tree_add_item(tree, hf_amr_if1_mode_req, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_amr_wb_if1_mode_ind, tvb, offset, 1, FALSE);
+ proto_tree_add_item(tree, hf_amr_wb_if1_mode_req, tvb, offset, 1, FALSE);
  offset++;
  proto_tree_add_text(tree, tvb, offset, -1, "Speech data");
 
+
 }
 
 static void
-dissect_amr_if2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree){
+dissect_amr_nb_if2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree){
  int offset =0;
  guint8 octet;
-
- proto_tree_add_item(tree, hf_amr_if2_ft, tvb, offset, 1, FALSE);
+ 
+ proto_tree_add_item(tree, hf_amr_nb_if2_ft, tvb, offset, 1, FALSE);
  octet = tvb_get_guint8(tvb,offset) & 0x0f;
- if (octet == AMR_SID){
+ 
+ if (octet == AMR_NB_SID) {
   proto_tree_add_text(tree, tvb, offset+1, 3, "Speech data");
-  proto_tree_add_item(tree, hf_amr_sti, tvb, offset+4, 1, FALSE);
-  proto_tree_add_item(tree, hf_amr_if2_ft, tvb, offset+5, 1, FALSE);
+  proto_tree_add_item(tree, hf_amr_if2_sti, tvb, offset+4, 1, FALSE);
+  proto_tree_add_item(tree, hf_amr_nb_if2_sti_mode_ind, tvb, offset+5, 1, FALSE);
   return;
  }
  if (octet == AMR_NO_TRANS)
@@ -179,51 +287,123 @@
 
  if(check_col(pinfo->cinfo, COL_INFO))
   col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
-   val_to_str(octet, amr_codec_mode_request_vals, "Unknown (%d)" ));
+   val_to_str(octet, amr_nb_codec_mode_request_vals, "Unknown (%d)" ));
 }
-/*
- * 4.3.5.1. Single Channel Payload Carrying a Single Frame
- * 
- *    The following diagram shows a bandwidth-efficient AMR payload from a
- *    single channel session carrying a single speech frame-block.
- * 
- *    In the payload, no specific mode is requested (CMR=15), the speech
- *    frame is not damaged at the IP origin (Q=1), and the coding mode is
- *    AMR 7.4 kbps (FT=4).  The encoded speech bits, d(0) to d(147), are
- *    arranged in descending sensitivity order according to [2].  Finally,
- *    two zero bits are added to the end as padding to make the payload
- *    octet aligned.
- * 
- *     0                   1                   2                   3
- *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *    | CMR=15|0| FT=4  |1|d(0)                                       |
- *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
+
 static void
-dissect_amr_be(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree){
- proto_item *item;
+dissect_amr_wb_if2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree){
+ int offset =0;
  guint8 octet;
- int offset =0;
-
- proto_tree_add_item(tree, hf_amr_cmr, tvb, offset, 1, FALSE);
- proto_tree_add_item(tree, hf_amr_be_reserved, tvb, offset, 1, FALSE);
- octet = tvb_get_guint8(tvb,offset) & 0x08;
- if ( octet != 0  ){
-  item = proto_tree_add_text(tree, tvb, offset, -1, "Reserved != 0, wrongly encoded or not bandwidth-efficient.");
-  PROTO_ITEM_SET_GENERATED(item);
+ 
+ proto_tree_add_item(tree, hf_amr_wb_if2_ft, tvb, offset, 1, FALSE);
+ octet = (tvb_get_guint8(tvb,offset) & 0xf0) >> 4;
+ 
+ if (octet == AMR_WB_SID) {
+  proto_tree_add_text(tree, tvb, offset+1, 4, "Speech data");
+  proto_tree_add_item(tree, hf_amr_if2_sti, tvb, offset+5, 1, FALSE);
+  proto_tree_add_item(tree, hf_amr_wb_if2_sti_mode_ind, tvb, offset+5, 1, FALSE);
   return;
  }
- proto_tree_add_item(tree, hf_amr_be_ft, tvb, offset, 2, FALSE);
- proto_tree_add_item(tree, hf_amr_be_reserved2, tvb, offset, 2, FALSE);
- offset++;
- octet = tvb_get_guint8(tvb,offset) & 0x40;
- if ( octet != 0x40  ){
-  item = proto_tree_add_text(tree, tvb, offset, -1, "Reserved != 1, wrongly encoded or not bandwidth-efficient.");
-  PROTO_ITEM_SET_GENERATED(item);
+ if (octet == AMR_NO_TRANS)
   return;
- }
+ proto_tree_add_text(tree, tvb, offset+1, -1, "Speech data");
+
+ if(check_col(pinfo->cinfo, COL_INFO))
+  col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
+   val_to_str(octet, amr_wb_codec_mode_request_vals, "Unknown (%d)" ));
+}
+
+static void
+dissect_amr_be(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree){
+ proto_item *item;
+ int ft;
+ int bitcount; /*bitcounter, MSB = bit 0, over bytes*/
+ int bits_used_for_frames =0;
+ int bytes_needed_for_frames;
+ gboolean frame_following;
+ guint16 unit16val;
  
+        /* Number of bits per frame for AMR-NB, see Table 1 RFC3267*/
+ /* Values taken for GSM-EFR SID, TDMA-EFR SID and PDC-EFR SID from 3GPP 26.101 Table A.1b */
+
+ /*               Frame type     0   1   2   3   4   5   6   7  8  9  10 11 12 13 14 15 */
+ unsigned char Framebits_NB[] = {95,103,118,134,148,159,204,244,39,43,38,37, 0, 0, 0, 0};
+ 
+ /* Number of bits per frame for AMR-WB, see 3GPP TS 26.201 Table 2*/
+ /*               Frame type     0   1   2   3   4   5   6   7   8   9  10 11 12 13 14 15 */
+ unsigned int Framebits_WB[] = {132,177,253,285,317,365,397,461,477,40,0, 0, 0, 0, 0, 0,};
+
+ 
+ /* Chapter 4.3 */
+ bitcount =3;
+ if (amr_mode==AMR_NB)
+     item = proto_tree_add_item(tree, hf_amr_nb_cmr, tvb, bitcount/8, 1, FALSE);
+ else    
+     item = proto_tree_add_item(tree, hf_amr_wb_cmr, tvb, bitcount/8, 1, FALSE); 
+     
+ do {
+  /* Check F bit */
+  bitcount +=1;
+  frame_following = tvb_get_guint8(tvb,bitcount/8) & 0x80 >> (bitcount % 8);
+  unit16val = tvb_get_ntohs(tvb,bitcount/8);
+  ft = (unit16val >> (11 - (bitcount % 8)))  &0x000F;
+  if (amr_mode==AMR_NB)
+      item = proto_tree_add_text(tree, tvb, bitcount/8, 1+(bitcount % 8)/5, 
+       amr_nb_codec_mode_request_vals[ft].strptr);
+  else
+      item = proto_tree_add_text(tree, tvb, bitcount/8, 1+(bitcount % 8)/5, 
+       amr_wb_codec_mode_request_vals[ft].strptr);
+           
+  bitcount +=4;
+  if (amr_mode==AMR_NB)
+      bits_used_for_frames +=Framebits_NB[ft];
+  else    
+      bits_used_for_frames +=Framebits_WB[ft];
+  /* Check Q bit */
+  bitcount +=1;
+  if (tvb_get_guint8(tvb,bitcount/8) & 0x80 >> (bitcount %8))
+      proto_item_append_text(item, " / Frame OK");
+  else    
+      proto_item_append_text(item, " / Frame damaged");
+ } while ((frame_following) && (tvb_reported_length_remaining(tvb, bitcount/8)>2));
+ 
+ if (bits_used_for_frames>0)
+         bytes_needed_for_frames = 1 + (bitcount+bits_used_for_frames)/8-bitcount/8;
+ else     
+     bytes_needed_for_frames = 0;
+
+ /* Check if we have enough data available for our frames */    
+ if (tvb_reported_length_remaining(tvb, bitcount/8)<bytes_needed_for_frames) {
+     item = proto_tree_add_text(tree, tvb, bitcount/8, bytes_needed_for_frames, "Error:");
+     proto_item_append_text(item, " %d Bytes available, %d would be needed!",
+        tvb_reported_length_remaining(tvb, bitcount/8),
+        bytes_needed_for_frames);
+     expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Not enough data for the frames according to TOC");
+ }       
+ else {
+     item = proto_tree_add_text(tree, tvb, bitcount/8, bytes_needed_for_frames, "Frame Data");
+     proto_item_append_text(item, " (%d Bytes)",bytes_needed_for_frames);
+ }    
+ 
+ bitcount+=bits_used_for_frames;
+ 
+ if (tvb_reported_length_remaining(tvb, (bitcount+8)/8)>0) {
+     item = proto_tree_add_text(tree, tvb, bitcount/8, tvb_reported_length_remaining(tvb, bitcount/8), "Error:");
+     proto_item_append_text(item, " %d Bytes remaining - should be 0!",tvb_reported_length_remaining(tvb, (bitcount+8)/8));
+     expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Superflous data remaining");
+
+     /* Now check the paddings */
+     if (bitcount%8 !=0) {
+  if ( (1 << (8 -(bitcount%8)-1)) & tvb_get_guint8(tvb,bitcount/8) )
+      item = proto_tree_add_text(tree, tvb, bitcount/8, 1, "Padding bits correct");
+  else {
+      item = proto_tree_add_text(tree, tvb, bitcount/8, 1, "Padding bits error");
+      expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Padding bits error - MUST be 0");
+  }    
+
+     }     
+ }    
+ 
 }
 /* Code to actually dissect the packets */
 static void
@@ -247,7 +427,8 @@
   ti = proto_tree_add_item(tree, proto_amr, tvb, 0, -1, FALSE);
   amr_tree = proto_item_add_subtree(ti, ett_amr);
 
-  proto_tree_add_text(amr_tree, tvb, offset, -1, "Payload decoded as %s",val_to_str(amr_encoding_type, amr_encoding_type_value, "Unknown value - Error"));
+  proto_tree_add_text(amr_tree, tvb, offset, -1, "Payload decoded as %s",
+      val_to_str(amr_encoding_type, amr_encoding_type_value, "Unknown value - Error"));
 
   switch (amr_encoding_type){
   case 0: /* RFC 3267 Byte aligned */
@@ -256,18 +437,26 @@
    dissect_amr_be(tvb, pinfo, amr_tree);
    return;
   case 2: /* AMR IF1 */
-   dissect_amr_if1(tvb, pinfo, amr_tree);
+   if (amr_mode==AMR_NB)
+       dissect_amr_nb_if1(tvb, pinfo, amr_tree);
+   else
+       dissect_amr_wb_if1(tvb, pinfo, amr_tree);    
    return;
   case 3: /* AMR IF2 */
-   dissect_amr_if2(tvb, pinfo, amr_tree);
+   if (amr_mode==AMR_NB)
+       dissect_amr_nb_if2(tvb, pinfo, amr_tree);
+   else
+       dissect_amr_wb_if2(tvb, pinfo, amr_tree);    
    return;
   default:
    break;
   }
-
-
-
-  proto_tree_add_item(amr_tree, hf_amr_cmr, tvb, offset, 1, FALSE);
+  
+  if (amr_mode==AMR_NB)
+      proto_tree_add_item(amr_tree, hf_amr_nb_cmr, tvb, offset, 1, FALSE);
+  else
+      proto_tree_add_item(amr_tree, hf_amr_wb_cmr, tvb, offset, 1, FALSE);    
+      
   octet = tvb_get_guint8(tvb,offset) & 0x0f;
   if ( octet != 0  ){
    item = proto_tree_add_text(amr_tree, tvb, offset, -1, "Reserved != 0, wrongly encoded or not octet aligned. Decoding as bandwidth-efficient mode");
@@ -304,7 +493,10 @@
    first_time = FALSE;
    octet = tvb_get_guint8(tvb,offset); 
    proto_tree_add_item(amr_tree, hf_amr_toc_f, tvb, offset, 1, FALSE);
-   proto_tree_add_item(amr_tree, hf_amr_toc_ft, tvb, offset, 1, FALSE);
+   if (amr_mode==AMR_NB)
+       proto_tree_add_item(amr_tree, hf_amr_nb_toc_ft, tvb, offset, 1, FALSE);
+   else
+       proto_tree_add_item(amr_tree, hf_amr_wb_toc_ft, tvb, offset, 1, FALSE);    
    proto_tree_add_item(amr_tree, hf_amr_toc_q, tvb, offset, 1, FALSE);
    offset++;
   }
@@ -340,6 +532,10 @@
   dissector_add("rtp.pt", dynamic_payload_type, amr_handle);
  }
  dissector_add_string("rtp_dyn_payload_type","AMR", amr_handle);
+ 
+/* Activate the next line for testing with the randpkt tool
+ dissector_add("udp.port", 55555, amr_handle); 
+*/
 
 }
 
@@ -355,11 +551,16 @@
 
 /* Setup list of header fields  See Section 1.6.1 for details*/
  static hf_register_info hf[] = {
-  { &hf_amr_cmr,
-   { "CMR",           "amr.cmr",
-   FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0xf0,          
+  { &hf_amr_nb_cmr,
+   { "CMR",           "amr_nb.cmr",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_request_vals), 0xf0,          
    "codec mode request", HFILL }
   },
+  { &hf_amr_wb_cmr,
+   { "CMR",           "amr_wb.cmr",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_request_vals), 0xf0,          
+   "codec mode request", HFILL }
+  },
   { &hf_amr_reserved,
    { "Reserved",           "amr.reserved",
    FT_UINT8, BASE_DEC, NULL, 0x0f,          
@@ -370,71 +571,96 @@
    FT_BOOLEAN, 8, TFS(&toc_f_bit_vals), 0x80,          
    "F bit", HFILL }
   },
-  { &hf_amr_toc_ft,
-   { "FT bits",           "amr.toc.ft",
-   FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0x78,          
+  { &hf_amr_nb_toc_ft,
+   { "FT bits",           "amr_nb.toc.ft",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_request_vals), 0x78,          
    "Frame type index", HFILL }
   },
+  { &hf_amr_wb_toc_ft,
+   { "FT bits",           "amr_wb.toc.ft",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_request_vals), 0x78,          
+   "Frame type index", HFILL }
+  },
   { &hf_amr_toc_q,
    { "Q bit",           "amr.toc.q",
    FT_BOOLEAN, 8, TFS(&toc_q_bit_vals), 0x04,          
    "Frame quality indicator bit", HFILL }
   },
-  { &hf_amr_if1_ft,
-   { "Frame Type",           "amr.if1.ft",
-   FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0xf0,          
+  { &hf_amr_nb_if1_ft,
+   { "Frame Type",           "amr_nb.if1.ft",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_vals), 0xf0,          
    "Frame Type", HFILL }
   },
-  { &hf_amr_if1_mode_req,
-   { "Mode Type request",           "amr.if1.modereq",
-   FT_UINT8, BASE_DEC, VALS(amr_codec_mode_vals), 0xe0,          
+  { &hf_amr_wb_if1_ft,
+   { "Frame Type",           "amr_wb.if1.ft",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_vals), 0xf0,          
+   "Frame Type", HFILL }
+  },
+  { &hf_amr_nb_if1_mode_req,
+   { "Mode Type request",           "amr_nb.if1.modereq",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_request_vals), 0xe0,
    "Mode Type request", HFILL }
   },
+  { &hf_amr_wb_if1_mode_req,
+   { "Mode Type request",           "amr_wb.if1.modereq",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_request_vals), 0x0f,
+   "Mode Type request", HFILL }
+  },
   { &hf_amr_if1_sti,
    { "SID Type Indicator",           "amr.if1.sti",
    FT_BOOLEAN, 8, TFS(&amr_sti_vals), 0x10,          
    "SID Type Indicator", HFILL }
   },
-  { &hf_amr_if1_sti_mode_ind,
-   { "Mode Type indication",           "amr.if1.modereq",
-   FT_UINT8, BASE_DEC, VALS(amr_codec_mode_vals), 0x0e,          
+  { &hf_amr_nb_if1_sti_mode_ind,
+   { "Mode Type indication",           "amr_nb.if1.stimodeind",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_vals), 0x0e,
    "Mode Type indication", HFILL }
   },
-  { &hf_amr_if1_mode_ind,
-   { "Mode Type indication",           "amr.if1.modereq",
-   FT_UINT8, BASE_DEC, VALS(amr_codec_mode_vals), 0x07,          
+  { &hf_amr_wb_if1_sti_mode_ind,
+   { "Mode Type indication",           "amr_wb.if1.stimodeind",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_vals), 0x0f,
    "Mode Type indication", HFILL }
   },
-  { &hf_amr_if2_ft,
-   { "Frame Type",           "amr.if2.ft",
-   FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0x0f,          
+  { &hf_amr_nb_if1_mode_ind,
+   { "Mode Type indication",           "amr_nb.if1.modeind",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_vals), 0x07,
+   "Mode Type indication", HFILL }
+  },
+  { &hf_amr_wb_if1_mode_ind,
+   { "Mode Type indication",           "amr_wb.if1.modeind",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_vals), 0xf0,
+   "Mode Type indication", HFILL }
+  },
+  { &hf_amr_nb_if2_ft,
+   { "Frame Type",           "amr_nb.if2.ft",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_vals), 0x0f,
    "Frame Type", HFILL }
   },
-  { &hf_amr_sti,
-   { "SID Type Indicator",           "amr.sti",
+  { &hf_amr_wb_if2_ft,
+   { "Frame Type",           "amr_wb.if2.ft",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_vals), 0xf0,
+   "Frame Type", HFILL }
+  },
+  { &hf_amr_if2_sti,
+   { "SID Type Indicator",           "amr.if2.sti",
    FT_BOOLEAN, 8, TFS(&amr_sti_vals), 0x80,          
    "SID Type Indicator", HFILL }
   },
+  { &hf_amr_nb_if2_sti_mode_ind,
+   { "Mode Type indication",           "amr_nb.if2.stimodeind",
+   FT_UINT8, BASE_DEC, VALS(amr_nb_codec_mode_vals), 0x07,
+   "Mode Type indication", HFILL }
+  },
+  { &hf_amr_wb_if2_sti_mode_ind,
+   { "Mode Type indication",           "amr_wb.if2.stimodeind",
+   FT_UINT8, BASE_DEC, VALS(amr_wb_codec_mode_vals), 0x78,
+   "Mode Type indication", HFILL }
+  },
   { &hf_amr_if1_fqi,
    { "FQI",           "amr.fqi",
    FT_BOOLEAN, 8, TFS(&toc_q_bit_vals), 0x08,          
    "Frame quality indicator bit", HFILL }
   },
-  { &hf_amr_be_reserved,
-   { "Reserved",           "amr.be.reserved",
-   FT_UINT8, BASE_DEC, NULL, 0x08,          
-   "Reserved", HFILL }
-  },
-  { &hf_amr_be_ft,
-   { "Frame Type",           "amr.be.ft",
-   FT_UINT16, BASE_DEC, VALS(amr_codec_mode_request_vals), 0x0780,          
-   "Frame Type", HFILL }
-  },
-  { &hf_amr_be_reserved2,
-   { "Reserved",           "amr.be.reserved2",
-   FT_UINT16, BASE_DEC, NULL, 0x0040,          
-   "Reserved", HFILL }
-  },
  };
 
 /* Setup protocol subtree array */
@@ -450,6 +676,12 @@
  {NULL, NULL, -1}
     };
 
+    static enum_val_t modes[] = {
+ {"AMR-NB", "Narrowband AMR", AMR_NB},
+ {"AMR-WB", "Wideband AMR", AMR_WB}, 
+ {NULL, NULL, -1}
+    };
+
 /* Register the protocol name and description */
  proto_amr = proto_register_protocol("Adaptive Multi-Rate","AMR", "amr");
 
@@ -471,10 +703,17 @@
       "Type of AMR encoding of the payload",
       "Type of AMR encoding of the payload",
       &amr_encoding_type, encoding_types, FALSE);
+
+    prefs_register_enum_preference(amr_module, "mode",
+      "The AMR mode",
+      "The AMR mode",
+      &amr_mode, modes, AMR_NB);
  
  register_dissector("amr", dissect_amr, proto_amr);
- register_dissector("amr_if1", dissect_amr_if1, proto_amr);
- register_dissector("amr_if2", dissect_amr_if2, proto_amr);
+ register_dissector("amr_if1_nb", dissect_amr_nb_if1, proto_amr);
+ register_dissector("amr_if1_wb", dissect_amr_wb_if1, proto_amr);
+ register_dissector("amr_if2_nb", dissect_amr_nb_if2, proto_amr);
+ register_dissector("amr_if2_wb", dissect_amr_wb_if2, proto_amr);
+ 
+
 }
-
-