1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * t38_core.c - Encode and decode the ASN.1 of a T.38 IFP message
5  *
6  * Written by Steve Underwood <steveu@coppice.org>
7  *
8  * Copyright (C) 2005, 2006 Steve Underwood
9  *
10  * All rights reserved.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 2.1,
14  * as published by the Free Software Foundation.
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 Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25 
26 /*! \file */
27 
28 #if defined(HAVE_CONFIG_H)
29 #include "config.h"
30 #endif
31 
32 #include <inttypes.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <time.h>
37 #include <string.h>
38 #if defined(HAVE_TGMATH_H)
39 #include <tgmath.h>
40 #endif
41 #if defined(HAVE_MATH_H)
42 #include <math.h>
43 #endif
44 #if defined(HAVE_STDBOOL_H)
45 #include <stdbool.h>
46 #else
47 #include "spandsp/stdbool.h"
48 #endif
49 #include "floating_fudge.h"
50 #include <assert.h>
51 #include <memory.h>
52 #include <tiffio.h>
53 
54 #include "spandsp/telephony.h"
55 #include "spandsp/alloc.h"
56 #include "spandsp/logging.h"
57 #include "spandsp/bit_operations.h"
58 #include "spandsp/t38_core.h"
59 
60 #include "spandsp/private/logging.h"
61 #include "spandsp/private/t38_core.h"
62 
63 #define ACCEPTABLE_SEQ_NO_OFFSET    2000
64 
65 /* The times for training, the optional TEP, and the HDLC preamble, for all the modem options, in ms.
66    Note that the preamble for V.21 is 1s+-15%, and for the other modems is 200ms+100ms. */
67 static const struct
68 {
69     int tep;
70     int training;
71     int flags;
72 } modem_startup_time[] =
73 {
74     {      0,   75000,       0},    /* T38_IND_NO_SIGNAL */
75     {      0,       0,       0},    /* T38_IND_CNG */
76     {      0, 3000000,       0},    /* T38_IND_CED */
77     {      0,       0, 1000000},    /* T38_IND_V21_PREAMBLE */ /* TODO: 850ms should be OK for this, but it causes trouble with some ATAs. Why? */
78     { 215000,  943000,  200000},    /* T38_IND_V27TER_2400_TRAINING */
79     { 215000,  708000,  200000},    /* T38_IND_V27TER_4800_TRAINING */
80     { 215000,  234000,  200000},    /* T38_IND_V29_7200_TRAINING */
81     { 215000,  234000,  200000},    /* T38_IND_V29_9600_TRAINING */
82     { 215000,  142000,  200000},    /* T38_IND_V17_7200_SHORT_TRAINING */
83     { 215000, 1393000,  200000},    /* T38_IND_V17_7200_LONG_TRAINING */
84     { 215000,  142000,  200000},    /* T38_IND_V17_9600_SHORT_TRAINING */
85     { 215000, 1393000,  200000},    /* T38_IND_V17_9600_LONG_TRAINING */
86     { 215000,  142000,  200000},    /* T38_IND_V17_12000_SHORT_TRAINING */
87     { 215000, 1393000,  200000},    /* T38_IND_V17_12000_LONG_TRAINING */
88     { 215000,  142000,  200000},    /* T38_IND_V17_14400_SHORT_TRAINING */
89     { 215000, 1393000,  200000},    /* T38_IND_V17_14400_LONG_TRAINING */
90     {      0,       0,       0},    /* T38_IND_V8_ANSAM */
91     {      0,       0,       0},    /* T38_IND_V8_SIGNAL */
92     {      0,       0,  200000},    /* T38_IND_V34_CNTL_CHANNEL_1200 */
93     {      0,       0,  200000},    /* T38_IND_V34_PRI_CHANNEL */
94     {      0,       0,       0},    /* T38_IND_V34_CC_RETRAIN */
95     { 215000,       0,  200000},    /* T38_IND_V33_12000_TRAINING */
96     { 215000,       0,  200000}     /* T38_IND_V33_14400_TRAINING */
97 };
98 
t38_indicator_to_str(int indicator)99 SPAN_DECLARE(const char *) t38_indicator_to_str(int indicator)
100 {
101     switch (indicator)
102     {
103     case T38_IND_NO_SIGNAL:
104         return "no-signal";
105     case T38_IND_CNG:
106         return "cng";
107     case T38_IND_CED:
108         return "ced";
109     case T38_IND_V21_PREAMBLE:
110         return "v21-preamble";
111     case T38_IND_V27TER_2400_TRAINING:
112         return "v27-2400-training";
113     case T38_IND_V27TER_4800_TRAINING:
114         return "v27-4800-training";
115     case T38_IND_V29_7200_TRAINING:
116         return "v29-7200-training";
117     case T38_IND_V29_9600_TRAINING:
118         return "v29-9600-training";
119     case T38_IND_V17_7200_SHORT_TRAINING:
120         return "v17-7200-short-training";
121     case T38_IND_V17_7200_LONG_TRAINING:
122         return "v17-7200-long-training";
123     case T38_IND_V17_9600_SHORT_TRAINING:
124         return "v17-9600-short-training";
125     case T38_IND_V17_9600_LONG_TRAINING:
126         return "v17-9600-long-training";
127     case T38_IND_V17_12000_SHORT_TRAINING:
128         return "v17-12000-short-training";
129     case T38_IND_V17_12000_LONG_TRAINING:
130         return "v17-12000-long-training";
131     case T38_IND_V17_14400_SHORT_TRAINING:
132         return "v17-14400-short-training";
133     case T38_IND_V17_14400_LONG_TRAINING:
134         return "v17-14400-long-training";
135     case T38_IND_V8_ANSAM:
136         return "v8-ansam";
137     case T38_IND_V8_SIGNAL:
138         return "v8-signal";
139     case T38_IND_V34_CNTL_CHANNEL_1200:
140         return "v34-cntl-channel-1200";
141     case T38_IND_V34_PRI_CHANNEL:
142         return "v34-pri-channel";
143     case T38_IND_V34_CC_RETRAIN:
144         return "v34-CC-retrain";
145     case T38_IND_V33_12000_TRAINING:
146         return "v33-12000-training";
147     case T38_IND_V33_14400_TRAINING:
148         return "v33-14400-training";
149     }
150     /*endswitch*/
151     return "???";
152 }
153 /*- End of function --------------------------------------------------------*/
154 
t38_data_type_to_str(int data_type)155 SPAN_DECLARE(const char *) t38_data_type_to_str(int data_type)
156 {
157     switch (data_type)
158     {
159     case T38_DATA_V21:
160         return "v21";
161     case T38_DATA_V27TER_2400:
162         return "v27-2400";
163     case T38_DATA_V27TER_4800:
164         return "v27-4800";
165     case T38_DATA_V29_7200:
166         return "v29-7200";
167     case T38_DATA_V29_9600:
168         return "v29-9600";
169     case T38_DATA_V17_7200:
170         return "v17-7200";
171     case T38_DATA_V17_9600:
172         return "v17-9600";
173     case T38_DATA_V17_12000:
174         return "v17-12000";
175     case T38_DATA_V17_14400:
176         return "v17-14400";
177     case T38_DATA_V8:
178         return "v8";
179     case T38_DATA_V34_PRI_RATE:
180         return "v34-pri-rate";
181     case T38_DATA_V34_CC_1200:
182         return "v34-CC-1200";
183     case T38_DATA_V34_PRI_CH:
184         return "v34-pri-ch";
185     case T38_DATA_V33_12000:
186         return "v33-12000";
187     case T38_DATA_V33_14400:
188         return "v33-14400";
189     }
190     /*endswitch*/
191     return "???";
192 }
193 /*- End of function --------------------------------------------------------*/
194 
t38_field_type_to_str(int field_type)195 SPAN_DECLARE(const char *) t38_field_type_to_str(int field_type)
196 {
197     switch (field_type)
198     {
199     case T38_FIELD_HDLC_DATA:
200         return "hdlc-data";
201     case T38_FIELD_HDLC_SIG_END:
202         return "hdlc-sig-end";
203     case T38_FIELD_HDLC_FCS_OK:
204         return "hdlc-fcs-OK";
205     case T38_FIELD_HDLC_FCS_BAD:
206         return "hdlc-fcs-BAD";
207     case T38_FIELD_HDLC_FCS_OK_SIG_END:
208         return "hdlc-fcs-OK-sig-end";
209     case T38_FIELD_HDLC_FCS_BAD_SIG_END:
210         return "hdlc-fcs-BAD-sig-end";
211     case T38_FIELD_T4_NON_ECM_DATA:
212         return "t4-non-ecm-data";
213     case T38_FIELD_T4_NON_ECM_SIG_END:
214         return "t4-non-ecm-sig-end";
215     case T38_FIELD_CM_MESSAGE:
216         return "cm-message";
217     case T38_FIELD_JM_MESSAGE:
218         return "jm-message";
219     case T38_FIELD_CI_MESSAGE:
220         return "ci-message";
221     case T38_FIELD_V34RATE:
222         return "v34rate";
223     }
224     /*endswitch*/
225     return "???";
226 }
227 /*- End of function --------------------------------------------------------*/
228 
t38_cm_profile_to_str(int profile)229 SPAN_DECLARE(const char *) t38_cm_profile_to_str(int profile)
230 {
231     switch (profile)
232     {
233     case '1':
234         return "G3 FAX sending terminal";
235     case '2':
236         return "G3 FAX receiving terminal";
237     case '3':
238         return "V.34 HDX and G3 FAX sending terminal";
239     case '4':
240         return "V.34 HDX and G3 FAX receiving terminal";
241     case '5':
242         return "V.34 HDX-only FAX sending terminal";
243     case '6':
244         return "V.34 HDX-only FAX receiving terminal";
245     }
246     /*endswitch*/
247     return "???";
248 }
249 /*- End of function --------------------------------------------------------*/
250 
t38_jm_to_str(const uint8_t * data,int len)251 SPAN_DECLARE(const char *) t38_jm_to_str(const uint8_t *data, int len)
252 {
253     if (len < 2)
254         return "???";
255     /*endif*/
256     switch (data[0])
257     {
258     case 'A':
259         switch (data[1])
260         {
261         case '0':
262             return "ACK";
263         }
264         /*endswitch*/
265         break;
266     case 'N':
267         switch (data[1])
268         {
269         case '0':
270             return "NACK: No compatible mode available";
271         case '1':
272             /* Response for profiles 1 and 2 */
273             return "NACK: No V.34 FAX, use G3 FAX";
274         case '2':
275             /* Response for profiles 5 and 6 */
276             return "NACK: V.34 only FAX.";
277         }
278         /*endswitch*/
279         break;
280     }
281     /*endswitch*/
282     return "???";
283 }
284 /*- End of function --------------------------------------------------------*/
285 
t38_v34rate_to_bps(const uint8_t * data,int len)286 SPAN_DECLARE(int) t38_v34rate_to_bps(const uint8_t *data, int len)
287 {
288     int i;
289     int rate;
290 
291     if (len < 3)
292         return -1;
293     /*endif*/
294     for (i = 0, rate = 0;  i < 3;  i++)
295     {
296         if (data[i] < '0'  ||  data[i] > '9')
297             return -1;
298         /*endif*/
299         rate = rate*10 + data[i] - '0';
300     }
301     /*endfor*/
302     return rate*100;
303 }
304 /*- End of function --------------------------------------------------------*/
305 
classify_seq_no_offset(int expected,int actual)306 static __inline__ int classify_seq_no_offset(int expected, int actual)
307 {
308     /* Classify the mismatch between expected and actual sequence numbers
309        according to whether the actual is a little in the past (late), a
310        little in the future (some packets have been lost), or a large jump
311        that represents the sequence being lost (possibly when some RTP
312        gets dumped to a UDPTL port). */
313     /* This assumes they are not equal */
314     if (expected > actual)
315     {
316         if (expected > actual + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET)
317         {
318             /* In the near future */
319             return 1;
320         }
321         /*endif*/
322         if (expected < actual + ACCEPTABLE_SEQ_NO_OFFSET)
323         {
324             /* In the recent past */
325             return -1;
326         }
327         /*endif*/
328     }
329     else
330     {
331         if (expected + ACCEPTABLE_SEQ_NO_OFFSET > actual)
332         {
333             /* In the near future */
334             return 1;
335         }
336         /*endif*/
337         if (expected + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET < actual)
338         {
339             /* In the recent past */
340             return -1;
341         }
342         /*endif*/
343     }
344     /*endif*/
345     /* There has been a huge step in the sequence */
346     return 0;
347 }
348 /*- End of function --------------------------------------------------------*/
349 
t38_core_rx_ifp_stream(t38_core_state_t * s,const uint8_t * buf,int len,uint16_t log_seq_no)350 SPAN_DECLARE(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no)
351 {
352     int i;
353     int t30_indicator;
354     int t30_data;
355     int prev_ptr;
356     int ptr;
357     int other_half;
358     int numocts;
359     int pkt_len;
360     int ret;
361     const uint8_t *msg;
362     unsigned int count;
363     unsigned int t30_field_type;
364     uint8_t type;
365     uint8_t data_field_present;
366     uint8_t field_data_present;
367     char tag[20];
368 
369     if (span_log_test(&s->logging, SPAN_LOG_FLOW))
370     {
371         sprintf(tag, "Rx %5d: IFP", log_seq_no);
372         span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len);
373     }
374     /*endif*/
375     ptr = 0;
376     pkt_len = len;
377     switch (s->data_transport_protocol)
378     {
379     case T38_TRANSPORT_TCP:
380         /* We don't know the actual packet length, so treat everythign we have as the packet */
381         ret = 0;
382         break;
383     case T38_TRANSPORT_TCP_TPKT:
384         if (len >= 4)
385         {
386             /* Version */
387             if (buf[0] != 3)
388                 return -1;
389             /*endif*/
390             /* Reserved */
391             if (buf[1] != 0)
392                 return -1;
393             /*endif*/
394             /* Packet length - this includes the length of the header itself */
395             pkt_len = (buf[2] << 8) | buf[3];
396             if (len < pkt_len)
397                 return 0;
398             /*endif*/
399             ptr = 4;
400         }
401         /*endif*/
402         ret = -1;
403         break;
404     default:
405         /* We know the actual packet length, and its the exact length of what we were passed. */
406         ret = -1;
407         break;
408     }
409     /*endswitch*/
410     if ((ptr + 1) > pkt_len)
411         return ret;
412     /*endif*/
413     data_field_present = buf[ptr] & 0x80;
414     type = (buf[ptr] >> 6) & 1;
415     switch (type)
416     {
417     case T38_TYPE_OF_MSG_T30_INDICATOR:
418         /* Indicators should never have a data field */
419         if (data_field_present)
420         {
421             span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Data field with indicator\n", log_seq_no);
422             return -1;
423         }
424         /*endif*/
425         /* Any received indicator should mean we no longer have a valid concept of "last received data/field type". */
426         s->current_rx_data_type = -1;
427         s->current_rx_field_type = -1;
428         if ((buf[ptr] & 0x20))
429         {
430             /* Extension */
431             if ((ptr + 2) > pkt_len)
432                 return ret;
433             /*endif*/
434             t30_indicator = T38_IND_V8_ANSAM + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3));
435             if (t30_indicator > T38_IND_V33_14400_TRAINING)
436             {
437                 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown indicator - %d\n", log_seq_no, t30_indicator);
438                 return -1;
439             }
440             /*endif*/
441             ptr += 2;
442         }
443         else
444         {
445             t30_indicator = (buf[ptr] >> 1) & 0xF;
446             ptr += 1;
447         }
448         /*endif*/
449         span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: indicator %s\n", log_seq_no, t38_indicator_to_str(t30_indicator));
450         s->rx_indicator_handler(s, s->rx_user_data, t30_indicator);
451         /* This must come after the indicator handler, so the handler routine sees the existing state of the
452            indicator. */
453         s->current_rx_indicator = t30_indicator;
454         break;
455     case T38_TYPE_OF_MSG_T30_DATA:
456         if ((buf[ptr] & 0x20))
457         {
458             /* Extension */
459             if ((ptr + 2) > pkt_len)
460                 return ret;
461             /*endif*/
462             t30_data = T38_DATA_V8 + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3));
463             if (t30_data > T38_DATA_V33_14400)
464             {
465                 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown data type - %d\n", log_seq_no, t30_data);
466                 return -1;
467             }
468             /*endif*/
469             ptr += 2;
470         }
471         else
472         {
473             t30_data = (buf[ptr] >> 1) & 0xF;
474             if (t30_data > T38_DATA_V17_14400)
475             {
476                 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown data type - %d\n", log_seq_no, t30_data);
477                 return -1;
478             }
479             /*endif*/
480             ptr += 1;
481         }
482         /*endif*/
483         if (!data_field_present)
484         {
485             /* This is kinda weird, but I guess if the length checks out we accept it. */
486             span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Data type with no data field\n", log_seq_no);
487             break;
488         }
489         /*endif*/
490         if (ptr >= pkt_len)
491             return ret;
492         /*endif*/
493         count = buf[ptr++];
494         //printf("Count is %d\n", count);
495         /* Do a dummy run through the fields to check we have a complete and uncorrupted packet. */
496         prev_ptr = ptr;
497         other_half = false;
498         for (i = 0;  i < (int) count;  i++)
499         {
500             if (ptr >= pkt_len)
501                 return ret;
502             /*endif*/
503             if (s->t38_version == 0)
504             {
505                 /* The original version of T.38 with a typo in the ASN.1 spec. */
506                 if (other_half)
507                 {
508                     /* The lack of a data field in the previous message means
509                        we are currently in the middle of an octet. */
510                     field_data_present = (buf[ptr] >> 3) & 1;
511                     /* Decode field_type */
512                     t30_field_type = buf[ptr] & 0x7;
513                     ptr++;
514                     other_half = false;
515                 }
516                 else
517                 {
518                     field_data_present = (buf[ptr] >> 7) & 1;
519                     /* Decode field_type */
520                     t30_field_type = (buf[ptr] >> 4) & 0x7;
521                     if (field_data_present)
522                         ptr++;
523                     else
524                         other_half = true;
525                     /*endif*/
526                 }
527                 /*endif*/
528                 if (t30_field_type > T38_FIELD_T4_NON_ECM_SIG_END)
529                 {
530                     span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown field type - %d\n", log_seq_no, t30_field_type);
531                     return -1;
532                 }
533                 /*endif*/
534             }
535             else
536             {
537                 field_data_present = (buf[ptr] >> 7) & 1;
538                 /* Decode field_type */
539                 if ((buf[ptr] & 0x40))
540                 {
541                     if ((ptr + 2) > pkt_len)
542                         return ret;
543                     /*endif*/
544                     t30_field_type = T38_FIELD_CM_MESSAGE + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3));
545                     if (t30_field_type > T38_FIELD_V34RATE)
546                     {
547                         span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown field type - %d\n", log_seq_no, t30_field_type);
548                         return -1;
549                     }
550                     /*endif*/
551                     ptr += 2;
552                 }
553                 else
554                 {
555                     ptr++;
556                 }
557                 /*endif*/
558             }
559             /*endif*/
560             /* Decode field_data */
561             if (field_data_present)
562             {
563                 if ((ptr + 2) > pkt_len)
564                     return ret;
565                 /*endif*/
566                 numocts = ((buf[ptr] << 8) | buf[ptr + 1]) + 1;
567                 ptr += numocts + 2;
568             }
569             /*endif*/
570             if (ptr > pkt_len)
571                 return ret;
572             /*endif*/
573         }
574         /*endfor*/
575         /* Check if we finished mid byte in a version 0 packet. */
576         if (other_half)
577             ptr++;
578         /*endif*/
579         if (ptr > pkt_len)
580             return ret;
581         /*endif*/
582 
583         /* Things look alright in the data, so lets run through the fields again, actually processing them.
584            There is no need to do all the error checking along the way on this pass. */
585         ptr = prev_ptr;
586         other_half = false;
587         for (i = 0;  i < (int) count;  i++)
588         {
589             if (s->t38_version == 0)
590             {
591                 /* The original version of T.38 with a typo in the ASN.1 spec. */
592                 if (other_half)
593                 {
594                     /* The lack of a data field in the previous message means
595                        we are currently in the middle of an octet. */
596                     field_data_present = (buf[ptr] >> 3) & 1;
597                     /* Decode field_type */
598                     t30_field_type = buf[ptr] & 0x7;
599                     ptr++;
600                     other_half = false;
601                 }
602                 else
603                 {
604                     field_data_present = (buf[ptr] >> 7) & 1;
605                     /* Decode field_type */
606                     t30_field_type = (buf[ptr] >> 4) & 0x7;
607                     if (field_data_present)
608                         ptr++;
609                     else
610                         other_half = true;
611                     /*endif*/
612                 }
613                 /*endif*/
614             }
615             else
616             {
617                 field_data_present = (buf[ptr] >> 7) & 1;
618                 /* Decode field_type */
619                 if ((buf[ptr] & 0x40))
620                 {
621                     t30_field_type = T38_FIELD_CM_MESSAGE + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3));
622                     ptr += 2;
623                 }
624                 else
625                 {
626                     t30_field_type = (buf[ptr++] >> 3) & 0x7;
627                 }
628                 /*endif*/
629             }
630             /*endif*/
631             /* Decode field_data */
632             if (field_data_present)
633             {
634                 numocts = ((buf[ptr] << 8) | buf[ptr + 1]) + 1;
635                 msg = buf + ptr + 2;
636                 ptr += numocts + 2;
637             }
638             else
639             {
640                 numocts = 0;
641                 msg = NULL;
642             }
643             /*endif*/
644             span_log(&s->logging,
645                      SPAN_LOG_FLOW,
646                      "Rx %5d: (%d) data %s/%s + %d byte(s)\n",
647                      log_seq_no,
648                      i,
649                      t38_data_type_to_str(t30_data),
650                      t38_field_type_to_str(t30_field_type),
651                      numocts);
652             s->rx_data_handler(s, s->rx_user_data, t30_data, t30_field_type, msg, numocts);
653             s->current_rx_data_type = t30_data;
654             s->current_rx_field_type = t30_field_type;
655         }
656         /*endfor*/
657         /* Check if we finished mid byte in a version 0 packet. */
658         if (other_half)
659             ptr++;
660         /*endif*/
661         break;
662     }
663     /*endswitch*/
664     if (ptr > pkt_len)
665         return ret;
666     /*endif*/
667     return ptr;
668 }
669 /*- End of function --------------------------------------------------------*/
670 
t38_core_rx_ifp_packet(t38_core_state_t * s,const uint8_t * buf,int len,uint16_t seq_no)671 SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no)
672 {
673     int log_seq_no;
674     int ptr;
675 
676     log_seq_no = (s->check_sequence_numbers)  ?  seq_no  :  s->rx_expected_seq_no;
677 
678     if (s->check_sequence_numbers)
679     {
680         seq_no &= 0xFFFF;
681         if (seq_no != s->rx_expected_seq_no)
682         {
683             /* An expected value of -1 indicates this is the first received packet, and will accept
684                anything for that. We can't assume they will start from zero, even though they should. */
685             if (s->rx_expected_seq_no != -1)
686             {
687                 /* We have a packet with a serial number that is not in sequence. The cause could be:
688                     - 1. a repeat copy of a recent packet. Many T.38 implementations can preduce quite a lot of these.
689                     - 2. a late packet, whose point in the sequence we have already passed.
690                     - 3. the result of a hop in the sequence numbers cause by something weird from the other
691                          end. Stream switching might cause this
692                     - 4. missing packets.
693 
694                     In cases 1 and 2 we need to drop this packet. In case 2 it might make sense to try to do
695                     something with it in the terminal case. Currently we don't. For gateway operation it will be
696                     too late to do anything useful.
697                  */
698                 if (((seq_no + 1) & 0xFFFF) == s->rx_expected_seq_no)
699                 {
700                     /* Assume this is truly a repeat packet, and don't bother checking its contents. */
701                     span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Repeat packet number\n", log_seq_no);
702                     return 0;
703                 }
704                 /*endif*/
705                 /* Distinguish between a little bit out of sequence, and a huge hop. */
706                 switch (classify_seq_no_offset(s->rx_expected_seq_no, seq_no))
707                 {
708                 case -1:
709                     /* This packet is in the near past, so its late. */
710                     span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Late packet - expected %d\n", log_seq_no, s->rx_expected_seq_no);
711                     return 0;
712                 case 1:
713                     /* This packet is in the near future, so some packets have been lost */
714                     span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Missing from %d\n", log_seq_no, s->rx_expected_seq_no);
715                     s->rx_missing_handler(s, s->rx_user_data, s->rx_expected_seq_no, seq_no);
716                     s->missing_packets += (seq_no - s->rx_expected_seq_no);
717                     break;
718                 default:
719                     /* The sequence has jumped wildly */
720                     span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Sequence restart\n", log_seq_no);
721                     s->rx_missing_handler(s, s->rx_user_data, -1, -1);
722                     s->missing_packets++;
723                     break;
724                 }
725                 /*endswitch*/
726             }
727             /*endif*/
728             s->rx_expected_seq_no = seq_no;
729         }
730         /*endif*/
731     }
732     /*endif*/
733     if (len < 1)
734     {
735         span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Bad packet length - %d\n", log_seq_no, len);
736         return -1;
737     }
738     /*endif*/
739     /* The sequence numbering is defined as rolling from 0xFFFF to 0x0000. Some implementations
740        of T.38 roll from 0xFFFF to 0x0001. Isn't standardisation a wonderful thing? The T.38
741        document specifies only a small fraction of what it should, yet then they actually nail
742        something properly, people ignore it. Developers in this industry truly deserves the ****
743        **** **** **** **** **** documents they have to live with. Anyway, when the far end has a
744        broken rollover behaviour we will get a hiccup at the rollover point. Don't worry too
745        much. We will just treat the message in progress as one with some missing data. With any
746        luck a retry will ride over the problem. Rollovers don't occur that often. It takes quite
747        a few FAX pages to reach rollover. */
748     s->rx_expected_seq_no = (s->rx_expected_seq_no + 1) & 0xFFFF;
749 
750     ptr = t38_core_rx_ifp_stream(s, buf, len, seq_no);
751     if (ptr != len)
752     {
753         if (ptr >= 0)
754             span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for packet - %d %d\n", log_seq_no, ptr, len);
755         /*endif*/
756         return -1;
757     }
758     /*endif*/
759     return 0;
760 }
761 /*- End of function --------------------------------------------------------*/
762 
t38_encode_indicator(t38_core_state_t * s,uint8_t buf[],int indicator)763 static int t38_encode_indicator(t38_core_state_t *s, uint8_t buf[], int indicator)
764 {
765     int len;
766 
767     /* Build the IFP packet */
768     len = 0;
769     if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT)
770         len = 4;
771     /*endif*/
772 
773     /* Data field not present */
774     /* Indicator packet */
775     /* Type of indicator */
776     if (indicator <= T38_IND_V17_14400_LONG_TRAINING)
777     {
778         buf[len++] = (uint8_t) (indicator << 1);
779     }
780     else if (s->t38_version != 0  &&  indicator <= T38_IND_V33_14400_TRAINING)
781     {
782         buf[len++] = (uint8_t) (0x20 | (((indicator - T38_IND_V8_ANSAM) & 0xF) >> 2));
783         buf[len++] = (uint8_t) (((indicator - T38_IND_V8_ANSAM) << 6) & 0xFF);
784     }
785     else
786     {
787         len = -1;
788     }
789     /*endif*/
790     if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT)
791     {
792         /* Fill in the TPKT header (see RFC1006) */
793         /* Version */
794         buf[0] = 3;
795         /* Reserved */
796         buf[1] = 0;
797         /* Packet length - this includes the length of the header itself */
798         buf[2] = (len >> 8) & 0xFF;
799         buf[3] = len & 0xFF;
800     }
801     /*endif*/
802     return len;
803 }
804 /*- End of function --------------------------------------------------------*/
805 
t38_encode_data(t38_core_state_t * s,uint8_t buf[],int data_type,const t38_data_field_t field[],int fields)806 static int t38_encode_data(t38_core_state_t *s, uint8_t buf[], int data_type, const t38_data_field_t field[], int fields)
807 {
808     int len;
809     int i;
810     int enclen;
811     int multiplier;
812     int data_field_no;
813     const t38_data_field_t *q;
814     unsigned int encoded_len;
815     unsigned int fragment_len;
816     unsigned int value;
817     uint8_t data_field_present;
818     uint8_t field_data_present;
819     char tag[20];
820 
821     /* Build the IFP packet */
822     len = 0;
823     if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT)
824         len = 4;
825     /*endif*/
826 
827     /* There seems no valid reason why a packet would ever be generated without a data field present */
828     data_field_present = (fields > 0)  ?  0x80  :  0x00;
829 
830     /* Data field present */
831     /* Data packet */
832     /* Type of data */
833     if (data_type <= T38_DATA_V17_14400)
834     {
835         buf[len++] = (uint8_t) (data_field_present | 0x40 | (data_type << 1));
836     }
837     else if (s->t38_version != 0  &&  data_type <= T38_DATA_V33_14400)
838     {
839         buf[len++] = (uint8_t) (data_field_present | 0x60 | (((data_type - T38_DATA_V8) & 0xF) >> 2));
840         buf[len++] = (uint8_t) (((data_type - T38_DATA_V8) << 6) & 0xFF);
841     }
842     else
843     {
844         return -1;
845     }
846     /*endif*/
847 
848     if (data_field_present)
849     {
850         encoded_len = 0;
851         data_field_no = 0;
852         do
853         {
854             value = fields - encoded_len;
855             if (value < 0x80)
856             {
857                 /* 1 octet case */
858                 buf[len++] = (uint8_t) value;
859                 enclen = value;
860             }
861             else if (value < 0x4000)
862             {
863                 /* 2 octet case */
864                 buf[len++] = (uint8_t) (0x80 | ((value >> 8) & 0xFF));
865                 buf[len++] = (uint8_t) (value & 0xFF);
866                 enclen = value;
867             }
868             else
869             {
870                 /* Fragmentation case */
871                 multiplier = (value/0x4000 < 4)  ?  value/0x4000  :  4;
872                 buf[len++] = (uint8_t) (0xC0 | multiplier);
873                 enclen = 0x4000*multiplier;
874             }
875             /*endif*/
876 
877             fragment_len = enclen;
878             encoded_len += fragment_len;
879             /* Encode the elements */
880             for (i = 0;  i < (int) encoded_len;  i++)
881             {
882                 q = &field[data_field_no];
883                 field_data_present = (uint8_t) (q->field_len > 0);
884                 /* Encode field_type */
885                 if (s->t38_version == 0)
886                 {
887                     /* Original version of T.38 with a typo */
888                     if (q->field_type > T38_FIELD_T4_NON_ECM_SIG_END)
889                         return -1;
890                     /*endif*/
891                     buf[len++] = (uint8_t) ((field_data_present << 7) | (q->field_type << 4));
892                 }
893                 else
894                 {
895                     if (q->field_type <= T38_FIELD_T4_NON_ECM_SIG_END)
896                     {
897                         buf[len++] = (uint8_t) ((field_data_present << 7) | (q->field_type << 3));
898                     }
899                     else if (q->field_type <= T38_FIELD_V34RATE)
900                     {
901                         buf[len++] = (uint8_t) ((field_data_present << 7) | 0x40 | ((q->field_type - T38_FIELD_CM_MESSAGE) >> 2));
902                         buf[len++] = (uint8_t) (((q->field_type - T38_FIELD_CM_MESSAGE) << 6) & 0xC0);
903                     }
904                     else
905                     {
906                         return -1;
907                     }
908                     /*endif*/
909                 }
910                 /*endif*/
911                 /* Encode field_data */
912                 if (field_data_present)
913                 {
914                     if (q->field_len < 1  ||  q->field_len > 65535)
915                         return -1;
916                     /*endif*/
917                     buf[len++] = (uint8_t) (((q->field_len - 1) >> 8) & 0xFF);
918                     buf[len++] = (uint8_t) ((q->field_len - 1) & 0xFF);
919                     memcpy(&buf[len], q->field, q->field_len);
920                     len += q->field_len;
921                 }
922                 /*endif*/
923                 data_field_no++;
924             }
925             /*endfor*/
926         }
927         while ((int) encoded_len != fields  ||  fragment_len >= 16384);
928     }
929     /*endif*/
930 
931     for (data_field_no = 0;  data_field_no < fields;  data_field_no++)
932     {
933         span_log(&s->logging,
934                  SPAN_LOG_FLOW,
935                  "Tx %5d: (%d) data %s/%s + %d byte(s)\n",
936                  s->tx_seq_no,
937                  data_field_no,
938                  t38_data_type_to_str(data_type),
939                  t38_field_type_to_str(field[data_field_no].field_type),
940                  field[data_field_no].field_len);
941     }
942     /*endfor*/
943 
944     if (s->data_transport_protocol == T38_TRANSPORT_TCP_TPKT)
945     {
946         /* Fill in the TPKT header (see RFC1006) */
947         /* Version */
948         buf[0] = 3;
949         /* Reserved */
950         buf[1] = 0;
951         /* Packet length - this includes the length of the header itself */
952         buf[2] = (len >> 8) & 0xFF;
953         buf[3] = len & 0xFF;
954     }
955     /*endif*/
956 
957     if (span_log_test(&s->logging, SPAN_LOG_FLOW))
958     {
959         sprintf(tag, "Tx %5d: IFP", s->tx_seq_no);
960         span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len);
961     }
962     /*endif*/
963     return len;
964 }
965 /*- End of function --------------------------------------------------------*/
966 
t38_core_send_indicator(t38_core_state_t * s,int indicator)967 SPAN_DECLARE(int) t38_core_send_indicator(t38_core_state_t *s, int indicator)
968 {
969     uint8_t buf[100];
970     int len;
971     int delay;
972     int transmissions;
973 
974     delay = 0;
975     /* Only send an indicator if it represents a change of state. */
976     /* If the 0x100 bit is set in indicator it will bypass this test, and force transmission */
977     if (s->current_tx_indicator != indicator)
978     {
979         /* Zero is a valid count, to suppress the transmission of indicators when the
980            transport means they are not needed - e.g. TPKT/TCP. */
981         transmissions = (indicator & 0x100)  ?  1  :  s->category_control[T38_PACKET_CATEGORY_INDICATOR];
982         indicator &= 0xFF;
983         if (s->category_control[T38_PACKET_CATEGORY_INDICATOR])
984         {
985             if ((len = t38_encode_indicator(s, buf, indicator)) < 0)
986             {
987                 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 indicator len is %d\n", len);
988                 return len;
989             }
990             /*endif*/
991             span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: indicator %s\n", s->tx_seq_no, t38_indicator_to_str(indicator));
992             if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, transmissions) < 0)
993             {
994                 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx packet handler failure\n");
995                 return -1;
996             }
997             /*endif*/
998             s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
999             if (s->pace_transmission)
1000             {
1001                 delay = modem_startup_time[indicator].training;
1002                 if (s->allow_for_tep)
1003                     delay += modem_startup_time[indicator].tep;
1004                 /*endif*/
1005             }
1006             /*endif*/
1007         }
1008         /*endif*/
1009         s->current_tx_indicator = indicator;
1010     }
1011     /*endif*/
1012     return delay;
1013 }
1014 /*- End of function --------------------------------------------------------*/
1015 
t38_core_send_flags_delay(t38_core_state_t * s,int indicator)1016 SPAN_DECLARE(int) t38_core_send_flags_delay(t38_core_state_t *s, int indicator)
1017 {
1018     if (s->pace_transmission)
1019         return modem_startup_time[indicator].flags;
1020     /*endif*/
1021     return 0;
1022 }
1023 /*- End of function --------------------------------------------------------*/
1024 
t38_core_send_training_delay(t38_core_state_t * s,int indicator)1025 SPAN_DECLARE(int) t38_core_send_training_delay(t38_core_state_t *s, int indicator)
1026 {
1027     if (s->pace_transmission)
1028         return modem_startup_time[indicator].training;
1029     /*endif*/
1030     return 0;
1031 }
1032 /*- End of function --------------------------------------------------------*/
1033 
t38_core_send_data(t38_core_state_t * s,int data_type,int field_type,const uint8_t field[],int field_len,int category)1034 SPAN_DECLARE(int) t38_core_send_data(t38_core_state_t *s, int data_type, int field_type, const uint8_t field[], int field_len, int category)
1035 {
1036     t38_data_field_t field0;
1037     uint8_t buf[1000];
1038     int len;
1039 
1040     field0.field_type = field_type;
1041     field0.field = field;
1042     field0.field_len = field_len;
1043     if ((len = t38_encode_data(s, buf, data_type, &field0, 1)) < 0)
1044     {
1045         span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len);
1046         return len;
1047     }
1048     /*endif*/
1049     if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]) < 0)
1050     {
1051         span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx packet handler failure\n");
1052         return -1;
1053     }
1054     /*endif*/
1055     s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
1056     return 0;
1057 }
1058 /*- End of function --------------------------------------------------------*/
1059 
t38_core_send_data_multi_field(t38_core_state_t * s,int data_type,const t38_data_field_t field[],int fields,int category)1060 SPAN_DECLARE(int) t38_core_send_data_multi_field(t38_core_state_t *s, int data_type, const t38_data_field_t field[], int fields, int category)
1061 {
1062     uint8_t buf[1000];
1063     int len;
1064 
1065     if ((len = t38_encode_data(s, buf, data_type, field, fields)) < 0)
1066     {
1067         span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len);
1068         return len;
1069     }
1070     /*endif*/
1071     if (s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]) < 0)
1072     {
1073         span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Tx packet handler failure\n");
1074         return -1;
1075     }
1076     /*endif*/
1077     s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
1078     return 0;
1079 }
1080 /*- End of function --------------------------------------------------------*/
1081 
t38_set_data_rate_management_method(t38_core_state_t * s,int method)1082 SPAN_DECLARE(void) t38_set_data_rate_management_method(t38_core_state_t *s, int method)
1083 {
1084     s->data_rate_management_method = method;
1085 }
1086 /*- End of function --------------------------------------------------------*/
1087 
t38_set_data_transport_protocol(t38_core_state_t * s,int data_transport_protocol)1088 SPAN_DECLARE(void) t38_set_data_transport_protocol(t38_core_state_t *s, int data_transport_protocol)
1089 {
1090     s->data_transport_protocol = data_transport_protocol;
1091 }
1092 /*- End of function --------------------------------------------------------*/
1093 
t38_set_fill_bit_removal(t38_core_state_t * s,bool fill_bit_removal)1094 SPAN_DECLARE(void) t38_set_fill_bit_removal(t38_core_state_t *s, bool fill_bit_removal)
1095 {
1096     s->fill_bit_removal = fill_bit_removal;
1097 }
1098 /*- End of function --------------------------------------------------------*/
1099 
t38_set_mmr_transcoding(t38_core_state_t * s,bool mmr_transcoding)1100 SPAN_DECLARE(void) t38_set_mmr_transcoding(t38_core_state_t *s, bool mmr_transcoding)
1101 {
1102     s->mmr_transcoding = mmr_transcoding;
1103 }
1104 /*- End of function --------------------------------------------------------*/
1105 
t38_set_jbig_transcoding(t38_core_state_t * s,bool jbig_transcoding)1106 SPAN_DECLARE(void) t38_set_jbig_transcoding(t38_core_state_t *s, bool jbig_transcoding)
1107 {
1108     s->jbig_transcoding = jbig_transcoding;
1109 }
1110 /*- End of function --------------------------------------------------------*/
1111 
t38_set_max_buffer_size(t38_core_state_t * s,int max_buffer_size)1112 SPAN_DECLARE(void) t38_set_max_buffer_size(t38_core_state_t *s, int max_buffer_size)
1113 {
1114     s->max_buffer_size = max_buffer_size;
1115 }
1116 /*- End of function --------------------------------------------------------*/
1117 
t38_set_max_datagram_size(t38_core_state_t * s,int max_datagram_size)1118 SPAN_DECLARE(void) t38_set_max_datagram_size(t38_core_state_t *s, int max_datagram_size)
1119 {
1120     s->max_datagram_size = max_datagram_size;
1121 }
1122 /*- End of function --------------------------------------------------------*/
1123 
t38_set_t38_version(t38_core_state_t * s,int t38_version)1124 SPAN_DECLARE(void) t38_set_t38_version(t38_core_state_t *s, int t38_version)
1125 {
1126     s->t38_version = t38_version;
1127 }
1128 /*- End of function --------------------------------------------------------*/
1129 
t38_set_sequence_number_handling(t38_core_state_t * s,bool check)1130 SPAN_DECLARE(void) t38_set_sequence_number_handling(t38_core_state_t *s, bool check)
1131 {
1132     s->check_sequence_numbers = check;
1133 }
1134 /*- End of function --------------------------------------------------------*/
1135 
t38_set_pace_transmission(t38_core_state_t * s,int pace_transmission)1136 SPAN_DECLARE(void) t38_set_pace_transmission(t38_core_state_t *s, int pace_transmission)
1137 {
1138     s->pace_transmission = pace_transmission;
1139 }
1140 /*- End of function --------------------------------------------------------*/
1141 
t38_set_tep_handling(t38_core_state_t * s,bool allow_for_tep)1142 SPAN_DECLARE(void) t38_set_tep_handling(t38_core_state_t *s, bool allow_for_tep)
1143 {
1144     s->allow_for_tep = allow_for_tep;
1145 }
1146 /*- End of function --------------------------------------------------------*/
1147 
t38_set_redundancy_control(t38_core_state_t * s,int category,int setting)1148 SPAN_DECLARE(void) t38_set_redundancy_control(t38_core_state_t *s, int category, int setting)
1149 {
1150     s->category_control[category] = setting;
1151 }
1152 /*- End of function --------------------------------------------------------*/
1153 
t38_set_fastest_image_data_rate(t38_core_state_t * s,int max_rate)1154 SPAN_DECLARE(void) t38_set_fastest_image_data_rate(t38_core_state_t *s, int max_rate)
1155 {
1156     s->fastest_image_data_rate = max_rate;
1157 }
1158 /*- End of function --------------------------------------------------------*/
1159 
t38_get_fastest_image_data_rate(t38_core_state_t * s)1160 SPAN_DECLARE(int) t38_get_fastest_image_data_rate(t38_core_state_t *s)
1161 {
1162     return s->fastest_image_data_rate;
1163 }
1164 /*- End of function --------------------------------------------------------*/
1165 
t38_core_get_logging_state(t38_core_state_t * s)1166 SPAN_DECLARE(logging_state_t *) t38_core_get_logging_state(t38_core_state_t *s)
1167 {
1168     return &s->logging;
1169 }
1170 /*- End of function --------------------------------------------------------*/
1171 
t38_core_restart(t38_core_state_t * s)1172 SPAN_DECLARE(int) t38_core_restart(t38_core_state_t *s)
1173 {
1174     /* Set the initial current receive states to something invalid, so the
1175        first data received is seen as a change of state. */
1176     s->current_rx_indicator = -1;
1177     s->current_rx_data_type = -1;
1178     s->current_rx_field_type = -1;
1179 
1180     /* Set the initial current indicator state to something invalid, so the
1181        first attempt to send an indicator will work. */
1182     s->current_tx_indicator = -1;
1183 
1184     /* We have no initial expectation of the received packet sequence number.
1185        They most often start at 0 or 1 for a UDPTL transport, but random
1186        starting numbers are possible. */
1187     s->rx_expected_seq_no = -1;
1188     return 0;
1189 }
1190 /*- End of function --------------------------------------------------------*/
1191 
t38_core_init(t38_core_state_t * s,t38_rx_indicator_handler_t rx_indicator_handler,t38_rx_data_handler_t rx_data_handler,t38_rx_missing_handler_t rx_missing_handler,void * rx_user_data,t38_tx_packet_handler_t tx_packet_handler,void * tx_packet_user_data)1192 SPAN_DECLARE(t38_core_state_t *) t38_core_init(t38_core_state_t *s,
1193                                                t38_rx_indicator_handler_t rx_indicator_handler,
1194                                                t38_rx_data_handler_t rx_data_handler,
1195                                                t38_rx_missing_handler_t rx_missing_handler,
1196                                                void *rx_user_data,
1197                                                t38_tx_packet_handler_t tx_packet_handler,
1198                                                void *tx_packet_user_data)
1199 {
1200     if (s == NULL)
1201     {
1202         if ((s = (t38_core_state_t *) span_alloc(sizeof(*s))) == NULL)
1203             return NULL;
1204         /*endif*/
1205     }
1206     /*endif*/
1207     memset(s, 0, sizeof(*s));
1208     span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
1209     span_log_set_protocol(&s->logging, "T.38");
1210 
1211     /* Set some defaults for the parameters configurable from outside the
1212        T.38 domain - e.g. from SDP data. */
1213     s->data_rate_management_method = T38_DATA_RATE_MANAGEMENT_TRANSFERRED_TCF;
1214     s->data_transport_protocol = T38_TRANSPORT_UDPTL;
1215     s->fill_bit_removal = false;
1216     s->mmr_transcoding = false;
1217     s->jbig_transcoding = false;
1218     s->max_buffer_size = 400;
1219     s->max_datagram_size = 100;
1220     s->t38_version = 0;
1221     s->check_sequence_numbers = true;
1222     s->pace_transmission = true;
1223 
1224     /* Set some defaults */
1225     s->category_control[T38_PACKET_CATEGORY_INDICATOR] = 1;
1226     s->category_control[T38_PACKET_CATEGORY_CONTROL_DATA] = 1;
1227     s->category_control[T38_PACKET_CATEGORY_CONTROL_DATA_END] = 1;
1228     s->category_control[T38_PACKET_CATEGORY_IMAGE_DATA] = 1;
1229     s->category_control[T38_PACKET_CATEGORY_IMAGE_DATA_END] = 1;
1230 
1231     s->rx_indicator_handler = rx_indicator_handler;
1232     s->rx_data_handler = rx_data_handler;
1233     s->rx_missing_handler = rx_missing_handler;
1234     s->rx_user_data = rx_user_data;
1235     s->tx_packet_handler = tx_packet_handler;
1236     s->tx_packet_user_data = tx_packet_user_data;
1237 
1238     t38_core_restart(s);
1239     return s;
1240 }
1241 /*- End of function --------------------------------------------------------*/
1242 
t38_core_release(t38_core_state_t * s)1243 SPAN_DECLARE(int) t38_core_release(t38_core_state_t *s)
1244 {
1245     return 0;
1246 }
1247 /*- End of function --------------------------------------------------------*/
1248 
t38_core_free(t38_core_state_t * s)1249 SPAN_DECLARE(int) t38_core_free(t38_core_state_t *s)
1250 {
1251     if (s)
1252         span_free(s);
1253     return 0;
1254 }
1255 /*- End of function --------------------------------------------------------*/
1256 /*- End of file ------------------------------------------------------------*/
1257