added some options and enhancements to the print output:
[obnox/wireshark/wip.git] / packet-t38.c
1 /* packet-t38.c
2  * Routines for T.38 packet dissection
3  * 2003  Hans Viens
4  *
5  * $Id: packet-t38.c,v 1.6 2004/01/26 22:52:22 guy Exp $
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
26
27 /* Depending on what ASN.1 specification is used you may have to change
28  * the preference setting regarding Pre-Corrigendum ASN.1 specification:
29  * http://www.itu.int/ITU-T/asn1/database/itu-t/t/t38/1998/T38.html  (Pre-Corrigendum=TRUE)
30  * http://www.itu.int/ITU-T/asn1/database/itu-t/t/t38/2003/T38(1998).html (Pre-Corrigendum=TRUE)
31  *
32  * http://www.itu.int/ITU-T/asn1/database/itu-t/t/t38/2003/T38(2002).html (Pre-Corrigendum=FALSE)
33  * http://www.itu.int/ITU-T/asn1/database/itu-t/t/t38/2002/t38.html  (Pre-Corrigendum=FALSE)
34  * http://www.itu.int/ITU-T/asn1/database/itu-t/t/t38/2002-Amd1/T38.html (Pre-Corrigendum=FALSE)
35  */
36
37 /* TO DO:  
38  * - TCP desegmentation is currently not supported for T.38 IFP directly over TCP. 
39  * - SDP and H.245 dissectors should be updated to start conversations for T.38 similar to RTP.
40  * - It would be nice if we could dissect the T.30 data.
41  * - Sometimes the last octet is not high-lighted when selecting something in the tree. Bug in PER dissector? 
42  * - Add support for RTP payload audio/t38 (draft-jones-avt-audio-t38-03.txt), i.e. T38 in RTP packets.
43  */
44
45
46 #ifdef HAVE_CONFIG_H
47 # include "config.h"
48 #endif
49
50 #include <glib.h>
51 #include <epan/packet.h>
52 #include <epan/conversation.h>
53
54 #include <stdio.h>
55 #include <string.h>
56
57 #include "prefs.h"
58 #include "ipproto.h"
59 #include "packet-per.h"
60 #include "prefs.h"
61 #include "packet-tpkt.h"
62
63 #define PORT_T38 6004  
64 static guint global_t38_tcp_port = PORT_T38;
65 static guint global_t38_udp_port = PORT_T38;
66
67 /*
68 * Variables to allow for proper deletion of dissector registration when
69 * the user changes port from the gui.
70 */
71 static guint tcp_port = 0;
72 static guint udp_port = 0;
73
74 /* dissect using the Pre Corrigendum T.38 ASN.1 specification (1998) */
75 static gboolean use_pre_corrigendum_asn1_specification = TRUE;
76
77 /* dissect packets that looks like RTP version 2 packets as RTP     */
78 /* instead of as T.38. This may result in that some T.38 UPTL       */
79 /* packets with sequence number values higher than 32767 may be     */
80 /* shown as RTP packets.                                            */ 
81 static gboolean dissect_possible_rtpv2_packets_as_rtp = FALSE;
82
83
84 /* Reassembly of T.38 PDUs over TPKT over TCP */
85 static gboolean t38_tpkt_reassembly = TRUE;
86
87
88 /* Preference setting whether TPKT header is used when sending T.38 over TCP.
89  * The default setting is Maybe where the dissector will look on the first
90  * bytes to try to determine whether TPKT header is used or not. This may not
91  * work so well in some cases. You may want to change the setting to Always or
92  * Newer.
93  */
94 #define T38_TPKT_NEVER 0   /* Assume that there is never a TPKT header    */
95 #define T38_TPKT_ALWAYS 1  /* Assume that there is always a TPKT header   */
96 #define T38_TPKT_MAYBE 2   /* Assume TPKT if first octets are 03-00-xx-xx */
97 static gint t38_tpkt_usage = T38_TPKT_MAYBE;
98
99 static const enum_val_t t38_tpkt_options[] = {
100   {"Never", T38_TPKT_NEVER},
101   {"Always", T38_TPKT_ALWAYS},
102   {"Maybe", T38_TPKT_MAYBE},
103   {NULL, -1}
104 };
105
106
107 static dissector_handle_t t38_udp_handle;
108 static dissector_handle_t t38_tcp_handle;
109 static dissector_handle_t t38_tcp_pdu_handle;
110 static dissector_handle_t rtp_handle;
111
112 static guint32 Type_of_msg_value;
113 static guint32 Data_Field_field_type_value;
114 static guint32 Data_value;
115 static guint32 T30ind_value;
116
117 static int proto_t38 = -1;
118 static int hf_t38_IFPPacket = -1;
119 static int hf_t38_Type_of_msg = -1;
120 static int hf_t38_t30_indicator = -1;
121 static int hf_t38_data = -1;
122 static int hf_t38_Data_Field = -1;
123 static int hf_t38_Data_Field_item = -1;
124 static int hf_t38_Data_Field_field_type = -1;
125 static int hf_t38_Data_Field_field_data = -1;
126 static int hf_t38_UDPTLPacket = -1;
127 static int hf_t38_seq_number = -1;
128 static int hf_t38_primary_ifp_packet = -1;
129 static int hf_t38_primary_ifp_packet_length = -1;
130 static int hf_t38_error_recovery = -1;
131 static int hf_t38_secondary_ifp_packets = -1;
132 static int hf_t38_secondary_ifp_packets_item = -1;
133 static int hf_t38_secondary_ifp_packets_item_length = -1;
134 static int hf_t38_fec_info = -1;
135 static int hf_t38_fec_npackets = -1;
136 static int hf_t38_fec_data = -1;
137 static int hf_t38_fec_data_item = -1;
138
139 static gint ett_t38 = -1;
140 static gint ett_t38_IFPPacket = -1;
141 static gint ett_t38_Type_of_msg = -1;
142 static gint ett_t38_t30_indicator = -1;
143 static gint ett_t38_data = -1;
144 static gint ett_t38_Data_Field = -1;
145 static gint ett_t38_Data_Field_item = -1;
146 static gint ett_t38_Data_Field_field_type = -1;
147 static gint ett_t38_UDPTLPacket = -1;
148 static gint ett_t38_error_recovery = -1;
149 static gint ett_t38_secondary_ifp_packets = -1;
150 static gint ett_t38_fec_info = -1;
151 static gint ett_t38_fec_data = -1;
152
153 static gboolean primary_part = TRUE;
154 static guint32 seq_number = 0;
155
156
157 /* RTP Version is the first 2 bits of the first octet in the UDP payload*/
158 #define RTP_VERSION(octet)      ((octet) >> 6)
159
160 void proto_reg_handoff_t38(void);
161
162
163 static int
164 dissect_t38_NULL(tvbuff_t *tvb _U_, int offset, packet_info *pinfo _U_, proto_tree *tree _U_)
165 {
166         return offset;
167 }
168
169 static per_choice_t t30_indicator_choice[] = {
170         { 0, "no-signal", ASN1_EXTENSION_ROOT,
171                 dissect_t38_NULL},
172         { 1, "cng", ASN1_EXTENSION_ROOT,
173                 dissect_t38_NULL},
174         { 2, "ced", ASN1_EXTENSION_ROOT,
175                 dissect_t38_NULL},
176         { 3, "v21-preamble", ASN1_EXTENSION_ROOT,
177                 dissect_t38_NULL},
178         { 4, "v27-2400-training", ASN1_EXTENSION_ROOT,
179                 dissect_t38_NULL},
180         { 5, "v27-4800-training", ASN1_EXTENSION_ROOT,
181                 dissect_t38_NULL},
182         { 6, "v29-7200-training", ASN1_EXTENSION_ROOT,
183                 dissect_t38_NULL},
184         { 7, "v29-9600-training", ASN1_EXTENSION_ROOT,
185                 dissect_t38_NULL},
186         { 8, "v17-7200-short-training", ASN1_EXTENSION_ROOT,
187                 dissect_t38_NULL},
188         { 9, "v17-7200-long-training", ASN1_EXTENSION_ROOT,
189                 dissect_t38_NULL},
190         { 10, "v17-9600-short-training", ASN1_EXTENSION_ROOT,
191                 dissect_t38_NULL},
192         { 11, "v17-9600-long-training", ASN1_EXTENSION_ROOT,
193                 dissect_t38_NULL},
194         { 12, "v17-12000-short-training", ASN1_EXTENSION_ROOT,
195                 dissect_t38_NULL},
196         { 13, "v17-12000-long-training", ASN1_EXTENSION_ROOT,
197                 dissect_t38_NULL},
198         { 14, "v17-14400-short-training", ASN1_EXTENSION_ROOT,
199                 dissect_t38_NULL},
200         { 15, "v17-14400-long-training", ASN1_EXTENSION_ROOT,
201                 dissect_t38_NULL},
202         { 16, "v8-ansam", ASN1_NOT_EXTENSION_ROOT,
203                 dissect_t38_NULL},
204         { 17, "v8-signal", ASN1_NOT_EXTENSION_ROOT,
205                 dissect_t38_NULL},
206         { 18, "v34-cntl-channel-1200", ASN1_NOT_EXTENSION_ROOT,
207                 dissect_t38_NULL},
208         { 19, "v34-pri-channel", ASN1_NOT_EXTENSION_ROOT,
209                 dissect_t38_NULL},
210         { 20, "v34-CC-retrain", ASN1_NOT_EXTENSION_ROOT,
211                 dissect_t38_NULL},
212         { 21, "v33-12000-training", ASN1_NOT_EXTENSION_ROOT,
213                 dissect_t38_NULL},
214         { 22, "v33-14400-training", ASN1_NOT_EXTENSION_ROOT,
215                 dissect_t38_NULL},
216         { 0, NULL, 0, NULL }
217 };
218
219 static const value_string t30_indicator_vals[] = {
220         { 0, "no-signal" },
221         { 1, "cng" },
222         { 2, "ced" },
223         { 3, "v21-preamble" },
224         { 4, "v27-2400-training" },
225         { 5, "v27-4800-training" },
226         { 6, "v29-7200-training" },
227         { 7, "v29-9600-training" },
228         { 8, "v17-7200-short-training" },
229         { 9, "v17-7200-long-training" },
230         { 10, "v17-9600-short-training" },
231         { 11, "v17-9600-long-training" },
232         { 12, "v17-12000-short-training" },
233         { 13, "v17-12000-long-training" },
234         { 14, "v17-14400-short-training" },
235         { 15, "v17-14400-long-training" },
236     { 16, "v8-ansam" },
237     { 17, "v8-signal" },
238     { 18, "v34-cntl-channel-1200" },
239     { 19, "v34-pri-channel" },
240     { 20, "v34-CC-retrain" },
241     { 21, "v33-12000-training" },
242     { 22, "v33-14400-training" },
243         { 0, NULL },
244 };
245
246 static int
247 dissect_t38_t30_indicator(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
248 {
249     offset=dissect_per_choice(tvb, offset, pinfo,
250         tree, hf_t38_t30_indicator, ett_t38_t30_indicator,
251         t30_indicator_choice, "T30 Indicator", &T30ind_value);
252
253         if (check_col(pinfo->cinfo, COL_INFO) && primary_part){
254         col_append_fstr(pinfo->cinfo, COL_INFO, " t30ind: %s",
255          val_to_str(T30ind_value,t30_indicator_vals,"<unknown>"));
256         }
257         return offset;
258 }
259
260 static per_choice_t data_choice[] = {
261         { 0, "v21", ASN1_EXTENSION_ROOT,
262                 dissect_t38_NULL},
263         { 1, "v27-2400", ASN1_EXTENSION_ROOT,
264                 dissect_t38_NULL},
265         { 2, "v27-4800", ASN1_EXTENSION_ROOT,
266                 dissect_t38_NULL},
267         { 3, "v29-7200", ASN1_EXTENSION_ROOT,
268                 dissect_t38_NULL},
269         { 4, "v29-9600", ASN1_EXTENSION_ROOT,
270                 dissect_t38_NULL},
271         { 5, "v17-7200", ASN1_EXTENSION_ROOT,
272                 dissect_t38_NULL},
273         { 6, "v17-9600", ASN1_EXTENSION_ROOT,
274                 dissect_t38_NULL},
275         { 7, "v17-12000", ASN1_EXTENSION_ROOT,
276                 dissect_t38_NULL},
277         { 8, "v17-14400", ASN1_EXTENSION_ROOT,
278                 dissect_t38_NULL},
279         { 9, "v8", ASN1_NOT_EXTENSION_ROOT,
280                 dissect_t38_NULL},
281         { 10, "v34-pri-rate", ASN1_NOT_EXTENSION_ROOT,
282                 dissect_t38_NULL},
283         { 11, "v34-CC-1200", ASN1_NOT_EXTENSION_ROOT,
284                 dissect_t38_NULL},
285         { 12, "v34-pri-ch", ASN1_NOT_EXTENSION_ROOT,
286                 dissect_t38_NULL},
287         { 13, "v33-12000", ASN1_NOT_EXTENSION_ROOT,
288                 dissect_t38_NULL},
289         { 14, "v33-14400", ASN1_NOT_EXTENSION_ROOT,
290                 dissect_t38_NULL},
291         { 0, NULL, 0, NULL }
292 };
293
294 static const value_string data_vals[] = {
295         { 0, "v21" },
296         { 1, "v27-2400" },
297         { 2, "v27-4800" },
298         { 3, "v29-7200" },
299         { 4, "v29-9600" },
300         { 5, "v17-7200" },
301         { 6, "v17-9600" },
302         { 7, "v17-12000" },
303         { 8, "v17-14400" },
304         { 9, "v8" },
305         { 10, "v34-pri-rate" },
306         { 11, "v34-CC-1200" },
307         { 12, "v34-pri-ch" },
308         { 13, "v33-12000" },
309         { 14, "v33-14400" },
310         { 0, NULL },
311 };
312
313 static int
314 dissect_t38_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
315 {
316     offset=dissect_per_choice(tvb, offset, pinfo,
317         tree, hf_t38_data, ett_t38_data,
318         data_choice, "data", &Data_value);
319
320     if (check_col(pinfo->cinfo, COL_INFO) && primary_part){
321         col_append_fstr(pinfo->cinfo, COL_INFO, " data:%s:",
322          val_to_str(Data_value,data_vals,"<unknown>"));
323         }
324         return offset;
325 }
326
327 static per_choice_t Type_of_msg_choice[] = {
328         { 0, "t30-indicator", ASN1_NO_EXTENSIONS,
329                 dissect_t38_t30_indicator},
330         { 1, "data", ASN1_NO_EXTENSIONS,
331                 dissect_t38_data},
332         { 0, NULL, 0, NULL }
333 };
334
335 static const value_string Type_of_msg_vals[] = {
336         { 0, "t30-indicator" },
337         { 1, "data" },
338     { 0, NULL}
339 };
340
341 static int
342 dissect_t38_Type_of_msg(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
343 {
344         offset=dissect_per_choice(tvb, offset, pinfo,
345         tree, hf_t38_Type_of_msg, ett_t38_Type_of_msg,
346         Type_of_msg_choice, "Type of message", &Type_of_msg_value);
347         return offset;
348 }
349
350 static per_choice_t Data_Field_field_type_PreCorrigendum_choice[] = {
351         { 0, "hdlc-data", ASN1_NO_EXTENSIONS,
352                 dissect_t38_NULL},
353         { 1, "hdlc-sig-end", ASN1_NO_EXTENSIONS,
354                 dissect_t38_NULL},
355         { 2, "hdlc-fcs-OK", ASN1_NO_EXTENSIONS,
356                 dissect_t38_NULL},
357         { 3, "hdlc-fcs-BAD", ASN1_NO_EXTENSIONS,
358                 dissect_t38_NULL},
359         { 4, "hdlc-fcs-OK-sig-end", ASN1_NO_EXTENSIONS,
360                 dissect_t38_NULL},
361         { 5, "hdlc-fcs-BAD-sig-end", ASN1_NO_EXTENSIONS,
362                 dissect_t38_NULL},
363         { 6, "t4-non-ecm-data", ASN1_NO_EXTENSIONS,
364                 dissect_t38_NULL},
365         { 7, "t4-non-ecm-sig-end", ASN1_NO_EXTENSIONS,
366                 dissect_t38_NULL},
367         { 0, NULL, 0, NULL }
368 };
369
370
371 static per_choice_t Data_Field_field_type_choice[] = {
372         { 0, "hdlc-data", ASN1_EXTENSION_ROOT,
373                 dissect_t38_NULL},
374         { 1, "hdlc-sig-end", ASN1_EXTENSION_ROOT,
375                 dissect_t38_NULL},
376         { 2, "hdlc-fcs-OK", ASN1_EXTENSION_ROOT,
377                 dissect_t38_NULL},
378         { 3, "hdlc-fcs-BAD", ASN1_EXTENSION_ROOT,
379                 dissect_t38_NULL},
380         { 4, "hdlc-fcs-OK-sig-end", ASN1_EXTENSION_ROOT,
381                 dissect_t38_NULL},
382         { 5, "hdlc-fcs-BAD-sig-end", ASN1_EXTENSION_ROOT,
383                 dissect_t38_NULL},
384         { 6, "t4-non-ecm-data", ASN1_EXTENSION_ROOT,
385                 dissect_t38_NULL},
386         { 7, "t4-non-ecm-sig-end", ASN1_EXTENSION_ROOT,
387                 dissect_t38_NULL},
388         { 8, "cm-message", ASN1_NOT_EXTENSION_ROOT,
389                 dissect_t38_NULL},
390         { 9, "jm-message", ASN1_NOT_EXTENSION_ROOT,
391                 dissect_t38_NULL},
392         { 10, "ci-message", ASN1_NOT_EXTENSION_ROOT,
393                 dissect_t38_NULL},
394         { 11, "v34-rate", ASN1_NOT_EXTENSION_ROOT,
395                 dissect_t38_NULL},
396         { 0, NULL, 0, NULL }
397 };
398
399
400 static const value_string Data_Field_field_type_vals[] = {
401         { 0, "hdlc-data" },
402         { 1, "hdlc-sig-end" },
403         { 2, "hdlc-fcs-OK" },
404         { 3, "hdlc-fcs-BAD" },
405         { 4, "hdlc-fcs-OK-sig-end" },
406         { 5, "hdlc-fcs-BAD-sig-end" },
407         { 6, "t4-non-ecm-data" },
408         { 7, "t4-non-ecm-sig-end" },
409         { 8, "cm-message" },
410         { 9, "jm-message" },
411         { 10, "ci-message" },
412         { 11, "v34-rate" },
413         { 0, NULL },
414 };
415
416 static int
417 dissect_t38_Data_Field_field_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
418 {
419         if(use_pre_corrigendum_asn1_specification){
420                 offset=dissect_per_choice(tvb, offset, pinfo,
421                         tree, hf_t38_Data_Field_field_type, ett_t38_Data_Field_field_type,
422                         Data_Field_field_type_PreCorrigendum_choice, "Field Type", &Data_Field_field_type_value);
423         }
424         else{
425                 offset=dissect_per_choice(tvb, offset, pinfo,
426                         tree, hf_t38_Data_Field_field_type, ett_t38_Data_Field_field_type,
427                         Data_Field_field_type_choice, "Field Type", &Data_Field_field_type_value);
428         }
429
430     if (check_col(pinfo->cinfo, COL_INFO) && primary_part){
431         col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
432          val_to_str(Data_Field_field_type_value,Data_Field_field_type_vals,"<unknown>"));
433         }
434
435     return offset;
436 }
437
438 static int
439 dissect_t38_Data_Field_field_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
440 {
441         guint32 value_offset = 0;
442         guint32 value_len = 0;
443
444         offset=dissect_per_octet_string(tvb, offset, pinfo,
445         tree, hf_t38_Data_Field_field_data, 1, 65535,
446         &value_offset, &value_len);
447
448         if (check_col(pinfo->cinfo, COL_INFO) && primary_part){
449         if(value_len < 8){
450                 col_append_fstr(pinfo->cinfo, COL_INFO, "[%s]",
451                tvb_bytes_to_str(tvb,value_offset,value_len));
452         }
453         else {
454                 col_append_fstr(pinfo->cinfo, COL_INFO, "[%s...]",
455                tvb_bytes_to_str(tvb,value_offset,7));
456         }
457         }
458         return offset;
459 }
460
461 static per_sequence_t Data_Field_item_sequence[] = {
462         { "field-type", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
463                 dissect_t38_Data_Field_field_type },
464         { "field-data", ASN1_NO_EXTENSIONS, ASN1_OPTIONAL,
465                 dissect_t38_Data_Field_field_data },
466         { NULL, 0, 0, NULL }
467 };
468
469 static int
470 dissect_t38_Data_Field_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
471 {
472         offset=dissect_per_sequence(tvb, offset, pinfo,
473         tree, hf_t38_Data_Field_item, ett_t38_Data_Field_item,
474         Data_Field_item_sequence);
475         return offset;
476 }
477
478 static int
479 dissect_t38_Data_Field(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
480 {
481         offset=dissect_per_sequence_of(tvb, offset, pinfo,
482         tree, hf_t38_Data_Field, ett_t38_Data_Field,
483         dissect_t38_Data_Field_item);
484         return offset;
485 }
486
487 static per_sequence_t IFPPacket_sequence[] = {
488         { "type-of-msg", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
489                 dissect_t38_Type_of_msg },
490         { "data-field", ASN1_NO_EXTENSIONS, ASN1_OPTIONAL,
491                 dissect_t38_Data_Field },
492         { NULL, 0, 0, NULL }
493 };
494
495 static int
496 dissect_t38_IFPPacket(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
497 {
498         offset=dissect_per_sequence(tvb, offset, pinfo,
499         tree, hf_t38_IFPPacket, ett_t38_IFPPacket,
500         IFPPacket_sequence);
501         return offset;
502 }
503
504 static int
505 dissect_t38_seq_number(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
506 {
507         offset=dissect_per_constrained_integer(tvb, offset, pinfo,
508                 tree, hf_t38_seq_number, 0, 65535,
509                 &seq_number, NULL, FALSE);
510
511       if (check_col(pinfo->cinfo, COL_INFO)){
512         col_append_fstr(pinfo->cinfo, COL_INFO, "Seq=%05u ",seq_number);
513         }
514         return offset;
515 }
516
517 static int
518 dissect_t38_primary_ifp_packet(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
519 {
520     guint32 length;
521         primary_part = TRUE;
522
523     offset=dissect_per_length_determinant(tvb, offset, pinfo,
524         tree, hf_t38_primary_ifp_packet_length, &length);
525     offset=dissect_t38_IFPPacket(tvb, offset, pinfo, tree);
526         return offset;
527 }
528
529 static int
530 dissect_t38_secondary_ifp_packets_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
531 {
532     guint32 length;
533
534     offset=dissect_per_length_determinant(tvb, offset, pinfo,
535         tree, hf_t38_secondary_ifp_packets_item_length, &length);
536     offset=dissect_t38_IFPPacket(tvb, offset, pinfo, tree);
537         return offset;
538 }
539
540 static int
541 dissect_t38_secondary_ifp_packets(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
542 {
543     /* When the field-data is not present, we MUST offset 1 byte*/
544     if((Data_Field_field_type_value != 0) &&
545        (Data_Field_field_type_value != 6))
546     {
547         offset=offset+8;
548     }
549
550     offset=dissect_per_sequence_of(tvb, offset, pinfo,
551         tree, hf_t38_secondary_ifp_packets, ett_t38_secondary_ifp_packets,
552         dissect_t38_secondary_ifp_packets_item);
553         return offset;
554 }
555
556 static int
557 dissect_t38_fec_npackets(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
558 {
559     offset=dissect_per_integer(tvb, offset, pinfo,
560         tree, hf_t38_fec_npackets,
561         NULL, NULL);
562         return offset;
563 }
564
565 static int
566 dissect_t38_fec_data_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
567 {
568     offset=dissect_per_octet_string(tvb, offset, pinfo,
569         tree, hf_t38_fec_data_item, -1, -1,
570         NULL, NULL);
571         return offset;
572 }
573
574 static int
575 dissect_t38_fec_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
576 {
577     offset=dissect_per_sequence_of(tvb, offset, pinfo,
578         tree, hf_t38_fec_data, ett_t38_fec_data,
579         dissect_t38_fec_data_item);
580         return offset;
581 }
582
583 static per_sequence_t fec_info_sequence[] = {
584         { "fec-npackets", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
585                 dissect_t38_fec_npackets },
586         { "fec-data", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
587                 dissect_t38_fec_data },
588         { NULL, 0, 0, NULL }
589 };
590
591 static int
592 dissect_t38_fec_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
593 {
594         offset=dissect_per_sequence(tvb, offset, pinfo,
595         tree, hf_t38_fec_info, ett_t38_fec_info,
596         fec_info_sequence);
597         return offset;
598 }
599
600 static per_choice_t error_recovery_choice[] = {
601         { 0, "secondary-ifp-packets", ASN1_NO_EXTENSIONS,
602                 dissect_t38_secondary_ifp_packets},
603         { 1, "fec-info", ASN1_NO_EXTENSIONS,
604                 dissect_t38_fec_info},
605         { 0, NULL, 0, NULL }
606 };
607
608 static const value_string error_recovery_vals[] = {
609         { 0, "secondary-ifp-packets" },
610         { 1, "fec-info" },
611     { 0, NULL}
612 };
613
614 static int
615 dissect_t38_error_recovery(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
616 {
617         primary_part = FALSE;
618
619     offset=dissect_per_choice(tvb, offset, pinfo,
620         tree, hf_t38_error_recovery, ett_t38_error_recovery,
621         error_recovery_choice, "Error recovery", NULL);
622
623         primary_part = TRUE;
624
625         return offset;
626 }
627
628 static per_sequence_t UDPTLPacket_sequence[] = {
629         { "seq-number", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
630                 dissect_t38_seq_number },
631         { "primary-ifp-packet", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
632                 dissect_t38_primary_ifp_packet },
633         { "error-recovery", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
634                 dissect_t38_error_recovery },
635         { NULL, 0, 0, NULL }
636 };
637
638 static int
639 dissect_t38_UDPTLPacket(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
640 {
641     /* Initialize to something else than data type */
642     Data_Field_field_type_value = 1;
643
644         offset=dissect_per_sequence(tvb, offset, pinfo,
645         tree, hf_t38_UDPTLPacket, ett_t38_UDPTLPacket,
646         UDPTLPacket_sequence);
647     return offset;
648 }
649
650 /* Entry point for dissection */
651 static void
652 dissect_t38_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
653 {
654         guint8 octet1;
655         proto_item *it;
656         proto_tree *tr;
657         guint32 offset=0;
658
659         /*
660          * XXX - heuristic to check for misidentified packets.
661          */
662         if(dissect_possible_rtpv2_packets_as_rtp){
663                 octet1 = tvb_get_guint8( tvb, offset );
664                 if(RTP_VERSION(octet1) == 2){
665                         call_dissector(rtp_handle,tvb,pinfo,tree);
666                         return;
667                 }
668         }
669
670         if (check_col(pinfo->cinfo, COL_PROTOCOL)){
671                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "T.38");
672         }
673         if (check_col(pinfo->cinfo, COL_INFO)){
674                 col_clear(pinfo->cinfo, COL_INFO);
675         }
676
677         primary_part = TRUE;
678
679         it=proto_tree_add_protocol_format(tree, proto_t38, tvb, 0, -1,
680             "ITU-T Recommendation T.38");
681         tr=proto_item_add_subtree(it, ett_t38);
682
683         if (check_col(pinfo->cinfo, COL_INFO)){
684                 col_append_fstr(pinfo->cinfo, COL_INFO, "UDP: UDPTLPacket ");
685         }
686
687         offset=dissect_t38_UDPTLPacket(tvb, offset, pinfo, tr);
688
689         if(offset&0x07){
690                 offset=(offset&0xfffffff8)+8;
691         }
692         if(tvb_length_remaining(tvb,offset>>3)>0){
693                 if(tr){
694                         proto_tree_add_text(tr, tvb, offset, tvb_reported_length_remaining(tvb, offset),
695                                 "[MALFORMED PACKET or wrong preference settings]");
696                 }
697                 if (check_col(pinfo->cinfo, COL_INFO)){
698                         col_append_fstr(pinfo->cinfo, COL_INFO, " [Malformed?]");
699                 }
700         }
701 }
702
703 static void
704 dissect_t38_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
705 {
706         proto_item *it;
707         proto_tree *tr;
708         guint32 offset=0;
709         guint16 ifp_packet_number=1;
710
711         if (check_col(pinfo->cinfo, COL_PROTOCOL)){
712                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "T.38");
713         }
714         if (check_col(pinfo->cinfo, COL_INFO)){
715                 col_clear(pinfo->cinfo, COL_INFO);
716         }
717
718         it=proto_tree_add_protocol_format(tree, proto_t38, tvb, 0, -1,
719             "ITU-T Recommendation T.38");
720         tr=proto_item_add_subtree(it, ett_t38);
721
722         if (check_col(pinfo->cinfo, COL_INFO)){
723                 col_append_fstr(pinfo->cinfo, COL_INFO, "TCP: IFPPacket");
724         }
725
726         while(tvb_length_remaining(tvb,offset>>3)>0)
727         {
728                 offset=dissect_t38_IFPPacket(tvb, offset, pinfo, tr);
729                 ifp_packet_number++;
730
731                 if(offset&0x07){
732                         offset=(offset&0xfffffff8)+8;
733                 }
734
735                 if(tvb_length_remaining(tvb,offset>>3)>0){
736                         if(t38_tpkt_usage == T38_TPKT_ALWAYS){
737                                 if(tr){
738                                         proto_tree_add_text(tr, tvb, offset, tvb_reported_length_remaining(tvb, offset),
739                                                 "[MALFORMED PACKET or wrong preference settings]");
740                                 }
741                                 if (check_col(pinfo->cinfo, COL_INFO)){
742                                         col_append_fstr(pinfo->cinfo, COL_INFO, " [Malformed?]");
743                                 }
744                                 break;
745                         } 
746                         else {
747                                 if (check_col(pinfo->cinfo, COL_INFO)){
748                                         col_append_fstr(pinfo->cinfo, COL_INFO, " IFPPacket#%u",ifp_packet_number);
749                                 }
750                         }
751                 }
752         }
753
754 }
755
756 static void
757 dissect_t38_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
758 {
759         primary_part = TRUE;
760
761         if(t38_tpkt_usage == T38_TPKT_ALWAYS){
762                 dissect_tpkt_encap(tvb,pinfo,tree,t38_tpkt_reassembly,t38_tcp_pdu_handle);
763         } 
764         else if((t38_tpkt_usage == T38_TPKT_NEVER) || (is_tpkt(tvb,1) == -1)){
765                 dissect_t38_tcp_pdu(tvb, pinfo, tree);
766         } 
767         else {
768                 dissect_tpkt_encap(tvb,pinfo,tree,t38_tpkt_reassembly,t38_tcp_pdu_handle);
769         }
770 }
771
772 static void
773 dissect_t38(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
774 {
775         if(pinfo->ipproto == IP_PROTO_TCP)
776         {
777                 dissect_t38_tcp(tvb, pinfo, tree);
778         }
779         else if(pinfo->ipproto == IP_PROTO_UDP)
780         {   
781                 dissect_t38_udp(tvb, pinfo, tree);
782         }
783 }
784
785 /* Ethereal Protocol Registration */
786 void
787 proto_register_t38(void)
788 {
789         static hf_register_info hf[] =
790         {
791         {  &hf_t38_IFPPacket,
792             { "IFPPacket", "t38.IFPPacket", FT_NONE, BASE_NONE,
793                       NULL, 0, "IFPPacket sequence", HFILL }},
794         {  &hf_t38_Type_of_msg,
795             { "Type of msg", "t38.Type_of_msg_type", FT_UINT32, BASE_DEC,
796                       VALS(Type_of_msg_vals), 0, "Type_of_msg choice", HFILL }},
797         {  &hf_t38_t30_indicator,
798             { "T30 indicator", "t38.t30_indicator", FT_UINT32, BASE_DEC,
799               VALS(t30_indicator_vals), 0, "t30_indicator", HFILL }},
800         {  &hf_t38_data,
801             { "data", "t38.t38_data", FT_UINT32, BASE_DEC,
802               VALS(data_vals), 0, "data", HFILL }},
803         {  &hf_t38_Data_Field,
804             { "Data Field", "t38.Data_Field", FT_NONE, BASE_NONE,
805               NULL, 0, "Data_Field sequence of", HFILL }},
806         {  &hf_t38_Data_Field_item,
807             { "Data_Field_item", "t38.Data_Field_item", FT_NONE, BASE_NONE,
808               NULL, 0, "Data_Field_item sequence", HFILL }},
809         {  &hf_t38_Data_Field_field_type,
810             { "Data_Field_field_type", "t38.Data_Field_field_type", FT_UINT32, BASE_DEC,
811               VALS(Data_Field_field_type_vals), 0, "Data_Field_field_type choice", HFILL }},
812         {  &hf_t38_Data_Field_field_data,
813             { "Data_Field_field_data", "t38.Data_Field_field_data", FT_BYTES, BASE_HEX,
814             NULL, 0, "Data_Field_field_data octet string", HFILL }},
815         {  &hf_t38_UDPTLPacket,
816             { "UDPTLPacket", "t38.UDPTLPacket", FT_NONE, BASE_NONE,
817                       NULL, 0, "UDPTLPacket sequence", HFILL }},
818         {  &hf_t38_seq_number,
819             { "Sequence number", "t38.seq_number", FT_UINT32, BASE_DEC,
820                       NULL, 0, "seq_number", HFILL }},
821         {  &hf_t38_primary_ifp_packet,
822             { "Primary IFPPacket", "t38.primary_ifp_packet", FT_BYTES, BASE_HEX,
823               NULL, 0, "primary_ifp_packet octet string", HFILL }},
824         {  &hf_t38_primary_ifp_packet_length,
825             { "primary_ifp_packet_length", "t38.primary_ifp_packet_length", FT_UINT32, BASE_DEC,
826             NULL, 0, "primary_ifp_packet_length", HFILL }},
827         {  &hf_t38_error_recovery,
828             { "Error recovery", "t38.error_recovery", FT_UINT32, BASE_DEC,
829                       VALS(error_recovery_vals), 0, "error_recovery choice", HFILL }},
830         {  &hf_t38_secondary_ifp_packets,
831             { "Secondary IFPPackets", "t38.secondary_ifp_packets", FT_NONE, BASE_NONE,
832               NULL, 0, "secondary_ifp_packets sequence of", HFILL }},
833         {  &hf_t38_secondary_ifp_packets_item,
834             { "Secondary IFPPackets item", "t38.secondary_ifp_packets_item", FT_BYTES, BASE_HEX,
835               NULL, 0, "secondary_ifp_packets_item octet string", HFILL }},
836         {  &hf_t38_secondary_ifp_packets_item_length,
837             { "secondary_ifp_packets_item_length", "t38.secondary_ifp_packets_item_length", FT_UINT32, BASE_DEC,
838             NULL, 0, "secondary_ifp_packets_item_length", HFILL }},
839         {  &hf_t38_fec_info,
840             { "Fec info", "t38.fec_info", FT_NONE, BASE_NONE,
841                       NULL, 0, "fec_info sequence", HFILL }},
842         {  &hf_t38_fec_npackets,
843             { "Fec npackets", "h245.fec_npackets", FT_INT32, BASE_DEC,
844               NULL, 0, "fec_npackets value", HFILL }},
845         {  &hf_t38_fec_data,
846             { "Fec data", "t38.fec_data", FT_NONE, BASE_NONE,
847               NULL, 0, "fec_data sequence of", HFILL }},
848         {  &hf_t38_fec_data_item,
849             { "t38_fec_data_item", "t38.t38_fec_data_item", FT_BYTES, BASE_HEX,
850             NULL, 0, "t38_fec_data_item octet string", HFILL }},
851         };
852
853         static gint *ett[] =
854         {
855                 &ett_t38,
856                 &ett_t38_IFPPacket,
857                 &ett_t38_Type_of_msg,
858                 &ett_t38_t30_indicator,
859                 &ett_t38_data,
860                 &ett_t38_Data_Field,
861                 &ett_t38_Data_Field_item,
862                 &ett_t38_Data_Field_field_type,
863                 &ett_t38_UDPTLPacket,
864                 &ett_t38_error_recovery,
865                 &ett_t38_secondary_ifp_packets,
866                 &ett_t38_fec_info,
867                 &ett_t38_fec_data,
868         };
869         module_t *t38_module;
870
871         proto_t38 = proto_register_protocol("T38", "T38", "t38");
872         proto_register_field_array(proto_t38, hf, array_length(hf));
873         proto_register_subtree_array(ett, array_length(ett));
874         register_dissector("t38", dissect_t38, proto_t38);
875
876         t38_module = prefs_register_protocol(proto_t38, proto_reg_handoff_t38);
877         prefs_register_bool_preference(t38_module, "use_pre_corrigendum_asn1_specification",
878             "Use the Pre-Corrigendum ASN.1 specification",
879             "Whether the T.38 dissector should decode using the Pre-Corrigendum T.38 "
880                 "ASN.1 specification (1998).",
881             &use_pre_corrigendum_asn1_specification);
882         prefs_register_bool_preference(t38_module, "dissect_possible_rtpv2_packets_as_rtp",
883             "Dissect possible RTP version 2 packets with RTP dissector",
884             "Whether a UDP packet that looks like RTP version 2 packet will "
885                 "be dissected as RTP packet or T.38 packet. If enabled there is a risk that T.38 UDPTL "
886                 "packets with sequence number higher than 32767 may be dissected as RTP.",
887             &dissect_possible_rtpv2_packets_as_rtp);
888         prefs_register_uint_preference(t38_module, "tcp.port",
889                 "T.38 TCP Port",
890                 "Set the TCP port for T.38 messages",
891                 10, &global_t38_tcp_port);
892         prefs_register_uint_preference(t38_module, "udp.port",
893                 "T.38 UDP Port",
894                 "Set the UDP port for T.38 messages",
895                 10, &global_t38_udp_port);      
896         prefs_register_bool_preference(t38_module, "reassembly",
897                 "Reassemble T.38 PDUs over TPKT over TCP",
898                 "Whether the dissector should reassemble T.38 PDUs spanning multiple TCP segments "
899                 "when TPKT is used over TCP",
900                 &t38_tpkt_reassembly);
901         prefs_register_enum_preference(t38_module, "tpkt_usage",
902                 "TPKT used over TCP",
903                 "Whether T.38 is used with TPKT for TCP",
904                 (gint *)&t38_tpkt_usage,t38_tpkt_options,FALSE);
905 }
906
907 void
908 proto_reg_handoff_t38(void)
909 {
910         static int t38_prefs_initialized = FALSE;
911
912         if (!t38_prefs_initialized) {
913                 t38_udp_handle=create_dissector_handle(dissect_t38_udp, proto_t38);
914                 t38_tcp_handle=create_dissector_handle(dissect_t38_tcp, proto_t38);
915                 t38_tcp_pdu_handle=create_dissector_handle(dissect_t38_tcp_pdu, proto_t38);
916                 t38_prefs_initialized = TRUE;
917         }
918         else {
919                 dissector_delete("tcp.port", tcp_port, t38_tcp_handle);
920                 dissector_delete("udp.port", udp_port, t38_udp_handle);
921         }
922         tcp_port = global_t38_tcp_port;
923         udp_port = global_t38_udp_port;
924
925         dissector_add("tcp.port", tcp_port, t38_tcp_handle);
926         dissector_add("udp.port", udp_port, t38_udp_handle);
927
928         rtp_handle = find_dissector("rtp");
929 }