494c4fd330e7eb3bc62ea60b6b2225f5f5b63fc2
[obnox/wireshark/wip.git] / epan / dissectors / packet-amr.c
1 /* packet-amr.c
2  * Routines for AMR dissection
3  * Copyright 2005, Anders Broman <anders.broman[at]ericsson.com>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  *
25  * References:
26  * RFC 3267 
27  * http://www.ietf.org/rfc/rfc3267.txt?number=3267
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <glib.h>
39
40 #include <epan/packet.h>
41 #include <epan/proto.h>
42
43 #include "prefs.h"
44
45 #define AMR_SID 8
46 #define AMR_NO_TRANS 15
47
48 /* Initialize the protocol and registered fields */
49 static int proto_amr            = -1;
50 static int hf_amr_cmr           = -1;
51 static int hf_amr_reserved      = -1;
52 static int hf_amr_toc_f         = -1;
53 static int hf_amr_toc_ft        = -1;
54 static int hf_amr_toc_q         = -1;
55 static int hf_amr_toc_f_unaligned1 = -1;
56 static int hf_amr_toc_ft_unaligned1 = -1;
57 static int hf_amr_toc_q_unaligned1 = -1;
58 static int hf_amr_toc_f_unaligned2 = -1;
59 static int hf_amr_toc_ft_unaligned2 = -1;
60 static int hf_amr_toc_q_unaligned2 = -1;
61
62 static int hf_amr_if1_ft = -1;
63 static int hf_amr_if1_fqi = -1;
64 static int hf_amr_if1_mode_req = -1;
65 static int hf_amr_if1_sti = -1;
66 static int hf_amr_if1_mode_ind = -1;
67 static int hf_amr_if1_sti_mode_ind = -1;
68 static int hf_amr_sti = -1;
69
70 static int hf_amr_if2_ft = -1;
71
72
73 /* Initialize the subtree pointers */
74 static int ett_amr = -1;
75 static int ett_amr_toc = -1;
76
77 /* The dynamic payload type which will be dissected as AMR */
78
79 static guint dynamic_payload_type = 0;
80 static guint temp_dynamic_payload_type = 0;
81 gint amr_encoding_type = 0;
82
83 /* Currently only octet aligned works */
84 /* static gboolean octet_aligned = TRUE; */
85
86 static const value_string amr_encoding_type_value[] = {
87         {0,                     "RFC 3267"}, 
88         {1,                     "RFC 3267 bandwidth-efficient mode"}, /* Not coded */
89         {2,                     "AMR IF 1"},
90         {3,                     "AMR IF 2"},
91         { 0,    NULL }
92 };
93
94 static const value_string amr_codec_mode_vals[] = {
95         {0,                     "AMR 4,75 kbit/s"}, 
96         {1,                     "AMR 5,15 kbit/s"},
97         {2,                     "AMR 5,90 kbit/s"},
98         {3,                     "AMR 6,70 kbit/s (PDC-EFR)"},
99         {4,                     "AMR 7,40 kbit/s (TDMA-EFR)"},
100         {5,                     "AMR 7,95 kbit/s"},
101         {6,                     "AMR 10,2 kbit/s"},
102         {7,                     "AMR 12,2 kbit/s (GSM-EFR)"},
103         { 0,    NULL }
104 };
105
106 static const value_string amr_codec_mode_request_vals[] = {
107         {0,                     "AMR 4,75 kbit/s"}, 
108         {1,                     "AMR 5,15 kbit/s"},
109         {2,                     "AMR 5,90 kbit/s"},
110         {3,                     "AMR 6,70 kbit/s (PDC-EFR)"},
111         {4,                     "AMR 7,40 kbit/s (TDMA-EFR)"},
112         {5,                     "AMR 7,95 kbit/s"},
113         {6,                     "AMR 10,2 kbit/s"},
114         {7,                     "AMR 12,2 kbit/s (GSM-EFR)"},
115         {AMR_SID,       "AMR SID"},
116         {9,                     "GSM-EFR SID"},
117         {10,            "TDMA-EFR SID"},
118         {11,            "PDC-EFR SID"},
119         /*
120         {12-14  -       -       For future use
121         */
122         {AMR_NO_TRANS,  "No Data (No transmission/No reception)"}, 
123         { 0,    NULL }
124 };
125
126 static const true_false_string toc_f_bit_vals = {
127   "Followed by another speech frame",
128   "Last frame in this payload"
129 };
130
131 static const true_false_string toc_q_bit_vals = {
132   "Ok",
133   "Severely damaged frame"
134 };
135
136 static const true_false_string amr_sti_vals = {
137   "SID_UPDATE",
138   "SID_FIRST"
139 };
140 static void
141 dissect_amr_if1(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree){
142         int offset =0;
143         guint8 octet;
144
145         proto_tree_add_item(tree, hf_amr_if1_ft, tvb, offset, 1, FALSE);
146         proto_tree_add_item(tree, hf_amr_if1_fqi, tvb, offset, 1, FALSE);
147         octet = tvb_get_guint8(tvb,offset) & 0x0f;
148         if (octet == AMR_SID){
149                 proto_tree_add_item(tree, hf_amr_if1_mode_req, tvb, offset+1, 1, FALSE);
150                 proto_tree_add_text(tree, tvb, offset+2, 4, "Speech data");
151                 proto_tree_add_item(tree, hf_amr_if1_sti, tvb, offset+7, 1, FALSE);
152                 proto_tree_add_item(tree, hf_amr_if1_sti_mode_ind, tvb, offset+7, 1, FALSE);
153                 return;
154         }
155
156         proto_tree_add_item(tree, hf_amr_if1_mode_ind, tvb, offset, 1, FALSE);
157         offset++;
158         proto_tree_add_item(tree, hf_amr_if1_mode_req, tvb, offset, 1, FALSE);
159         offset++;
160         proto_tree_add_text(tree, tvb, offset, -1, "Speech data");
161
162 }
163
164 static void
165 dissect_amr_if2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree){
166         int offset =0;
167         guint8 octet;
168
169         proto_tree_add_item(tree, hf_amr_if2_ft, tvb, offset, 1, FALSE);
170         octet = tvb_get_guint8(tvb,offset) & 0x0f;
171         if (octet == AMR_SID){
172                 proto_tree_add_text(tree, tvb, offset+1, 3, "Speech data");
173                 proto_tree_add_item(tree, hf_amr_sti, tvb, offset+4, 1, FALSE);
174                 proto_tree_add_item(tree, hf_amr_if2_ft, tvb, offset+5, 1, FALSE);
175                 return;
176         }
177         if (octet == AMR_NO_TRANS)
178                 return;
179         proto_tree_add_text(tree, tvb, offset+1, -1, "Speech data");
180
181         if(check_col(pinfo->cinfo, COL_INFO))
182                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
183                         val_to_str(octet, amr_codec_mode_request_vals, "Unknown (%d)" ));
184 }
185
186 /* Code to actually dissect the packets */
187 static void
188 dissect_amr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
189 {
190         int offset = 0;
191         int toc_offset = 0;
192         guint8 octet;
193         proto_item *item;
194
195 /* Set up structures needed to add the protocol subtree and manage it */
196         proto_item *ti,*toc_item;
197         proto_tree *amr_tree, *toc_tree;
198
199 /* Make entries in Protocol column and Info column on summary display */
200         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
201                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "AMR");
202         if (tree) {
203
204                 ti = proto_tree_add_item(tree, proto_amr, tvb, 0, -1, FALSE);
205                 amr_tree = proto_item_add_subtree(ti, ett_amr);
206
207                 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"));
208
209                 switch (amr_encoding_type){
210                 case 0:
211                 case 1:
212                         break;
213                 case 2: /* AMR IF1 */
214                         dissect_amr_if1(tvb, pinfo, amr_tree);
215                         return;
216                 case 3: /* AMR IF2 */
217                         dissect_amr_if2(tvb, pinfo, amr_tree);
218                         return;
219                 default:
220                         break;
221                 }
222
223
224
225                 proto_tree_add_item(amr_tree, hf_amr_cmr, tvb, offset, 1, FALSE);
226                 octet = tvb_get_guint8(tvb,offset) & 0x0f;
227                 if ( octet != 0  ){
228                         item = proto_tree_add_text(amr_tree, tvb, offset, -1, "Reserved != 0, wrongly encoded or not octet aligned. Decoding as bandwidth-efficient mode");
229                         PROTO_ITEM_SET_GENERATED(item);
230                         if (!tvb_length_remaining(tvb,offset))
231                                 return;
232                         /*     0 1 2 3 4 5
233                          *   +-+-+-+-+-+-+
234                          *   |F|  FT   |Q|
235                          *   +-+-+-+-+-+-+
236                          */
237
238                         toc_item = proto_tree_add_text(amr_tree, tvb, offset, -1, "Payload Table of Contents");
239                         toc_tree = proto_item_add_subtree(toc_item, ett_amr_toc);
240
241                         proto_tree_add_item(amr_tree, hf_amr_toc_f_unaligned1, tvb, offset, 2, FALSE);
242                         proto_tree_add_item(amr_tree, hf_amr_toc_ft_unaligned1, tvb, offset, 2, FALSE);
243                         proto_tree_add_item(amr_tree, hf_amr_toc_q_unaligned1, tvb, offset, 2, FALSE);
244                         if (octet & 0x04)
245                                 return;
246                         octet = tvb_get_guint8(tvb,offset+1);
247                         proto_tree_add_item(amr_tree, hf_amr_toc_f_unaligned2, tvb, offset, 2, FALSE);
248                         proto_tree_add_item(amr_tree, hf_amr_toc_ft_unaligned2, tvb, offset, 2, FALSE);
249                         proto_tree_add_item(amr_tree, hf_amr_toc_q_unaligned2, tvb, offset, 2, FALSE);
250                         if (octet & 0x20)
251                                 return;
252                         return;
253                 }
254
255                 proto_tree_add_item(amr_tree, hf_amr_reserved, tvb, offset, 1, FALSE);
256                 offset++;
257                 toc_offset = offset;
258                 /* If interleaced ILL and ILP follows here */
259
260                 /* Payload Table of Contents 
261                  * A ToC entry takes the following format in octet-aligned mode:
262                  *
263                  *  0 1 2 3 4 5 6 7
264                  * +-+-+-+-+-+-+-+-+
265                  * |F|  FT   |Q|P|P|
266                  * +-+-+-+-+-+-+-+-+
267                  */
268                 octet = tvb_get_guint8(tvb,offset);
269                 toc_item = proto_tree_add_text(amr_tree, tvb, offset, -1, "Payload Table of Contents");
270                 toc_tree = proto_item_add_subtree(toc_item, ett_amr_toc);
271
272                 while ( ( octet& 0x80 ) == 0x80 ){
273                         octet = tvb_get_guint8(tvb,offset);     
274                         proto_tree_add_item(amr_tree, hf_amr_toc_f, tvb, offset, 1, FALSE);
275                         proto_tree_add_item(amr_tree, hf_amr_toc_ft, tvb, offset, 1, FALSE);
276                         proto_tree_add_item(amr_tree, hf_amr_toc_q, tvb, offset, 1, FALSE);
277                         offset++;
278                 }
279
280         }/* if tree */
281
282 }
283
284
285 /* Register the protocol with Ethereal */
286 /* If this dissector uses sub-dissector registration add a registration routine.
287    This format is required because a script is used to find these routines and
288    create the code that calls these routines.
289 */
290 void
291 proto_reg_handoff_amr(void)
292 {
293         dissector_handle_t amr_handle;
294         static int amr_prefs_initialized = FALSE;
295         
296         amr_handle = create_dissector_handle(dissect_amr, proto_amr);
297
298         if (!amr_prefs_initialized) {
299                 amr_prefs_initialized = TRUE;
300           }
301         else {
302                         if ( dynamic_payload_type > 95 )
303                                 dissector_delete("rtp.pt", dynamic_payload_type, amr_handle);
304         }
305         dynamic_payload_type = temp_dynamic_payload_type;
306
307         if ( dynamic_payload_type > 95 ){
308                 dissector_add("rtp.pt", dynamic_payload_type, amr_handle);
309         }
310         dissector_add_string("rtp_dyn_payload_type","AMR", amr_handle);
311
312 }
313
314 /* this format is require because a script is used to build the C function
315    that calls all the protocol registration.
316 */
317
318 void
319 proto_register_amr(void)
320 {                 
321
322         module_t *amr_module;
323
324 /* Setup list of header fields  See Section 1.6.1 for details*/
325         static hf_register_info hf[] = {
326                 { &hf_amr_cmr,
327                         { "CMR",           "amr.cmr",
328                         FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0xf0,          
329                         "codec mode request", HFILL }
330                 },
331                 { &hf_amr_reserved,
332                         { "Reserved",           "amr.reserved",
333                         FT_UINT8, BASE_DEC, NULL, 0x0f,          
334                         "Reserved bits", HFILL }
335                 },
336                 { &hf_amr_toc_f,
337                         { "F bit",           "amr.toc.f",
338                         FT_BOOLEAN, 8, TFS(&toc_f_bit_vals), 0x80,          
339                         "F bit", HFILL }
340                 },
341                 { &hf_amr_toc_ft,
342                         { "FT bits",           "amr.toc.ft",
343                         FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0x78,          
344                         "FT bits", HFILL }
345                 },
346                 { &hf_amr_toc_q,
347                         { "Q bit",           "amr.toc.q",
348                         FT_BOOLEAN, 8, TFS(&toc_q_bit_vals), 0x04,          
349                         "Frame quality indicator bit", HFILL }
350                 },
351                 { &hf_amr_toc_f_unaligned1,
352                         { "F bit",           "amr.toc.f.ual1",
353                         FT_BOOLEAN, 16, TFS(&toc_f_bit_vals), 0x0800,          
354                         "F bit", HFILL }
355                 },
356                 { &hf_amr_toc_ft_unaligned1,
357                         { "FT bits",           "amr.toc.ft.ual1",
358                         FT_UINT16, BASE_DEC, VALS(amr_codec_mode_request_vals), 0x0780,          
359                         "FT bits", HFILL }
360                 },
361                 { &hf_amr_toc_q_unaligned1,
362                         { "Q bit",           "amr.toc.ua1.q.ual1",
363                         FT_BOOLEAN, 16, TFS(&toc_q_bit_vals), 0x0040,          
364                         "Frame quality indicator bit", HFILL }
365                 },
366                 { &hf_amr_toc_f_unaligned2,
367                         { "F bit",           "amr.toc.f.ual2",
368                         FT_BOOLEAN, 16, TFS(&toc_f_bit_vals), 0x0020,          
369                         "F bit", HFILL }
370                 },
371                 { &hf_amr_toc_ft_unaligned2,
372                         { "FT bits",           "amr.toc.ft.ual2",
373                         FT_UINT16, BASE_DEC, VALS(amr_codec_mode_request_vals), 0x001e,          
374                         "FT bits", HFILL }
375                 },
376                 { &hf_amr_toc_q_unaligned2,
377                         { "Q bit",           "amr.toc.ua1.q.ual2",
378                         FT_BOOLEAN, 16, TFS(&toc_q_bit_vals), 0x00001,          
379                         "Frame quality indicator bit", HFILL }
380                 },
381                 { &hf_amr_if1_ft,
382                         { "Frame Type",           "amr.if1.ft",
383                         FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0xf0,          
384                         "Frame Type", HFILL }
385                 },
386                 { &hf_amr_if1_mode_req,
387                         { "Mode Type request",           "amr.if1.modereq",
388                         FT_UINT8, BASE_DEC, VALS(amr_codec_mode_vals), 0xe0,          
389                         "Mode Type request", HFILL }
390                 },
391                 { &hf_amr_if1_sti,
392                         { "SID Type Indicator",           "amr.if1.sti",
393                         FT_BOOLEAN, 8, TFS(&amr_sti_vals), 0x10,          
394                         "SID Type Indicator", HFILL }
395                 },
396                 { &hf_amr_if1_sti_mode_ind,
397                         { "Mode Type indication",           "amr.if1.modereq",
398                         FT_UINT8, BASE_DEC, VALS(amr_codec_mode_vals), 0x0e,          
399                         "Mode Type indication", HFILL }
400                 },
401                 { &hf_amr_if1_mode_ind,
402                         { "Mode Type indication",           "amr.if1.modereq",
403                         FT_UINT8, BASE_DEC, VALS(amr_codec_mode_vals), 0x07,          
404                         "Mode Type indication", HFILL }
405                 },
406                 { &hf_amr_if2_ft,
407                         { "Frame Type",           "amr.if2.ft",
408                         FT_UINT8, BASE_DEC, VALS(amr_codec_mode_request_vals), 0x0f,          
409                         "Frame Type", HFILL }
410                 },
411                 { &hf_amr_sti,
412                         { "SID Type Indicator",           "amr.sti",
413                         FT_BOOLEAN, 8, TFS(&amr_sti_vals), 0x80,          
414                         "SID Type Indicator", HFILL }
415                 },
416                 { &hf_amr_if1_fqi,
417                         { "FQI",           "amr.fqi",
418                         FT_BOOLEAN, 8, TFS(&toc_q_bit_vals), 0x08,          
419                         "Frame quality indicator bit", HFILL }
420                 },
421         };
422
423 /* Setup protocol subtree array */
424         static gint *ett[] = {
425                 &ett_amr,
426                 &ett_amr_toc,
427         };
428     static enum_val_t encoding_types[] = {
429         {"RFC 3267 Byte aligned", "RFC 3267", 0},
430         {"AMR IF1", "AMR IF1", 2},
431         {"AMR IF2", "AMR IF2", 3},
432         {NULL, NULL, -1}
433     };
434
435 /* Register the protocol name and description */
436         proto_amr = proto_register_protocol("Adaptive Multi-Rate","AMR", "amr");
437
438 /* Required function calls to register the header fields and subtrees used */
439         proto_register_field_array(proto_amr, hf, array_length(hf));
440         proto_register_subtree_array(ett, array_length(ett));
441         /* Register a configuration option for port */
442
443         
444         amr_module = prefs_register_protocol(proto_amr, proto_reg_handoff_amr);
445
446         prefs_register_uint_preference(amr_module, "dynamic.payload.type",
447                                                                    "AMR dynamic payload type",
448                                                                    "The dynamic payload type which will be interpreted as AMR",
449                                                                    10,
450                                                                    &temp_dynamic_payload_type);
451
452     prefs_register_enum_preference(amr_module, "encoding.version",
453       "Type of AMR encoding of the payload",
454       "Type of AMR encoding of the payload",
455       &amr_encoding_type, encoding_types, FALSE);
456
457         register_dissector("amr_if1", dissect_amr_if1, proto_amr);
458         register_dissector("amr_if2", dissect_amr_if2, proto_amr);
459 }
460
461