5
|
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 ------------------------------------------------------------*/
|