comparison spandsp-0.0.3/spandsp-0.0.3/src/t38_core.c @ 5:f762bf195c4b

import spandsp-0.0.3
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 16:00:21 +0200
parents
children
comparison
equal deleted inserted replaced
4:26cd8f1ef0b1 5:f762bf195c4b
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 General Public License version 2, as
14 * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: t38_core.c,v 1.24 2006/12/09 04:50:12 steveu Exp $
26 */
27
28 /*! \file */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <inttypes.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <time.h>
39 #include <string.h>
40 #if defined(HAVE_TGMATH_H)
41 #include <tgmath.h>
42 #endif
43 #if defined(HAVE_MATH_H)
44 #include <math.h>
45 #endif
46 #include <assert.h>
47 #include <memory.h>
48 #include <tiffio.h>
49
50 #include "spandsp/telephony.h"
51 #include "spandsp/logging.h"
52 #include "spandsp/bit_operations.h"
53 #include "spandsp/queue.h"
54 #include "spandsp/power_meter.h"
55 #include "spandsp/complex.h"
56 #include "spandsp/tone_generate.h"
57 #include "spandsp/async.h"
58 #include "spandsp/hdlc.h"
59 #include "spandsp/fsk.h"
60 #include "spandsp/v29rx.h"
61 #include "spandsp/v29tx.h"
62 #include "spandsp/v27ter_rx.h"
63 #include "spandsp/v27ter_tx.h"
64 #if defined(ENABLE_V17)
65 #include "spandsp/v17rx.h"
66 #include "spandsp/v17tx.h"
67 #endif
68 #include "spandsp/t4.h"
69
70 #include "spandsp/t30_fcf.h"
71 #include "spandsp/t35.h"
72 #include "spandsp/t30.h"
73
74 #include "spandsp/t38_core.h"
75
76 #define ACCEPTABLE_SEQ_NO_OFFSET 2000
77
78 const char *t38_indicator(int indicator)
79 {
80 const char *type;
81
82 switch (indicator)
83 {
84 case T38_IND_NO_SIGNAL:
85 type = "no-signal";
86 break;
87 case T38_IND_CNG:
88 type = "cng";
89 break;
90 case T38_IND_CED:
91 type = "ced";
92 break;
93 case T38_IND_V21_PREAMBLE:
94 type = "v21-preamble";
95 break;
96 case T38_IND_V27TER_2400_TRAINING:
97 type = "v27-2400-training";
98 break;
99 case T38_IND_V27TER_4800_TRAINING:
100 type = "v27-4800-training";
101 break;
102 case T38_IND_V29_7200_TRAINING:
103 type = "v29-7200-training";
104 break;
105 case T38_IND_V29_9600_TRAINING:
106 type = "v29-9600-training";
107 break;
108 case T38_IND_V17_7200_SHORT_TRAINING:
109 type = "v17-7200-short-training";
110 break;
111 case T38_IND_V17_7200_LONG_TRAINING:
112 type = "v17-7200-long-training";
113 break;
114 case T38_IND_V17_9600_SHORT_TRAINING:
115 type = "v17-9600-short-training";
116 break;
117 case T38_IND_V17_9600_LONG_TRAINING:
118 type = "v17-9600-long-training";
119 break;
120 case T38_IND_V17_12000_SHORT_TRAINING:
121 type = "v17-12000-short-training";
122 break;
123 case T38_IND_V17_12000_LONG_TRAINING:
124 type = "v17-12000-long-training";
125 break;
126 case T38_IND_V17_14400_SHORT_TRAINING:
127 type = "v17-14400-short-training";
128 break;
129 case T38_IND_V17_14400_LONG_TRAINING:
130 type = "v17-14400-long-training";
131 break;
132 case T38_IND_V8_ANSAM:
133 type = "v8-ansam";
134 break;
135 case T38_IND_V8_SIGNAL:
136 type = "v8-signal";
137 break;
138 case T38_IND_V34_CNTL_CHANNEL_1200:
139 type = "v34-cntl-channel-1200";
140 break;
141 case T38_IND_V34_PRI_CHANNEL:
142 type = "v34-pri-channel";
143 break;
144 case T38_IND_V34_CC_RETRAIN:
145 type = "v34-CC-retrain";
146 break;
147 case T38_IND_V33_12000_TRAINING:
148 type = "v33-12000-training";
149 break;
150 case T38_IND_V33_14400_TRAINING:
151 type = "v33-14400-training";
152 break;
153 default:
154 type = "???";
155 break;
156 }
157 return type;
158 }
159 /*- End of function --------------------------------------------------------*/
160
161 const char *t38_data_type(int data_type)
162 {
163 const char *type;
164
165 switch (data_type)
166 {
167 case T38_DATA_V21:
168 type = "v21";
169 break;
170 case T38_DATA_V27TER_2400:
171 type = "v27-2400";
172 break;
173 case T38_DATA_V27TER_4800:
174 type = "v27-4800";
175 break;
176 case T38_DATA_V29_7200:
177 type = "v29-7200";
178 break;
179 case T38_DATA_V29_9600:
180 type = "v29-9600";
181 break;
182 case T38_DATA_V17_7200:
183 type = "v17-7200";
184 break;
185 case T38_DATA_V17_9600:
186 type = "v17-9600";
187 break;
188 case T38_DATA_V17_12000:
189 type = "v17-12000";
190 break;
191 case T38_DATA_V17_14400:
192 type = "v17-14400";
193 break;
194 case T38_DATA_V8:
195 type = "v8";
196 break;
197 case T38_DATA_V34_PRI_RATE:
198 type = "v34-pri-rate";
199 break;
200 case T38_DATA_V34_CC_1200:
201 type = "v34-CC-1200";
202 break;
203 case T38_DATA_V34_PRI_CH:
204 type = "v34-pri-vh";
205 break;
206 case T38_DATA_V33_12000:
207 type = "v33-12000";
208 break;
209 case T38_DATA_V33_14400:
210 type = "v33-14400";
211 break;
212 default:
213 type = "???";
214 break;
215 }
216 return type;
217 }
218 /*- End of function --------------------------------------------------------*/
219
220 const char *t38_field_type(int field_type)
221 {
222 const char *type;
223
224 switch (field_type)
225 {
226 case T38_FIELD_HDLC_DATA:
227 type = "hdlc-data";
228 break;
229 case T38_FIELD_HDLC_SIG_END:
230 type = "hdlc-sig-end";
231 break;
232 case T38_FIELD_HDLC_FCS_OK:
233 type = "hdlc-fcs-OK";
234 break;
235 case T38_FIELD_HDLC_FCS_BAD:
236 type = "hdlc-fcs-BAD";
237 break;
238 case T38_FIELD_HDLC_FCS_OK_SIG_END:
239 type = "hdlc-fcs-OK-sig-end";
240 break;
241 case T38_FIELD_HDLC_FCS_BAD_SIG_END:
242 type = "hdlc-fcs-BAD-sig-end";
243 break;
244 case T38_FIELD_T4_NON_ECM_DATA:
245 type = "t4-non-ecm-data";
246 break;
247 case T38_FIELD_T4_NON_ECM_SIG_END:
248 type = "t4-non-ecm-sig-end";
249 break;
250 case T38_FIELD_CM_MESSAGE:
251 type = "cm-message";
252 break;
253 case T38_FIELD_JM_MESSAGE:
254 type = "jm-message";
255 break;
256 case T38_FIELD_CI_MESSAGE:
257 type = "ci-message";
258 break;
259 case T38_FIELD_V34RATE:
260 type = "v34rate";
261 break;
262 default:
263 type = "???";
264 break;
265 }
266 return type;
267 }
268 /*- End of function --------------------------------------------------------*/
269
270 static __inline__ int classify_seq_no_offset(int expected, int actual)
271 {
272 /* Classify the mismatch between expected and actual sequence numbers
273 according to whether the actual is a little in the past (late), a
274 little in the future (some packets have been lost), or a large jump
275 that represents the sequence being lost (possibly when some RTP
276 gets dumped to a UDPTL port). */
277 /* This assumes they are not equal */
278 if (expected > actual)
279 {
280 if (expected > actual + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET)
281 {
282 /* In the near future */
283 return 1;
284 }
285 if (expected < actual + ACCEPTABLE_SEQ_NO_OFFSET)
286 {
287 /* In the recent past */
288 return -1;
289 }
290 }
291 else
292 {
293 if (expected + ACCEPTABLE_SEQ_NO_OFFSET > actual)
294 {
295 /* In the near future */
296 return 1;
297 }
298 if (expected + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET < actual)
299 {
300 /* In the recent past */
301 return -1;
302 }
303 }
304 /* There has been a huge step in the sequence */
305 return 0;
306 }
307 /*- End of function --------------------------------------------------------*/
308
309 int t38_core_rx_ifp_packet(t38_core_state_t *s, int seq_no, const uint8_t *buf, int len)
310 {
311 int i;
312 int t30_indicator;
313 int t30_data;
314 int ptr;
315 int other_half;
316 int numocts;
317 const uint8_t *msg;
318 uint8_t type;
319 unsigned int count;
320 unsigned int field_type;
321 uint8_t data_field_present;
322 uint8_t field_data_present;
323
324 if (span_log_test(&s->logging, SPAN_LOG_FLOW))
325 {
326 char tag[20];
327
328 sprintf(tag, "Rx %5d:", seq_no);
329 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len);
330 }
331 if (len < 1)
332 {
333 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad packet length - %d\n", seq_no, len);
334 return -1;
335 }
336 seq_no &= 0xFFFF;
337 if (seq_no != s->rx_expected_seq_no)
338 {
339 /* An expected value of -1 indicates this is the first received packet, and will accept
340 anything for that. We can't assume they will start from zero, even though they should. */
341 if (s->rx_expected_seq_no != -1)
342 {
343 /* We have a packet with a serial number that is not in sequence. The cause could be:
344 - 1. a repeat copy of a recent packet. Many T.38 implementations can preduce quite a lot of these.
345 - 2. a late packet, whose point in the sequence we have already passed.
346 - 3. the result of a hop in the sequence numbers cause by something weird from the other
347 end. Stream switching might cause this
348 - 4. missing packets.
349
350 In cases 1 and 2 we need to drop this packet. In case 2 it might make sense to try to do
351 something with it in the terminal case. Currently we don't. For gateway operation it will be
352 too late to do anything useful.
353 */
354 if (((seq_no + 1) & 0xFFFF) == s->rx_expected_seq_no)
355 {
356 /* Assume this is truly a repeat packet, and don't bother checking its contents. */
357 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Repeat packet number\n", seq_no);
358 return 0;
359 }
360 /* Distinguish between a little bit out of sequence, and a huge hop. */
361 switch (classify_seq_no_offset(s->rx_expected_seq_no, seq_no))
362 {
363 case -1:
364 /* This packet is in the near past, so its late. */
365 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Late packet - expected %d\n", seq_no, s->rx_expected_seq_no);
366 return 0;
367 case 1:
368 /* This packet is in the near future, so some packets have been lost */
369 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Missing from %d\n", seq_no, s->rx_expected_seq_no);
370 s->rx_missing_handler(s, s->rx_user_data, s->rx_expected_seq_no, seq_no);
371 s->missing_packets += (seq_no - s->rx_expected_seq_no);
372 break;
373 default:
374 /* The sequence has jumped wildly */
375 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Sequence restart\n", seq_no);
376 s->rx_missing_handler(s, s->rx_user_data, -1, -1);
377 s->missing_packets++;
378 break;
379 }
380 }
381 s->rx_expected_seq_no = seq_no;
382 }
383 s->rx_expected_seq_no = (s->rx_expected_seq_no + 1) & 0xFFFF;
384
385 data_field_present = (buf[0] >> 7) & 1;
386 type = (buf[0] >> 6) & 1;
387 ptr = 0;
388 switch (type)
389 {
390 case T38_TYPE_OF_MSG_T30_INDICATOR:
391 /* Indicators should never have a data field */
392 if (data_field_present)
393 {
394 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Data field with indicator\n", seq_no);
395 return -1;
396 }
397 if ((buf[0] & 0x20))
398 {
399 /* Extension */
400 if (len != 2)
401 {
402 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Invalid length for indicator\n", seq_no);
403 return -1;
404 }
405 t30_indicator = T38_IND_V8_ANSAM + (((buf[0] << 2) & 0x3C) | ((buf[1] >> 6) & 0x3));
406 if (t30_indicator > T38_IND_V33_14400_TRAINING)
407 {
408 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown indicator - %d\n", seq_no, t30_indicator);
409 return -1;
410 }
411 }
412 else
413 {
414 if (len != 1)
415 {
416 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Invalid length for indicator\n", seq_no);
417 return -1;
418 }
419 t30_indicator = (buf[0] >> 1) & 0xF;
420 }
421 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: indicator %s\n", seq_no, t38_indicator(t30_indicator));
422 s->rx_indicator_handler(s, s->rx_user_data, t30_indicator);
423 /* This must come after the indicator handler, so the handler routine sees the existing state of the
424 indicator. */
425 s->current_rx_indicator = t30_indicator;
426 break;
427 case T38_TYPE_OF_MSG_T30_DATA:
428 if ((buf[0] & 0x20))
429 {
430 /* Extension */
431 if (len < 2)
432 {
433 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Invalid length for data\n", seq_no);
434 return -1;
435 }
436 t30_data = T38_DATA_V8 + (((buf[0] << 2) & 0x3C) | ((buf[1] >> 6) & 0x3));
437 if (t30_data > T38_DATA_V33_14400)
438 {
439 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown data type - %d\n", seq_no, t30_data);
440 return -1;
441 }
442 ptr = 2;
443 }
444 else
445 {
446 t30_data = (buf[0] >> 1) & 0xF;
447 if (t30_data > T38_DATA_V17_14400)
448 {
449 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown data type - %d\n", seq_no, t30_data);
450 return -1;
451 }
452 ptr = 1;
453 }
454 if (!data_field_present)
455 {
456 /* This is kinda weird, but I guess if the length checks out we accept it. */
457 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Data type with no data field\n", seq_no);
458 if (ptr != len)
459 {
460 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no);
461 return -1;
462 }
463 break;
464 }
465 if (ptr >= len)
466 {
467 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no);
468 return -1;
469 }
470 count = buf[ptr++];
471 //printf("Count is %d\n", count);
472 other_half = FALSE;
473 for (i = 0; i < (int) count; i++)
474 {
475 if (ptr >= len)
476 {
477 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no);
478 return -1;
479 }
480 if (s->t38_version == 0)
481 {
482 /* The original version of T.38 with a typo in the ASN.1 spec. */
483 if (other_half)
484 {
485 /* The lack of a data field in the previous message means
486 we are currently in the middle of an octet. */
487 field_data_present = (buf[ptr] >> 3) & 1;
488 /* Decode field_type */
489 field_type = buf[ptr] & 0x7;
490 ptr++;
491 other_half = FALSE;
492 }
493 else
494 {
495 field_data_present = (buf[ptr] >> 7) & 1;
496 /* Decode field_type */
497 field_type = (buf[ptr] >> 4) & 0x7;
498 if (field_data_present)
499 ptr++;
500 else
501 other_half = TRUE;
502 }
503 if (field_type > T38_FIELD_T4_NON_ECM_SIG_END)
504 {
505 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown field type - %d\n", seq_no, field_type);
506 return -1;
507 }
508 }
509 else
510 {
511 field_data_present = (buf[ptr] >> 7) & 1;
512 /* Decode field_type */
513 if ((buf[ptr] & 0x40))
514 {
515 if (ptr > len - 2)
516 {
517 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no);
518 return -1;
519 }
520 field_type = T38_FIELD_CM_MESSAGE + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3));
521 if (field_type > T38_FIELD_V34RATE)
522 {
523 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown field type - %d\n", seq_no, field_type);
524 return -1;
525 }
526 ptr++;
527 }
528 else
529 {
530 field_type = (buf[ptr++] >> 3) & 0x7;
531 if (field_type > T38_FIELD_T4_NON_ECM_SIG_END)
532 {
533 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown field type - %d\n", seq_no, field_type);
534 return -1;
535 }
536 }
537 }
538 /* Decode field_data */
539 if (field_data_present)
540 {
541 if (ptr > len - 2)
542 {
543 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no);
544 return -1;
545 }
546 numocts = ((buf[ptr] << 8) | buf[ptr + 1]) + 1;
547 msg = buf + ptr + 2;
548 ptr += numocts + 2;
549 }
550 else
551 {
552 numocts = 0;
553 msg = NULL;
554 }
555 if (ptr > len)
556 {
557 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no);
558 return -1;
559 }
560 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: data type %s/%s + %d byte(s)\n", seq_no, t38_data_type(t30_data), t38_field_type(field_type), numocts);
561 s->rx_data_handler(s, s->rx_user_data, t30_data, field_type, msg, numocts);
562 }
563 if (ptr != len)
564 {
565 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no);
566 return -1;
567 }
568 break;
569 }
570 return 0;
571 }
572 /*- End of function --------------------------------------------------------*/
573
574 static int t38_encode_data(t38_core_state_t *s, uint8_t buf[], int data_type, int field_type, const uint8_t *msg, int msglen)
575 {
576 int len;
577 int i;
578 int enclen;
579 int multiplier;
580 int data_field_no;
581 int data_field_count;
582 data_field_element_t data_field_seq[10];
583 data_field_element_t *q;
584 unsigned int encoded_len;
585 unsigned int fragment_len;
586 unsigned int value;
587 uint8_t data_field_present;
588
589 span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: data type %s/%s + %d byte(s)\n", s->tx_seq_no, t38_data_type(data_type), t38_field_type(field_type), msglen);
590
591 /* Build the IFP packet */
592 data_field_present = TRUE;
593
594 data_field_seq[0].field_data_present = (uint8_t) (msglen > 0);
595 data_field_seq[0].field_type = field_type;
596 data_field_seq[0].field_data.numocts = msglen;
597 data_field_seq[0].field_data.data = msg;
598 data_field_count = 1;
599
600 len = 0;
601 /* Data field present */
602 /* Data packet */
603 /* Type of data */
604 if (data_type <= T38_DATA_V17_14400)
605 {
606 buf[len++] = (uint8_t) ((data_field_present << 7) | 0x40 | (data_type << 1));
607 }
608 else if (data_type <= T38_DATA_V33_14400)
609 {
610 buf[len++] = (uint8_t) ((data_field_present << 7) | 0x60 | (((data_type - T38_DATA_V8) & 0xF) >> 2));
611 buf[len++] = (uint8_t) (((data_type - T38_DATA_V8) << 6) & 0xFF);
612 }
613 else
614 {
615 return -1;
616 }
617 if (data_field_present)
618 {
619 encoded_len = 0;
620 data_field_no = 0;
621 do
622 {
623 value = data_field_count - encoded_len;
624 if (value < 0x80)
625 {
626 /* 1 octet case */
627 buf[len++] = (uint8_t) value;
628 enclen = value;
629 }
630 else if (value < 0x4000)
631 {
632 /* 2 octet case */
633 buf[len++] = (uint8_t) (0x80 | ((value >> 8) & 0xFF));
634 buf[len++] = (uint8_t) (value & 0xFF);
635 enclen = value;
636 }
637 else
638 {
639 /* Fragmentation case */
640 multiplier = (value/0x4000 < 4) ? value/0x4000 : 4;
641 buf[len++] = (uint8_t) (0xC0 | multiplier);
642 enclen = 0x4000*multiplier;
643 }
644
645 fragment_len = enclen;
646 encoded_len += fragment_len;
647 /* Encode the elements */
648 for (i = 0; i < (int) encoded_len; i++)
649 {
650 q = &data_field_seq[data_field_no];
651 /* Encode field_type */
652 if (s->t38_version == 0)
653 {
654 /* Original version of T.38 with a typo */
655 if (q->field_type > T38_FIELD_T4_NON_ECM_SIG_END)
656 return -1;
657 buf[len++] = (uint8_t) ((q->field_data_present << 7) | (q->field_type << 4));
658 }
659 else
660 {
661 if (q->field_type <= T38_FIELD_T4_NON_ECM_SIG_END)
662 {
663 buf[len++] = (uint8_t) ((q->field_data_present << 7) | (q->field_type << 3));
664 }
665 else if (q->field_type <= T38_FIELD_V34RATE)
666 {
667 buf[len++] = (uint8_t) ((q->field_data_present << 7) | 0x40 | (((q->field_type - T38_FIELD_CM_MESSAGE) & 0x1F) >> 1));
668 buf[len++] = (uint8_t) (((q->field_type - T38_FIELD_CM_MESSAGE) << 7) & 0xFF);
669 }
670 else
671 {
672 return -1;
673 }
674 }
675 /* Encode field_data */
676 if (q->field_data_present)
677 {
678 if (q->field_data.numocts < 1 || q->field_data.numocts > 65535)
679 return -1;
680 buf[len++] = (uint8_t) (((q->field_data.numocts - 1) >> 8) & 0xFF);
681 buf[len++] = (uint8_t) ((q->field_data.numocts - 1) & 0xFF);
682 memcpy(buf + len, q->field_data.data, q->field_data.numocts);
683 len += q->field_data.numocts;
684 }
685 data_field_no++;
686 }
687 }
688 while (data_field_count != (int) encoded_len || fragment_len >= 16384);
689 }
690
691 if (span_log_test(&s->logging, SPAN_LOG_FLOW))
692 {
693 char tag[20];
694
695 sprintf(tag, "Tx %5d:", s->tx_seq_no);
696 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len);
697 }
698 return len;
699 }
700 /*- End of function --------------------------------------------------------*/
701
702 static int t38_encode_indicator(t38_core_state_t *s, uint8_t buf[], int indicator)
703 {
704 int len;
705
706 span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: indicator %s\n", s->tx_seq_no, t38_indicator(indicator));
707
708 /* Build the IFP packet */
709 /* Data field not present */
710 /* Indicator packet */
711 /* Type of indicator */
712 if (indicator <= T38_IND_V17_14400_LONG_TRAINING)
713 {
714 buf[0] = (uint8_t) (indicator << 1);
715 len = 1;
716 }
717 else if (indicator <= T38_IND_V33_14400_TRAINING)
718 {
719 buf[0] = (uint8_t) (0x20 | (((indicator - T38_IND_V8_ANSAM) & 0xF) >> 2));
720 buf[1] = (uint8_t) (((indicator - T38_IND_V8_ANSAM) << 6) & 0xFF);
721 len = 2;
722 }
723 else
724 {
725 len = -1;
726 }
727 return len;
728 }
729 /*- End of function --------------------------------------------------------*/
730
731 int t38_core_send_data(t38_core_state_t *s, int data_type, int field_type, const uint8_t *msg, int msglen)
732 {
733 uint8_t buf[100];
734 int len;
735
736 if ((len = t38_encode_data(s, buf, data_type, field_type, msg, msglen)) > 0)
737 s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, 1);
738 else
739 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len);
740 s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
741 return 0;
742 }
743 /*- End of function --------------------------------------------------------*/
744
745 int t38_core_send_indicator(t38_core_state_t *s, int indicator, int count)
746 {
747 uint8_t buf[100];
748 int len;
749
750 if ((len = t38_encode_indicator(s, buf, indicator)) > 0)
751 {
752 s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, count);
753 s->current_tx_indicator = indicator;
754 }
755 else
756 {
757 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 indicator len is %d\n", len);
758 }
759 s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF;
760 return 0;
761 }
762 /*- End of function --------------------------------------------------------*/
763
764 void t38_set_data_rate_management_method(t38_core_state_t *s, int method)
765 {
766 s->data_rate_management_method = method;
767 }
768 /*- End of function --------------------------------------------------------*/
769
770 void t38_set_data_transport_protocol(t38_core_state_t *s, int data_transport_protocol)
771 {
772 s->data_transport_protocol = data_transport_protocol;
773 }
774 /*- End of function --------------------------------------------------------*/
775
776 void t38_set_fill_bit_removal(t38_core_state_t *s, int fill_bit_removal)
777 {
778 s->fill_bit_removal = fill_bit_removal;
779 }
780 /*- End of function --------------------------------------------------------*/
781
782 void t38_set_mmr_transcoding(t38_core_state_t *s, int mmr_transcoding)
783 {
784 s->mmr_transcoding = mmr_transcoding;
785 }
786 /*- End of function --------------------------------------------------------*/
787
788 void t38_set_jbig_transcoding(t38_core_state_t *s, int jbig_transcoding)
789 {
790 s->jbig_transcoding = jbig_transcoding;
791 }
792 /*- End of function --------------------------------------------------------*/
793
794 void t38_set_max_buffer_size(t38_core_state_t *s, int max_buffer_size)
795 {
796 s->max_buffer_size = max_buffer_size;
797 }
798 /*- End of function --------------------------------------------------------*/
799
800 void t38_set_max_datagram_size(t38_core_state_t *s, int max_datagram_size)
801 {
802 s->max_datagram_size = max_datagram_size;
803 }
804 /*- End of function --------------------------------------------------------*/
805
806 void t38_set_t38_version(t38_core_state_t *s, int t38_version)
807 {
808 s->t38_version = t38_version;
809 }
810 /*- End of function --------------------------------------------------------*/
811
812 int t38_get_fastest_image_data_rate(t38_core_state_t *s)
813 {
814 return s->fastest_image_data_rate;
815 }
816 /*- End of function --------------------------------------------------------*/
817
818 t38_core_state_t *t38_core_init(t38_core_state_t *s,
819 t38_rx_indicator_handler_t *rx_indicator_handler,
820 t38_rx_data_handler_t *rx_data_handler,
821 t38_rx_missing_handler_t *rx_missing_handler,
822 void *rx_user_data)
823 {
824 memset(s, 0, sizeof(*s));
825 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
826 span_log_set_protocol(&s->logging, "T.38");
827
828 span_log(&s->logging, SPAN_LOG_FLOW, "Start tx document\n");
829 s->data_rate_management_method = 2;
830 s->data_transport_protocol = T38_TRANSPORT_UDPTL;
831 s->fill_bit_removal = FALSE;
832 s->mmr_transcoding = FALSE;
833 s->jbig_transcoding = FALSE;
834 s->max_buffer_size = 400;
835 s->max_datagram_size = 100;
836 s->t38_version = 0;
837 s->iaf = FALSE;
838 s->current_rx_indicator = -1;
839
840 s->rx_indicator_handler = rx_indicator_handler;
841 s->rx_data_handler = rx_data_handler;
842 s->rx_missing_handler = rx_missing_handler;
843 s->rx_user_data = rx_user_data;
844
845 s->rx_expected_seq_no = -1;
846 return s;
847 }
848 /*- End of function --------------------------------------------------------*/
849 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.