Move the GSM SMS dissection to a dedicated subdissector (currently still within
[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.3 2003/10/09 22:35:07 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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/conversation.h>
33
34 #include <stdio.h>
35 #include <string.h>
36
37 #include "prefs.h"
38 #include "ipproto.h"
39 #include "packet-per.h"
40
41 #define PORT_T38 6004
42
43 static dissector_handle_t t38_handle;
44
45 static guint32 Type_of_msg_value;
46 static guint32 Data_Field_field_type_value;
47
48 static int proto_t38 = -1;
49 static int hf_t38_IFPPacket = -1;
50 static int hf_t38_Type_of_msg = -1;
51 static int hf_t38_t30_indicator = -1;
52 static int hf_t38_data = -1;
53 static int hf_t38_Data_Field = -1;
54 static int hf_t38_Data_Field_item = -1;
55 static int hf_t38_Data_Field_field_type = -1;
56 static int hf_t38_Data_Field_field_data = -1;
57 static int hf_t38_UDPTLPacket = -1;
58 static int hf_t38_seq_number = -1;
59 static int hf_t38_primary_ifp_packet = -1;
60 static int hf_t38_primary_ifp_packet_length = -1;
61 static int hf_t38_error_recovery = -1;
62 static int hf_t38_secondary_ifp_packets = -1;
63 static int hf_t38_secondary_ifp_packets_item = -1;
64 static int hf_t38_secondary_ifp_packets_item_length = -1;
65 static int hf_t38_fec_info = -1;
66 static int hf_t38_fec_npackets = -1;
67 static int hf_t38_fec_data = -1;
68 static int hf_t38_fec_data_item = -1;
69
70 static gint ett_t38 = -1;
71 static gint ett_t38_IFPPacket = -1;
72 static gint ett_t38_Type_of_msg = -1;
73 static gint ett_t38_t30_indicator = -1;
74 static gint ett_t38_data = -1;
75 static gint ett_t38_Data_Field = -1;
76 static gint ett_t38_Data_Field_item = -1;
77 static gint ett_t38_Data_Field_field_type = -1;
78 static gint ett_t38_UDPTLPacket = -1;
79 static gint ett_t38_error_recovery = -1;
80 static gint ett_t38_secondary_ifp_packets = -1;
81 static gint ett_t38_fec_info = -1;
82 static gint ett_t38_fec_data = -1;
83
84
85 static int
86 dissect_t38_NULL(tvbuff_t *tvb _U_, int offset, packet_info *pinfo _U_, proto_tree *tree _U_)
87 {
88         return offset;
89 }
90
91 static per_choice_t t30_indicator_choice[] = {
92         { 0, "no-signal", ASN1_EXTENSION_ROOT,
93                 dissect_t38_NULL},
94         { 1, "cng", ASN1_EXTENSION_ROOT,
95                 dissect_t38_NULL},
96         { 2, "ced", ASN1_EXTENSION_ROOT,
97                 dissect_t38_NULL},
98         { 3, "v21-preamble", ASN1_EXTENSION_ROOT,
99                 dissect_t38_NULL},
100         { 4, "v27-2400-training", ASN1_EXTENSION_ROOT,
101                 dissect_t38_NULL},
102         { 5, "v27-4800-training", ASN1_EXTENSION_ROOT,
103                 dissect_t38_NULL},
104         { 6, "v29-7200-training", ASN1_EXTENSION_ROOT,
105                 dissect_t38_NULL},
106         { 7, "v29-9600-training", ASN1_EXTENSION_ROOT,
107                 dissect_t38_NULL},
108         { 8, "v17-7200-short-training", ASN1_EXTENSION_ROOT,
109                 dissect_t38_NULL},
110         { 9, "v17-7200-long-training", ASN1_EXTENSION_ROOT,
111                 dissect_t38_NULL},
112         { 10, "v17-9600-short-training", ASN1_EXTENSION_ROOT,
113                 dissect_t38_NULL},
114         { 11, "v17-9600-long-training", ASN1_EXTENSION_ROOT,
115                 dissect_t38_NULL},
116         { 12, "v17-12000-short-training", ASN1_EXTENSION_ROOT,
117                 dissect_t38_NULL},
118         { 13, "v17-12000-long-training", ASN1_EXTENSION_ROOT,
119                 dissect_t38_NULL},
120         { 14, "v17-14400-short-training", ASN1_EXTENSION_ROOT,
121                 dissect_t38_NULL},
122         { 15, "v17-14400-long-training", ASN1_EXTENSION_ROOT,
123                 dissect_t38_NULL},
124         { 16, "v8-ansam", ASN1_NOT_EXTENSION_ROOT,
125                 dissect_t38_NULL},
126         { 17, "v8-signal", ASN1_NOT_EXTENSION_ROOT,
127                 dissect_t38_NULL},
128         { 18, "v34-cntl-channel-1200", ASN1_NOT_EXTENSION_ROOT,
129                 dissect_t38_NULL},
130         { 19, "v34-pri-channel", ASN1_NOT_EXTENSION_ROOT,
131                 dissect_t38_NULL},
132         { 20, "v34-CC-retrain", ASN1_NOT_EXTENSION_ROOT,
133                 dissect_t38_NULL},
134         { 21, "v33-12000-training", ASN1_NOT_EXTENSION_ROOT,
135                 dissect_t38_NULL},
136         { 22, "v33-14400-training", ASN1_NOT_EXTENSION_ROOT,
137                 dissect_t38_NULL},
138         { 0, NULL, 0, NULL }
139 };
140
141 static const value_string t30_indicator_vals[] = {
142         { 0, "no-signal" },
143         { 1, "cng" },
144         { 2, "ced" },
145         { 3, "v21-preamble" },
146         { 4, "v27-2400-training" },
147         { 5, "v27-4800-training" },
148         { 6, "v29-7200-training" },
149         { 7, "v29-9600-training" },
150         { 8, "v17-7200-short-training" },
151         { 9, "v17-7200-long-training" },
152         { 10, "v17-9600-short-training" },
153         { 11, "v17-9600-long-training" },
154         { 12, "v17-12000-short-training" },
155         { 13, "v17-12000-long-training" },
156         { 14, "v17-14400-short-training" },
157         { 15, "v17-14400-long-training" },
158     { 16, "v8-ansam" },
159     { 17, "v8-signal" },
160     { 18, "v34-cntl-channel-1200" },
161     { 19, "v34-pri-channel" },
162     { 20, "v34-CC-retrain" },
163     { 21, "v33-12000-training" },
164     { 22, "v33-14400-training" },
165         { 0, NULL },
166 };
167
168 static int
169 dissect_t38_t30_indicator(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
170 {
171     offset=dissect_per_choice(tvb, offset, pinfo,
172         tree, hf_t38_t30_indicator, ett_t38_t30_indicator,
173         t30_indicator_choice, "T30 Indicator", NULL);
174         return offset;
175 }
176
177 static per_choice_t data_choice[] = {
178         { 0, "v21", ASN1_EXTENSION_ROOT,
179                 dissect_t38_NULL},
180         { 1, "v27-2400", ASN1_EXTENSION_ROOT,
181                 dissect_t38_NULL},
182         { 2, "v27-4800", ASN1_EXTENSION_ROOT,
183                 dissect_t38_NULL},
184         { 3, "v29-7200", ASN1_EXTENSION_ROOT,
185                 dissect_t38_NULL},
186         { 4, "v29-9600", ASN1_EXTENSION_ROOT,
187                 dissect_t38_NULL},
188         { 5, "v17-7200", ASN1_EXTENSION_ROOT,
189                 dissect_t38_NULL},
190         { 6, "v17-9600", ASN1_EXTENSION_ROOT,
191                 dissect_t38_NULL},
192         { 7, "v17-12000", ASN1_EXTENSION_ROOT,
193                 dissect_t38_NULL},
194         { 8, "v17-14400", ASN1_EXTENSION_ROOT,
195                 dissect_t38_NULL},
196         { 9, "v8", ASN1_NOT_EXTENSION_ROOT,
197                 dissect_t38_NULL},
198         { 10, "v34-pri-rate", ASN1_NOT_EXTENSION_ROOT,
199                 dissect_t38_NULL},
200         { 11, "v34-CC-1200", ASN1_NOT_EXTENSION_ROOT,
201                 dissect_t38_NULL},
202         { 12, "v34-pri-ch", ASN1_NOT_EXTENSION_ROOT,
203                 dissect_t38_NULL},
204         { 13, "v33-12000", ASN1_NOT_EXTENSION_ROOT,
205                 dissect_t38_NULL},
206         { 14, "v33-14400", ASN1_NOT_EXTENSION_ROOT,
207                 dissect_t38_NULL},
208         { 0, NULL, 0, NULL }
209 };
210
211 static const value_string data_vals[] = {
212         { 0, "v21" },
213         { 1, "v27-2400" },
214         { 2, "v27-4800" },
215         { 3, "v29-7200" },
216         { 4, "v29-9600" },
217         { 5, "v17-7200" },
218         { 6, "v17-9600" },
219         { 7, "v17-12000" },
220         { 8, "v17-14400" },
221         { 9, "v8" },
222         { 10, "v34-pri-rate" },
223         { 11, "v34-CC-1200" },
224         { 12, "v34-pri-ch" },
225         { 13, "v33-12000" },
226         { 14, "v33-14400" },
227         { 0, NULL },
228 };
229
230 static int
231 dissect_t38_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
232 {
233    offset=dissect_per_choice(tvb, offset, pinfo,
234         tree, hf_t38_data, ett_t38_data,
235         data_choice, "data", NULL);
236         return offset;
237 }
238
239 static per_choice_t Type_of_msg_choice[] = {
240         { 0, "t30-indicator", ASN1_NO_EXTENSIONS,
241                 dissect_t38_t30_indicator},
242         { 1, "data", ASN1_NO_EXTENSIONS,
243                 dissect_t38_data},
244         { 0, NULL, 0, NULL }
245 };
246
247 static const value_string Type_of_msg_vals[] = {
248         { 0, "t30-indicator" },
249         { 1, "data" },
250     { 0, NULL}
251 };
252
253 static int
254 dissect_t38_Type_of_msg(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
255 {
256         offset=dissect_per_choice(tvb, offset, pinfo,
257         tree, hf_t38_Type_of_msg, ett_t38_Type_of_msg,
258         Type_of_msg_choice, "Type of message", &Type_of_msg_value);
259         return offset;
260 }
261
262 static per_choice_t Data_Field_field_type_choice[] = {
263         { 0, "hdlc-data", ASN1_NO_EXTENSIONS,
264                 dissect_t38_NULL},
265         { 1, "hdlc-sig-end", ASN1_NO_EXTENSIONS,
266                 dissect_t38_NULL},
267         { 2, "hdlc-fcs-OK", ASN1_NO_EXTENSIONS,
268                 dissect_t38_NULL},
269         { 3, "hdlc-fcs-BAD", ASN1_NO_EXTENSIONS,
270                 dissect_t38_NULL},
271         { 4, "hdlc-fcs-OK-sig-end", ASN1_NO_EXTENSIONS,
272                 dissect_t38_NULL},
273         { 5, "hdlc-fcs-BAD-sig-end", ASN1_NO_EXTENSIONS,
274                 dissect_t38_NULL},
275         { 6, "t4-non-ecm-data", ASN1_NO_EXTENSIONS,
276                 dissect_t38_NULL},
277         { 7, "t4-non-ecm-sig-end", ASN1_NO_EXTENSIONS,
278                 dissect_t38_NULL},
279         { 0, NULL, 0, NULL }
280 };
281
282 static const value_string Data_Field_field_type_vals[] = {
283         { 0, "hdlc-data" },
284         { 1, "hdlc-sig-end" },
285         { 2, "hdlc-fcs-OK" },
286         { 3, "hdlc-fcs-BAD" },
287         { 4, "hdlc-fcs-OK-sig-end" },
288         { 5, "hdlc-fcs-BAD-sig-end" },
289         { 6, "t4-non-ecm-data" },
290         { 7, "t4-non-ecm-sig-end" },
291         { 0, NULL },
292 };
293
294 static int
295 dissect_t38_Data_Field_field_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
296 {
297     offset=dissect_per_choice(tvb, offset, pinfo,
298         tree, hf_t38_Data_Field_field_type, ett_t38_Data_Field_field_type,
299         Data_Field_field_type_choice, "Field Type", &Data_Field_field_type_value);
300     return offset;
301 }
302
303 static int
304 dissect_t38_Data_Field_field_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
305 {
306         offset=dissect_per_octet_string(tvb, offset, pinfo,
307         tree, hf_t38_Data_Field_field_data, 1, 65535,
308         NULL, NULL);
309         return offset;
310 }
311
312 static per_sequence_t Data_Field_item_sequence[] = {
313         { "field-type", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
314                 dissect_t38_Data_Field_field_type },
315         { "field-data", ASN1_NO_EXTENSIONS, ASN1_OPTIONAL,
316                 dissect_t38_Data_Field_field_data },
317         { NULL, 0, 0, NULL }
318 };
319
320 static int
321 dissect_t38_Data_Field_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
322 {
323         offset=dissect_per_sequence(tvb, offset, pinfo,
324         tree, hf_t38_Data_Field_item, ett_t38_Data_Field_item,
325         Data_Field_item_sequence);
326         return offset;
327 }
328
329 static int
330 dissect_t38_Data_Field(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
331 {
332         offset=dissect_per_sequence_of(tvb, offset, pinfo,
333         tree, hf_t38_Data_Field, ett_t38_Data_Field,
334         dissect_t38_Data_Field_item);
335         return offset;
336 }
337
338 static per_sequence_t IFPPacket_sequence[] = {
339         { "type-of-msg", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
340                 dissect_t38_Type_of_msg },
341         { "data-field", ASN1_NO_EXTENSIONS, ASN1_OPTIONAL,
342                 dissect_t38_Data_Field },
343         { NULL, 0, 0, NULL }
344 };
345
346 static int
347 dissect_t38_IFPPacket(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
348 {
349         offset=dissect_per_sequence(tvb, offset, pinfo,
350         tree, hf_t38_IFPPacket, ett_t38_IFPPacket,
351         IFPPacket_sequence);
352         return offset;
353 }
354
355 static int
356 dissect_t38_seq_number(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
357 {
358         offset=dissect_per_constrained_integer(tvb, offset, pinfo,
359                 tree, hf_t38_seq_number, 0, 65535,
360                 NULL, NULL, FALSE);
361         return offset;
362 }
363
364 static int
365 dissect_t38_primary_ifp_packet(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
366 {
367     guint32 length;
368
369     offset=dissect_per_length_determinant(tvb, offset, pinfo,
370         tree, hf_t38_primary_ifp_packet_length, &length);
371     offset=dissect_t38_IFPPacket(tvb, offset, pinfo, tree);
372         return offset;
373 }
374
375 static int
376 dissect_t38_secondary_ifp_packets_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
377 {
378     guint32 length;
379
380     offset=dissect_per_length_determinant(tvb, offset, pinfo,
381         tree, hf_t38_secondary_ifp_packets_item_length, &length);
382     offset=dissect_t38_IFPPacket(tvb, offset, pinfo, tree);
383         return offset;
384 }
385
386 static int
387 dissect_t38_secondary_ifp_packets(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
388 {
389     /* When the field-data is not present, we MUST offset 1 byte*/
390     if((Data_Field_field_type_value != 0) &&
391        (Data_Field_field_type_value != 6))
392     {
393         offset=offset+8;
394     }
395
396     offset=dissect_per_sequence_of(tvb, offset, pinfo,
397         tree, hf_t38_secondary_ifp_packets, ett_t38_secondary_ifp_packets,
398         dissect_t38_secondary_ifp_packets_item);
399         return offset;
400 }
401
402 static int
403 dissect_t38_fec_npackets(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
404 {
405     offset=dissect_per_integer(tvb, offset, pinfo,
406         tree, hf_t38_fec_npackets,
407         NULL, NULL);
408         return offset;
409 }
410
411 static int
412 dissect_t38_fec_data_item(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
413 {
414     offset=dissect_per_octet_string(tvb, offset, pinfo,
415         tree, hf_t38_fec_data_item, -1, -1,
416         NULL, NULL);
417         return offset;
418 }
419
420 static int
421 dissect_t38_fec_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
422 {
423     offset=dissect_per_sequence_of(tvb, offset, pinfo,
424         tree, hf_t38_fec_data, ett_t38_fec_data,
425         dissect_t38_fec_data_item);
426         return offset;
427 }
428
429 static per_sequence_t fec_info_sequence[] = {
430         { "fec-npackets", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
431                 dissect_t38_fec_npackets },
432         { "fec-data", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
433                 dissect_t38_fec_data },
434         { NULL, 0, 0, NULL }
435 };
436
437 static int
438 dissect_t38_fec_info(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
439 {
440         offset=dissect_per_sequence(tvb, offset, pinfo,
441         tree, hf_t38_fec_info, ett_t38_fec_info,
442         fec_info_sequence);
443         return offset;
444 }
445
446 static per_choice_t error_recovery_choice[] = {
447         { 0, "secondary-ifp-packets", ASN1_NO_EXTENSIONS,
448                 dissect_t38_secondary_ifp_packets},
449         { 1, "fec-info", ASN1_NO_EXTENSIONS,
450                 dissect_t38_fec_info},
451         { 0, NULL, 0, NULL }
452 };
453
454 static const value_string error_recovery_vals[] = {
455         { 0, "secondary-ifp-packets" },
456         { 1, "fec-info" },
457     { 0, NULL}
458 };
459
460 static int
461 dissect_t38_error_recovery(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
462 {
463     offset=dissect_per_choice(tvb, offset, pinfo,
464         tree, hf_t38_error_recovery, ett_t38_error_recovery,
465         error_recovery_choice, "Error recovery", NULL);
466         return offset;
467 }
468
469 static per_sequence_t UDPTLPacket_sequence[] = {
470         { "seq-number", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
471                 dissect_t38_seq_number },
472         { "primary-ifp-packet", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
473                 dissect_t38_primary_ifp_packet },
474         { "error-recovery", ASN1_NO_EXTENSIONS, ASN1_NOT_OPTIONAL,
475                 dissect_t38_error_recovery },
476         { NULL, 0, 0, NULL }
477 };
478
479 static int
480 dissect_t38_UDPTLPacket(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
481 {
482     /* Initialize to something else than data type */
483     Data_Field_field_type_value = 1;
484
485         offset=dissect_per_sequence(tvb, offset, pinfo,
486         tree, hf_t38_UDPTLPacket, ett_t38_UDPTLPacket,
487         UDPTLPacket_sequence);
488     return offset;
489 }
490
491 /* Entry point for dissection */
492 static void
493 dissect_t38_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
494 {
495         proto_item *it;
496         proto_tree *tr;
497     guint32 offset=0;
498
499         if (check_col(pinfo->cinfo, COL_PROTOCOL)){
500                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "T.38");
501         }
502         if (check_col(pinfo->cinfo, COL_INFO)){
503                 col_clear(pinfo->cinfo, COL_INFO);
504         }
505
506         it=proto_tree_add_protocol_format(tree, proto_t38, tvb, 0, tvb_length(tvb),
507         "ITU-T Recommendation T.38");
508         tr=proto_item_add_subtree(it, ett_t38);
509
510     offset=dissect_t38_UDPTLPacket(tvb, offset, pinfo, tr);
511
512     if (check_col(pinfo->cinfo, COL_INFO)){
513         col_prepend_fstr(pinfo->cinfo, COL_INFO, "UDP: UDPTLPacket");
514         }
515 }
516
517 static void
518 dissect_t38_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
519 {
520     proto_item *it;
521         proto_tree *tr;
522     guint32 offset=0;
523
524         if (check_col(pinfo->cinfo, COL_PROTOCOL)){
525                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "T.38");
526         }
527         if (check_col(pinfo->cinfo, COL_INFO)){
528                 col_clear(pinfo->cinfo, COL_INFO);
529         }
530
531         it=proto_tree_add_protocol_format(tree, proto_t38, tvb, 0, tvb_length(tvb),
532         "ITU-T Recommendation T.38");
533         tr=proto_item_add_subtree(it, ett_t38);
534
535     offset=dissect_t38_IFPPacket(tvb, offset, pinfo, tr);
536
537     if (check_col(pinfo->cinfo, COL_INFO)){
538         col_prepend_fstr(pinfo->cinfo, COL_INFO, "TCP: IFPPacket");
539         }
540 }
541
542 static void
543 dissect_t38(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
544 {
545         if(pinfo->ipproto == IP_PROTO_TCP)
546         {
547                 dissect_t38_tcp(tvb, pinfo, tree);
548         }
549         else if(pinfo->ipproto == IP_PROTO_UDP)
550         {
551                 dissect_t38_udp(tvb, pinfo, tree);
552         }
553 }
554
555 /* Ethereal Protocol Registration */
556 void
557 proto_register_t38(void)
558 {
559         static hf_register_info hf[] =
560         {
561         {  &hf_t38_IFPPacket,
562             { "IFPPacket", "t38.IFPPacket", FT_NONE, BASE_NONE,
563                       NULL, 0, "IFPPacket sequence", HFILL }},
564         {  &hf_t38_Type_of_msg,
565             { "Type of msg", "t38.Type_of_msg_type", FT_UINT32, BASE_DEC,
566                       VALS(Type_of_msg_vals), 0, "Type_of_msg choice", HFILL }},
567         {  &hf_t38_t30_indicator,
568             { "T30 indicator", "t38.t30_indicator", FT_UINT32, BASE_DEC,
569               VALS(t30_indicator_vals), 0, "t30_indicator", HFILL }},
570         {  &hf_t38_data,
571             { "data", "t38.t38_data", FT_UINT32, BASE_DEC,
572               VALS(data_vals), 0, "data", HFILL }},
573         {  &hf_t38_Data_Field,
574             { "Data Field", "t38.Data_Field", FT_NONE, BASE_NONE,
575               NULL, 0, "Data_Field sequence of", HFILL }},
576         {  &hf_t38_Data_Field_item,
577             { "Data_Field_item", "t38.Data_Field_item", FT_NONE, BASE_NONE,
578               NULL, 0, "Data_Field_item sequence", HFILL }},
579         {  &hf_t38_Data_Field_field_type,
580             { "Data_Field_field_type", "t38.Data_Field_field_type", FT_UINT32, BASE_DEC,
581               VALS(Data_Field_field_type_vals), 0, "Data_Field_field_type choice", HFILL }},
582         {  &hf_t38_Data_Field_field_data,
583             { "Data_Field_field_data", "t38.Data_Field_field_data", FT_BYTES, BASE_HEX,
584             NULL, 0, "Data_Field_field_data octet string", HFILL }},
585         {  &hf_t38_UDPTLPacket,
586             { "UDPTLPacket", "t38.UDPTLPacket", FT_NONE, BASE_NONE,
587                       NULL, 0, "UDPTLPacket sequence", HFILL }},
588         {  &hf_t38_seq_number,
589             { "Sequence number", "t38.seq_number", FT_UINT32, BASE_DEC,
590                       NULL, 0, "seq_number", HFILL }},
591         {  &hf_t38_primary_ifp_packet,
592             { "Primary IFPPacket", "t38.primary_ifp_packet", FT_BYTES, BASE_HEX,
593               NULL, 0, "primary_ifp_packet octet string", HFILL }},
594         {  &hf_t38_primary_ifp_packet_length,
595             { "primary_ifp_packet_length", "t38.primary_ifp_packet_length", FT_UINT32, BASE_DEC,
596             NULL, 0, "primary_ifp_packet_length", HFILL }},
597         {  &hf_t38_error_recovery,
598             { "Error recovery", "t38.error_recovery", FT_UINT32, BASE_DEC,
599                       VALS(error_recovery_vals), 0, "error_recovery choice", HFILL }},
600         {  &hf_t38_secondary_ifp_packets,
601             { "Secondary IFPPackets", "t38.secondary_ifp_packets", FT_NONE, BASE_NONE,
602               NULL, 0, "secondary_ifp_packets sequence of", HFILL }},
603         {  &hf_t38_secondary_ifp_packets_item,
604             { "Secondary IFPPackets item", "t38.secondary_ifp_packets_item", FT_BYTES, BASE_HEX,
605               NULL, 0, "secondary_ifp_packets_item octet string", HFILL }},
606         {  &hf_t38_secondary_ifp_packets_item_length,
607             { "secondary_ifp_packets_item_length", "t38.secondary_ifp_packets_item_length", FT_UINT32, BASE_DEC,
608             NULL, 0, "secondary_ifp_packets_item_length", HFILL }},
609         {  &hf_t38_fec_info,
610             { "Fec info", "t38.fec_info", FT_NONE, BASE_NONE,
611                       NULL, 0, "fec_info sequence", HFILL }},
612         {  &hf_t38_fec_npackets,
613             { "Fec npackets", "h245.fec_npackets", FT_INT32, BASE_DEC,
614               NULL, 0, "fec_npackets value", HFILL }},
615         {  &hf_t38_fec_data,
616             { "Fec data", "t38.fec_data", FT_NONE, BASE_NONE,
617               NULL, 0, "fec_data sequence of", HFILL }},
618         {  &hf_t38_fec_data_item,
619             { "t38_fec_data_item", "t38.t38_fec_data_item", FT_BYTES, BASE_HEX,
620             NULL, 0, "t38_fec_data_item octet string", HFILL }},
621         };
622
623         static gint *ett[] =
624         {
625                 &ett_t38,
626         &ett_t38_IFPPacket,
627         &ett_t38_Type_of_msg,
628         &ett_t38_t30_indicator,
629         &ett_t38_data,
630         &ett_t38_Data_Field,
631         &ett_t38_Data_Field_item,
632         &ett_t38_Data_Field_field_type,
633         &ett_t38_UDPTLPacket,
634         &ett_t38_error_recovery,
635         &ett_t38_secondary_ifp_packets,
636         &ett_t38_fec_info,
637         &ett_t38_fec_data,
638         };
639
640         proto_t38 = proto_register_protocol("T38", "T38", "t38");
641         proto_register_field_array(proto_t38, hf, array_length(hf));
642         proto_register_subtree_array(ett, array_length(ett));
643         register_dissector("t38", dissect_t38, proto_t38);
644 }
645
646 void
647 proto_reg_handoff_t38(void)
648 {
649         t38_handle=create_dissector_handle(dissect_t38, proto_t38);
650         dissector_add("udp.port", PORT_T38, t38_handle);
651     dissector_add("tcp.port", PORT_T38, t38_handle);
652 }