Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/t38_core.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
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 * $Id: t38_core.c,v 1.54 2009/10/09 14:53:57 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #if defined(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 "floating_fudge.h" | |
47 #include <assert.h> | |
48 #include <memory.h> | |
49 #include <tiffio.h> | |
50 | |
51 #include "spandsp/telephony.h" | |
52 #include "spandsp/logging.h" | |
53 #include "spandsp/bit_operations.h" | |
54 #include "spandsp/t38_core.h" | |
55 | |
56 #include "spandsp/private/logging.h" | |
57 #include "spandsp/private/t38_core.h" | |
58 | |
59 #define ACCEPTABLE_SEQ_NO_OFFSET 2000 | |
60 | |
61 /* The times for training, the optional TEP, and the HDLC preamble, for all the modem options, in ms. | |
62 Note that the preamble for V.21 is 1s+-15%, and for the other modems is 200ms+100ms. */ | |
63 static const struct | |
64 { | |
65 int tep; | |
66 int training; | |
67 int flags; | |
68 } modem_startup_time[] = | |
69 { | |
70 { 0, 75000, 0}, /* T38_IND_NO_SIGNAL */ | |
71 { 0, 0, 0}, /* T38_IND_CNG */ | |
72 { 0, 3000000, 0}, /* T38_IND_CED */ | |
73 { 0, 0, 1000000}, /* T38_IND_V21_PREAMBLE */ /* TODO: 850ms should be OK for this, but it causes trouble with some ATAs. Why? */ | |
74 { 215000, 943000, 200000}, /* T38_IND_V27TER_2400_TRAINING */ | |
75 { 215000, 708000, 200000}, /* T38_IND_V27TER_4800_TRAINING */ | |
76 { 215000, 234000, 200000}, /* T38_IND_V29_7200_TRAINING */ | |
77 { 215000, 234000, 200000}, /* T38_IND_V29_9600_TRAINING */ | |
78 { 215000, 142000, 200000}, /* T38_IND_V17_7200_SHORT_TRAINING */ | |
79 { 215000, 1393000, 200000}, /* T38_IND_V17_7200_LONG_TRAINING */ | |
80 { 215000, 142000, 200000}, /* T38_IND_V17_9600_SHORT_TRAINING */ | |
81 { 215000, 1393000, 200000}, /* T38_IND_V17_9600_LONG_TRAINING */ | |
82 { 215000, 142000, 200000}, /* T38_IND_V17_12000_SHORT_TRAINING */ | |
83 { 215000, 1393000, 200000}, /* T38_IND_V17_12000_LONG_TRAINING */ | |
84 { 215000, 142000, 200000}, /* T38_IND_V17_14400_SHORT_TRAINING */ | |
85 { 215000, 1393000, 200000}, /* T38_IND_V17_14400_LONG_TRAINING */ | |
86 { 215000, 0, 0}, /* T38_IND_V8_ANSAM */ | |
87 { 215000, 0, 0}, /* T38_IND_V8_SIGNAL */ | |
88 { 215000, 0, 0}, /* T38_IND_V34_CNTL_CHANNEL_1200 */ | |
89 { 215000, 0, 0}, /* T38_IND_V34_PRI_CHANNEL */ | |
90 { 215000, 0, 0}, /* T38_IND_V34_CC_RETRAIN */ | |
91 { 215000, 0, 0}, /* T38_IND_V33_12000_TRAINING */ | |
92 { 215000, 0, 0} /* T38_IND_V33_14400_TRAINING */ | |
93 }; | |
94 | |
95 SPAN_DECLARE(const char *) t38_indicator_to_str(int indicator) | |
96 { | |
97 switch (indicator) | |
98 { | |
99 case T38_IND_NO_SIGNAL: | |
100 return "no-signal"; | |
101 case T38_IND_CNG: | |
102 return "cng"; | |
103 case T38_IND_CED: | |
104 return "ced"; | |
105 case T38_IND_V21_PREAMBLE: | |
106 return "v21-preamble"; | |
107 case T38_IND_V27TER_2400_TRAINING: | |
108 return "v27-2400-training"; | |
109 case T38_IND_V27TER_4800_TRAINING: | |
110 return "v27-4800-training"; | |
111 case T38_IND_V29_7200_TRAINING: | |
112 return "v29-7200-training"; | |
113 case T38_IND_V29_9600_TRAINING: | |
114 return "v29-9600-training"; | |
115 case T38_IND_V17_7200_SHORT_TRAINING: | |
116 return "v17-7200-short-training"; | |
117 case T38_IND_V17_7200_LONG_TRAINING: | |
118 return "v17-7200-long-training"; | |
119 case T38_IND_V17_9600_SHORT_TRAINING: | |
120 return "v17-9600-short-training"; | |
121 case T38_IND_V17_9600_LONG_TRAINING: | |
122 return "v17-9600-long-training"; | |
123 case T38_IND_V17_12000_SHORT_TRAINING: | |
124 return "v17-12000-short-training"; | |
125 case T38_IND_V17_12000_LONG_TRAINING: | |
126 return "v17-12000-long-training"; | |
127 case T38_IND_V17_14400_SHORT_TRAINING: | |
128 return "v17-14400-short-training"; | |
129 case T38_IND_V17_14400_LONG_TRAINING: | |
130 return "v17-14400-long-training"; | |
131 case T38_IND_V8_ANSAM: | |
132 return "v8-ansam"; | |
133 case T38_IND_V8_SIGNAL: | |
134 return "v8-signal"; | |
135 case T38_IND_V34_CNTL_CHANNEL_1200: | |
136 return "v34-cntl-channel-1200"; | |
137 case T38_IND_V34_PRI_CHANNEL: | |
138 return "v34-pri-channel"; | |
139 case T38_IND_V34_CC_RETRAIN: | |
140 return "v34-CC-retrain"; | |
141 case T38_IND_V33_12000_TRAINING: | |
142 return "v33-12000-training"; | |
143 case T38_IND_V33_14400_TRAINING: | |
144 return "v33-14400-training"; | |
145 } | |
146 return "???"; | |
147 } | |
148 /*- End of function --------------------------------------------------------*/ | |
149 | |
150 SPAN_DECLARE(const char *) t38_data_type_to_str(int data_type) | |
151 { | |
152 switch (data_type) | |
153 { | |
154 case T38_DATA_V21: | |
155 return "v21"; | |
156 case T38_DATA_V27TER_2400: | |
157 return "v27-2400"; | |
158 case T38_DATA_V27TER_4800: | |
159 return "v27-4800"; | |
160 case T38_DATA_V29_7200: | |
161 return "v29-7200"; | |
162 case T38_DATA_V29_9600: | |
163 return "v29-9600"; | |
164 case T38_DATA_V17_7200: | |
165 return "v17-7200"; | |
166 case T38_DATA_V17_9600: | |
167 return "v17-9600"; | |
168 case T38_DATA_V17_12000: | |
169 return "v17-12000"; | |
170 case T38_DATA_V17_14400: | |
171 return "v17-14400"; | |
172 case T38_DATA_V8: | |
173 return "v8"; | |
174 case T38_DATA_V34_PRI_RATE: | |
175 return "v34-pri-rate"; | |
176 case T38_DATA_V34_CC_1200: | |
177 return "v34-CC-1200"; | |
178 case T38_DATA_V34_PRI_CH: | |
179 return "v34-pri-vh"; | |
180 case T38_DATA_V33_12000: | |
181 return "v33-12000"; | |
182 case T38_DATA_V33_14400: | |
183 return "v33-14400"; | |
184 } | |
185 return "???"; | |
186 } | |
187 /*- End of function --------------------------------------------------------*/ | |
188 | |
189 SPAN_DECLARE(const char *) t38_field_type_to_str(int field_type) | |
190 { | |
191 switch (field_type) | |
192 { | |
193 case T38_FIELD_HDLC_DATA: | |
194 return "hdlc-data"; | |
195 case T38_FIELD_HDLC_SIG_END: | |
196 return "hdlc-sig-end"; | |
197 case T38_FIELD_HDLC_FCS_OK: | |
198 return "hdlc-fcs-OK"; | |
199 case T38_FIELD_HDLC_FCS_BAD: | |
200 return "hdlc-fcs-BAD"; | |
201 case T38_FIELD_HDLC_FCS_OK_SIG_END: | |
202 return "hdlc-fcs-OK-sig-end"; | |
203 case T38_FIELD_HDLC_FCS_BAD_SIG_END: | |
204 return "hdlc-fcs-BAD-sig-end"; | |
205 case T38_FIELD_T4_NON_ECM_DATA: | |
206 return "t4-non-ecm-data"; | |
207 case T38_FIELD_T4_NON_ECM_SIG_END: | |
208 return "t4-non-ecm-sig-end"; | |
209 case T38_FIELD_CM_MESSAGE: | |
210 return "cm-message"; | |
211 case T38_FIELD_JM_MESSAGE: | |
212 return "jm-message"; | |
213 case T38_FIELD_CI_MESSAGE: | |
214 return "ci-message"; | |
215 case T38_FIELD_V34RATE: | |
216 return "v34rate"; | |
217 } | |
218 return "???"; | |
219 } | |
220 /*- End of function --------------------------------------------------------*/ | |
221 | |
222 SPAN_DECLARE(const char *) t38_cm_profile_to_str(int profile) | |
223 { | |
224 switch (profile) | |
225 { | |
226 case '1': | |
227 return "G3 FAX sending terminal"; | |
228 case '2': | |
229 return "G3 FAX receiving terminal"; | |
230 case '3': | |
231 return "V.34 HDX and G3 FAX sending terminal"; | |
232 case '4': | |
233 return "V.34 HDX and G3 FAX receiving terminal"; | |
234 case '5': | |
235 return "V.34 HDX-only FAX sending terminal"; | |
236 case '6': | |
237 return "V.34 HDX-only FAX receiving terminal"; | |
238 } | |
239 return "???"; | |
240 } | |
241 /*- End of function --------------------------------------------------------*/ | |
242 | |
243 SPAN_DECLARE(const char *) t38_jm_to_str(const uint8_t *data, int len) | |
244 { | |
245 if (len < 2) | |
246 return "???"; | |
247 switch (data[0]) | |
248 { | |
249 case 'A': | |
250 switch (data[1]) | |
251 { | |
252 case '0': | |
253 return "ACK"; | |
254 } | |
255 break; | |
256 case 'N': | |
257 switch (data[1]) | |
258 { | |
259 case '0': | |
260 return "NACK: No compatible mode available"; | |
261 case '1': | |
262 /* Response for profiles 1 and 2 */ | |
263 return "NACK: No V.34 FAX, use G3 FAX"; | |
264 case '2': | |
265 /* Response for profiles 5 and 6 */ | |
266 return "NACK: V.34 only FAX."; | |
267 } | |
268 break; | |
269 } | |
270 return "???"; | |
271 } | |
272 /*- End of function --------------------------------------------------------*/ | |
273 | |
274 SPAN_DECLARE(int) t38_v34rate_to_bps(const uint8_t *data, int len) | |
275 { | |
276 int i; | |
277 int rate; | |
278 | |
279 if (len < 3) | |
280 return -1; | |
281 for (i = 0, rate = 0; i < 3; i++) | |
282 { | |
283 if (data[i] < '0' || data[i] > '9') | |
284 return -1; | |
285 rate = rate*10 + data[i] - '0'; | |
286 } | |
287 return rate*100; | |
288 } | |
289 /*- End of function --------------------------------------------------------*/ | |
290 | |
291 static __inline__ int classify_seq_no_offset(int expected, int actual) | |
292 { | |
293 /* Classify the mismatch between expected and actual sequence numbers | |
294 according to whether the actual is a little in the past (late), a | |
295 little in the future (some packets have been lost), or a large jump | |
296 that represents the sequence being lost (possibly when some RTP | |
297 gets dumped to a UDPTL port). */ | |
298 /* This assumes they are not equal */ | |
299 if (expected > actual) | |
300 { | |
301 if (expected > actual + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET) | |
302 { | |
303 /* In the near future */ | |
304 return 1; | |
305 } | |
306 if (expected < actual + ACCEPTABLE_SEQ_NO_OFFSET) | |
307 { | |
308 /* In the recent past */ | |
309 return -1; | |
310 } | |
311 } | |
312 else | |
313 { | |
314 if (expected + ACCEPTABLE_SEQ_NO_OFFSET > actual) | |
315 { | |
316 /* In the near future */ | |
317 return 1; | |
318 } | |
319 if (expected + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET < actual) | |
320 { | |
321 /* In the recent past */ | |
322 return -1; | |
323 } | |
324 } | |
325 /* There has been a huge step in the sequence */ | |
326 return 0; | |
327 } | |
328 /*- End of function --------------------------------------------------------*/ | |
329 | |
330 SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no) | |
331 { | |
332 int i; | |
333 int t30_indicator; | |
334 int t30_data; | |
335 int ptr; | |
336 int other_half; | |
337 int numocts; | |
338 int log_seq_no; | |
339 const uint8_t *msg; | |
340 unsigned int count; | |
341 unsigned int t30_field_type; | |
342 uint8_t type; | |
343 uint8_t data_field_present; | |
344 uint8_t field_data_present; | |
345 char tag[20]; | |
346 | |
347 log_seq_no = (s->check_sequence_numbers) ? seq_no : s->rx_expected_seq_no; | |
348 | |
349 if (span_log_test(&s->logging, SPAN_LOG_FLOW)) | |
350 { | |
351 sprintf(tag, "Rx %5d: IFP", log_seq_no); | |
352 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len); | |
353 } | |
354 if (len < 1) | |
355 { | |
356 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Bad packet length - %d\n", log_seq_no, len); | |
357 return -1; | |
358 } | |
359 if (s->check_sequence_numbers) | |
360 { | |
361 seq_no &= 0xFFFF; | |
362 if (seq_no != s->rx_expected_seq_no) | |
363 { | |
364 /* An expected value of -1 indicates this is the first received packet, and will accept | |
365 anything for that. We can't assume they will start from zero, even though they should. */ | |
366 if (s->rx_expected_seq_no != -1) | |
367 { | |
368 /* We have a packet with a serial number that is not in sequence. The cause could be: | |
369 - 1. a repeat copy of a recent packet. Many T.38 implementations can preduce quite a lot of these. | |
370 - 2. a late packet, whose point in the sequence we have already passed. | |
371 - 3. the result of a hop in the sequence numbers cause by something weird from the other | |
372 end. Stream switching might cause this | |
373 - 4. missing packets. | |
374 | |
375 In cases 1 and 2 we need to drop this packet. In case 2 it might make sense to try to do | |
376 something with it in the terminal case. Currently we don't. For gateway operation it will be | |
377 too late to do anything useful. | |
378 */ | |
379 if (((seq_no + 1) & 0xFFFF) == s->rx_expected_seq_no) | |
380 { | |
381 /* Assume this is truly a repeat packet, and don't bother checking its contents. */ | |
382 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Repeat packet number\n", log_seq_no); | |
383 return 0; | |
384 } | |
385 /* Distinguish between a little bit out of sequence, and a huge hop. */ | |
386 switch (classify_seq_no_offset(s->rx_expected_seq_no, seq_no)) | |
387 { | |
388 case -1: | |
389 /* This packet is in the near past, so its late. */ | |
390 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Late packet - expected %d\n", log_seq_no, s->rx_expected_seq_no); | |
391 return 0; | |
392 case 1: | |
393 /* This packet is in the near future, so some packets have been lost */ | |
394 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Missing from %d\n", log_seq_no, s->rx_expected_seq_no); | |
395 s->rx_missing_handler(s, s->rx_user_data, s->rx_expected_seq_no, seq_no); | |
396 s->missing_packets += (seq_no - s->rx_expected_seq_no); | |
397 break; | |
398 default: | |
399 /* The sequence has jumped wildly */ | |
400 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Sequence restart\n", log_seq_no); | |
401 s->rx_missing_handler(s, s->rx_user_data, -1, -1); | |
402 s->missing_packets++; | |
403 break; | |
404 } | |
405 } | |
406 s->rx_expected_seq_no = seq_no; | |
407 } | |
408 } | |
409 /* The sequence numbering is defined as rolling from 0xFFFF to 0x0000. Some implementations | |
410 of T.38 roll from 0xFFFF to 0x0001. Isn't standardisation a wonderful thing? The T.38 | |
411 document specifies only a small fraction of what it should, yet then they actually nail | |
412 something properly, people ignore it. Developers in this industry truly deserves the **** | |
413 **** **** **** **** **** documents they have to live with. Anyway, when the far end has a | |
414 broken rollover behaviour we will get a hiccup at the rollover point. Don't worry too | |
415 much. We will just treat the message in progress as one with some missing data. With any | |
416 luck a retry will ride over the problem. Rollovers don't occur that often. It takes quite | |
417 a few FAX pages to reach rollover. */ | |
418 s->rx_expected_seq_no = (s->rx_expected_seq_no + 1) & 0xFFFF; | |
419 data_field_present = (buf[0] >> 7) & 1; | |
420 type = (buf[0] >> 6) & 1; | |
421 ptr = 0; | |
422 switch (type) | |
423 { | |
424 case T38_TYPE_OF_MSG_T30_INDICATOR: | |
425 /* Indicators should never have a data field */ | |
426 if (data_field_present) | |
427 { | |
428 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Data field with indicator\n", log_seq_no); | |
429 return -1; | |
430 } | |
431 /* Any received indicator should mean we no longer have a valid concept of "last received data/field type". */ | |
432 s->current_rx_data_type = -1; | |
433 s->current_rx_field_type = -1; | |
434 if ((buf[0] & 0x20)) | |
435 { | |
436 /* Extension */ | |
437 if (len != 2) | |
438 { | |
439 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for indicator (A)\n", log_seq_no); | |
440 return -1; | |
441 } | |
442 t30_indicator = T38_IND_V8_ANSAM + (((buf[0] << 2) & 0x3C) | ((buf[1] >> 6) & 0x3)); | |
443 if (t30_indicator > T38_IND_V33_14400_TRAINING) | |
444 { | |
445 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown indicator - %d\n", log_seq_no, t30_indicator); | |
446 return -1; | |
447 } | |
448 } | |
449 else | |
450 { | |
451 if (len != 1) | |
452 { | |
453 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for indicator (B)\n", log_seq_no); | |
454 return -1; | |
455 } | |
456 t30_indicator = (buf[0] >> 1) & 0xF; | |
457 } | |
458 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: indicator %s\n", log_seq_no, t38_indicator_to_str(t30_indicator)); | |
459 s->rx_indicator_handler(s, s->rx_user_data, t30_indicator); | |
460 /* This must come after the indicator handler, so the handler routine sees the existing state of the | |
461 indicator. */ | |
462 s->current_rx_indicator = t30_indicator; | |
463 break; | |
464 case T38_TYPE_OF_MSG_T30_DATA: | |
465 if ((buf[0] & 0x20)) | |
466 { | |
467 /* Extension */ | |
468 if (len < 2) | |
469 { | |
470 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (A)\n", log_seq_no); | |
471 return -1; | |
472 } | |
473 t30_data = T38_DATA_V8 + (((buf[0] << 2) & 0x3C) | ((buf[1] >> 6) & 0x3)); | |
474 if (t30_data > T38_DATA_V33_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 ptr = 2; | |
480 } | |
481 else | |
482 { | |
483 t30_data = (buf[0] >> 1) & 0xF; | |
484 if (t30_data > T38_DATA_V17_14400) | |
485 { | |
486 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown data type - %d\n", log_seq_no, t30_data); | |
487 return -1; | |
488 } | |
489 ptr = 1; | |
490 } | |
491 if (!data_field_present) | |
492 { | |
493 /* This is kinda weird, but I guess if the length checks out we accept it. */ | |
494 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Data type with no data field\n", log_seq_no); | |
495 if (ptr != len) | |
496 { | |
497 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (B)\n", log_seq_no); | |
498 return -1; | |
499 } | |
500 break; | |
501 } | |
502 if (ptr >= len) | |
503 { | |
504 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (C)\n", log_seq_no); | |
505 return -1; | |
506 } | |
507 count = buf[ptr++]; | |
508 //printf("Count is %d\n", count); | |
509 other_half = FALSE; | |
510 t30_field_type = 0; | |
511 for (i = 0; i < (int) count; i++) | |
512 { | |
513 if (ptr >= len) | |
514 { | |
515 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (D)\n", log_seq_no); | |
516 return -1; | |
517 } | |
518 if (s->t38_version == 0) | |
519 { | |
520 /* The original version of T.38 with a typo in the ASN.1 spec. */ | |
521 if (other_half) | |
522 { | |
523 /* The lack of a data field in the previous message means | |
524 we are currently in the middle of an octet. */ | |
525 field_data_present = (buf[ptr] >> 3) & 1; | |
526 /* Decode field_type */ | |
527 t30_field_type = buf[ptr] & 0x7; | |
528 ptr++; | |
529 other_half = FALSE; | |
530 } | |
531 else | |
532 { | |
533 field_data_present = (buf[ptr] >> 7) & 1; | |
534 /* Decode field_type */ | |
535 t30_field_type = (buf[ptr] >> 4) & 0x7; | |
536 if (field_data_present) | |
537 ptr++; | |
538 else | |
539 other_half = TRUE; | |
540 } | |
541 if (t30_field_type > T38_FIELD_T4_NON_ECM_SIG_END) | |
542 { | |
543 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown field type - %d\n", log_seq_no, t30_field_type); | |
544 return -1; | |
545 } | |
546 } | |
547 else | |
548 { | |
549 field_data_present = (buf[ptr] >> 7) & 1; | |
550 /* Decode field_type */ | |
551 if ((buf[ptr] & 0x40)) | |
552 { | |
553 if (ptr > len - 2) | |
554 { | |
555 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (E)\n", log_seq_no); | |
556 return -1; | |
557 } | |
558 t30_field_type = T38_FIELD_CM_MESSAGE + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3)); | |
559 if (t30_field_type > T38_FIELD_V34RATE) | |
560 { | |
561 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Unknown field type - %d\n", log_seq_no, t30_field_type); | |
562 return -1; | |
563 } | |
564 ptr += 2; | |
565 } | |
566 else | |
567 { | |
568 t30_field_type = (buf[ptr++] >> 3) & 0x7; | |
569 } | |
570 } | |
571 /* Decode field_data */ | |
572 if (field_data_present) | |
573 { | |
574 if (ptr > len - 2) | |
575 { | |
576 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (F)\n", log_seq_no); | |
577 return -1; | |
578 } | |
579 numocts = ((buf[ptr] << 8) | buf[ptr + 1]) + 1; | |
580 msg = buf + ptr + 2; | |
581 ptr += numocts + 2; | |
582 } | |
583 else | |
584 { | |
585 numocts = 0; | |
586 msg = NULL; | |
587 } | |
588 if (ptr > len) | |
589 { | |
590 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (G)\n", log_seq_no); | |
591 return -1; | |
592 } | |
593 span_log(&s->logging, | |
594 SPAN_LOG_FLOW, | |
595 "Rx %5d: (%d) data %s/%s + %d byte(s)\n", | |
596 log_seq_no, | |
597 i, | |
598 t38_data_type_to_str(t30_data), | |
599 t38_field_type_to_str(t30_field_type), | |
600 numocts); | |
601 s->rx_data_handler(s, s->rx_user_data, t30_data, t30_field_type, msg, numocts); | |
602 s->current_rx_data_type = t30_data; | |
603 s->current_rx_field_type = t30_field_type; | |
604 } | |
605 if (ptr != len) | |
606 { | |
607 if (s->t38_version != 0 || ptr != (len - 1) || !other_half) | |
608 { | |
609 span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Rx %5d: Invalid length for data (H) - %d %d\n", log_seq_no, ptr, len); | |
610 return -1; | |
611 } | |
612 } | |
613 break; | |
614 } | |
615 return 0; | |
616 } | |
617 /*- End of function --------------------------------------------------------*/ | |
618 | |
619 static int t38_encode_indicator(t38_core_state_t *s, uint8_t buf[], int indicator) | |
620 { | |
621 int len; | |
622 | |
623 /* Build the IFP packet */ | |
624 /* Data field not present */ | |
625 /* Indicator packet */ | |
626 /* Type of indicator */ | |
627 if (indicator <= T38_IND_V17_14400_LONG_TRAINING) | |
628 { | |
629 buf[0] = (uint8_t) (indicator << 1); | |
630 len = 1; | |
631 } | |
632 else if (s->t38_version != 0 && indicator <= T38_IND_V33_14400_TRAINING) | |
633 { | |
634 buf[0] = (uint8_t) (0x20 | (((indicator - T38_IND_V8_ANSAM) & 0xF) >> 2)); | |
635 buf[1] = (uint8_t) (((indicator - T38_IND_V8_ANSAM) << 6) & 0xFF); | |
636 len = 2; | |
637 } | |
638 else | |
639 { | |
640 len = -1; | |
641 } | |
642 return len; | |
643 } | |
644 /*- End of function --------------------------------------------------------*/ | |
645 | |
646 static int t38_encode_data(t38_core_state_t *s, uint8_t buf[], int data_type, const t38_data_field_t field[], int fields) | |
647 { | |
648 int len; | |
649 int i; | |
650 int enclen; | |
651 int multiplier; | |
652 int data_field_no; | |
653 const t38_data_field_t *q; | |
654 unsigned int encoded_len; | |
655 unsigned int fragment_len; | |
656 unsigned int value; | |
657 uint8_t data_field_present; | |
658 uint8_t field_data_present; | |
659 char tag[20]; | |
660 | |
661 /* Build the IFP packet */ | |
662 | |
663 /* There seems no valid reason why a packet would ever be generated without a data field present */ | |
664 data_field_present = TRUE; | |
665 | |
666 for (data_field_no = 0; data_field_no < fields; data_field_no++) | |
667 { | |
668 span_log(&s->logging, | |
669 SPAN_LOG_FLOW, | |
670 "Tx %5d: (%d) data %s/%s + %d byte(s)\n", | |
671 s->tx_seq_no, | |
672 data_field_no, | |
673 t38_data_type_to_str(data_type), | |
674 t38_field_type_to_str(field[data_field_no].field_type), | |
675 field[data_field_no].field_len); | |
676 } | |
677 | |
678 data_field_no = 0; | |
679 len = 0; | |
680 /* Data field present */ | |
681 /* Data packet */ | |
682 /* Type of data */ | |
683 if (data_type <= T38_DATA_V17_14400) | |
684 { | |
685 buf[len++] = (uint8_t) ((data_field_present << 7) | 0x40 | (data_type << 1)); | |
686 } | |
687 else if (s->t38_version != 0 && data_type <= T38_DATA_V33_14400) | |
688 { | |
689 buf[len++] = (uint8_t) ((data_field_present << 7) | 0x60 | (((data_type - T38_DATA_V8) & 0xF) >> 2)); | |
690 buf[len++] = (uint8_t) (((data_type - T38_DATA_V8) << 6) & 0xFF); | |
691 } | |
692 else | |
693 { | |
694 return -1; | |
695 } | |
696 if (data_field_present) | |
697 { | |
698 encoded_len = 0; | |
699 data_field_no = 0; | |
700 do | |
701 { | |
702 value = fields - encoded_len; | |
703 if (value < 0x80) | |
704 { | |
705 /* 1 octet case */ | |
706 buf[len++] = (uint8_t) value; | |
707 enclen = value; | |
708 } | |
709 else if (value < 0x4000) | |
710 { | |
711 /* 2 octet case */ | |
712 buf[len++] = (uint8_t) (0x80 | ((value >> 8) & 0xFF)); | |
713 buf[len++] = (uint8_t) (value & 0xFF); | |
714 enclen = value; | |
715 } | |
716 else | |
717 { | |
718 /* Fragmentation case */ | |
719 multiplier = (value/0x4000 < 4) ? value/0x4000 : 4; | |
720 buf[len++] = (uint8_t) (0xC0 | multiplier); | |
721 enclen = 0x4000*multiplier; | |
722 } | |
723 | |
724 fragment_len = enclen; | |
725 encoded_len += fragment_len; | |
726 /* Encode the elements */ | |
727 for (i = 0; i < (int) encoded_len; i++) | |
728 { | |
729 q = &field[data_field_no]; | |
730 field_data_present = (uint8_t) (q->field_len > 0); | |
731 /* Encode field_type */ | |
732 if (s->t38_version == 0) | |
733 { | |
734 /* Original version of T.38 with a typo */ | |
735 if (q->field_type > T38_FIELD_T4_NON_ECM_SIG_END) | |
736 return -1; | |
737 buf[len++] = (uint8_t) ((field_data_present << 7) | (q->field_type << 4)); | |
738 } | |
739 else | |
740 { | |
741 if (q->field_type <= T38_FIELD_T4_NON_ECM_SIG_END) | |
742 { | |
743 buf[len++] = (uint8_t) ((field_data_present << 7) | (q->field_type << 3)); | |
744 } | |
745 else if (q->field_type <= T38_FIELD_V34RATE) | |
746 { | |
747 buf[len++] = (uint8_t) ((field_data_present << 7) | 0x40 | ((q->field_type - T38_FIELD_CM_MESSAGE) >> 2)); | |
748 buf[len++] = (uint8_t) (((q->field_type - T38_FIELD_CM_MESSAGE) << 6) & 0xC0); | |
749 } | |
750 else | |
751 { | |
752 return -1; | |
753 } | |
754 } | |
755 /* Encode field_data */ | |
756 if (field_data_present) | |
757 { | |
758 if (q->field_len < 1 || q->field_len > 65535) | |
759 return -1; | |
760 buf[len++] = (uint8_t) (((q->field_len - 1) >> 8) & 0xFF); | |
761 buf[len++] = (uint8_t) ((q->field_len - 1) & 0xFF); | |
762 memcpy(buf + len, q->field, q->field_len); | |
763 len += q->field_len; | |
764 } | |
765 data_field_no++; | |
766 } | |
767 } | |
768 while (fields != (int) encoded_len || fragment_len >= 16384); | |
769 } | |
770 | |
771 if (span_log_test(&s->logging, SPAN_LOG_FLOW)) | |
772 { | |
773 sprintf(tag, "Tx %5d: IFP", s->tx_seq_no); | |
774 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len); | |
775 } | |
776 return len; | |
777 } | |
778 /*- End of function --------------------------------------------------------*/ | |
779 | |
780 SPAN_DECLARE(int) t38_core_send_indicator(t38_core_state_t *s, int indicator) | |
781 { | |
782 uint8_t buf[100]; | |
783 int len; | |
784 int delay; | |
785 | |
786 delay = 0; | |
787 /* Only send an indicator if it represents a change of state. */ | |
788 if (s->current_tx_indicator != indicator) | |
789 { | |
790 /* Zero is a valid count, to suppress the transmission of indicators when the | |
791 transport means they are not needed - e.g. TPKT/TCP. */ | |
792 if (s->category_control[T38_PACKET_CATEGORY_INDICATOR]) | |
793 { | |
794 if ((len = t38_encode_indicator(s, buf, indicator)) < 0) | |
795 { | |
796 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 indicator len is %d\n", len); | |
797 return len; | |
798 } | |
799 span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: indicator %s\n", s->tx_seq_no, t38_indicator_to_str(indicator)); | |
800 s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[T38_PACKET_CATEGORY_INDICATOR]); | |
801 s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; | |
802 delay = modem_startup_time[indicator].training; | |
803 if (s->allow_for_tep) | |
804 delay += modem_startup_time[indicator].tep; | |
805 } | |
806 s->current_tx_indicator = indicator; | |
807 } | |
808 return delay; | |
809 } | |
810 /*- End of function --------------------------------------------------------*/ | |
811 | |
812 SPAN_DECLARE(int) t38_core_send_flags_delay(t38_core_state_t *s, int indicator) | |
813 { | |
814 return modem_startup_time[indicator].flags; | |
815 } | |
816 /*- End of function --------------------------------------------------------*/ | |
817 | |
818 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) | |
819 { | |
820 t38_data_field_t field0; | |
821 uint8_t buf[1000]; | |
822 int len; | |
823 | |
824 field0.field_type = field_type; | |
825 field0.field = field; | |
826 field0.field_len = field_len; | |
827 if ((len = t38_encode_data(s, buf, data_type, &field0, 1)) < 0) | |
828 { | |
829 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len); | |
830 return len; | |
831 } | |
832 s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]); | |
833 s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; | |
834 return 0; | |
835 } | |
836 /*- End of function --------------------------------------------------------*/ | |
837 | |
838 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) | |
839 { | |
840 uint8_t buf[1000]; | |
841 int len; | |
842 | |
843 if ((len = t38_encode_data(s, buf, data_type, field, fields)) < 0) | |
844 { | |
845 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len); | |
846 return len; | |
847 } | |
848 s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, s->category_control[category]); | |
849 s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; | |
850 return 0; | |
851 } | |
852 /*- End of function --------------------------------------------------------*/ | |
853 | |
854 SPAN_DECLARE(void) t38_set_data_rate_management_method(t38_core_state_t *s, int method) | |
855 { | |
856 s->data_rate_management_method = method; | |
857 } | |
858 /*- End of function --------------------------------------------------------*/ | |
859 | |
860 SPAN_DECLARE(void) t38_set_data_transport_protocol(t38_core_state_t *s, int data_transport_protocol) | |
861 { | |
862 s->data_transport_protocol = data_transport_protocol; | |
863 } | |
864 /*- End of function --------------------------------------------------------*/ | |
865 | |
866 SPAN_DECLARE(void) t38_set_fill_bit_removal(t38_core_state_t *s, int fill_bit_removal) | |
867 { | |
868 s->fill_bit_removal = fill_bit_removal; | |
869 } | |
870 /*- End of function --------------------------------------------------------*/ | |
871 | |
872 SPAN_DECLARE(void) t38_set_mmr_transcoding(t38_core_state_t *s, int mmr_transcoding) | |
873 { | |
874 s->mmr_transcoding = mmr_transcoding; | |
875 } | |
876 /*- End of function --------------------------------------------------------*/ | |
877 | |
878 SPAN_DECLARE(void) t38_set_jbig_transcoding(t38_core_state_t *s, int jbig_transcoding) | |
879 { | |
880 s->jbig_transcoding = jbig_transcoding; | |
881 } | |
882 /*- End of function --------------------------------------------------------*/ | |
883 | |
884 SPAN_DECLARE(void) t38_set_max_buffer_size(t38_core_state_t *s, int max_buffer_size) | |
885 { | |
886 s->max_buffer_size = max_buffer_size; | |
887 } | |
888 /*- End of function --------------------------------------------------------*/ | |
889 | |
890 SPAN_DECLARE(void) t38_set_max_datagram_size(t38_core_state_t *s, int max_datagram_size) | |
891 { | |
892 s->max_datagram_size = max_datagram_size; | |
893 } | |
894 /*- End of function --------------------------------------------------------*/ | |
895 | |
896 SPAN_DECLARE(void) t38_set_t38_version(t38_core_state_t *s, int t38_version) | |
897 { | |
898 s->t38_version = t38_version; | |
899 } | |
900 /*- End of function --------------------------------------------------------*/ | |
901 | |
902 SPAN_DECLARE(void) t38_set_sequence_number_handling(t38_core_state_t *s, int check) | |
903 { | |
904 s->check_sequence_numbers = check; | |
905 } | |
906 /*- End of function --------------------------------------------------------*/ | |
907 | |
908 SPAN_DECLARE(void) t38_set_tep_handling(t38_core_state_t *s, int allow_for_tep) | |
909 { | |
910 s->allow_for_tep = allow_for_tep; | |
911 } | |
912 /*- End of function --------------------------------------------------------*/ | |
913 | |
914 SPAN_DECLARE(void) t38_set_redundancy_control(t38_core_state_t *s, int category, int setting) | |
915 { | |
916 s->category_control[category] = setting; | |
917 } | |
918 /*- End of function --------------------------------------------------------*/ | |
919 | |
920 SPAN_DECLARE(void) t38_set_fastest_image_data_rate(t38_core_state_t *s, int max_rate) | |
921 { | |
922 s->fastest_image_data_rate = max_rate; | |
923 } | |
924 /*- End of function --------------------------------------------------------*/ | |
925 | |
926 SPAN_DECLARE(int) t38_get_fastest_image_data_rate(t38_core_state_t *s) | |
927 { | |
928 return s->fastest_image_data_rate; | |
929 } | |
930 /*- End of function --------------------------------------------------------*/ | |
931 | |
932 SPAN_DECLARE(logging_state_t *) t38_core_get_logging_state(t38_core_state_t *s) | |
933 { | |
934 return &s->logging; | |
935 } | |
936 /*- End of function --------------------------------------------------------*/ | |
937 | |
938 SPAN_DECLARE(t38_core_state_t *) t38_core_init(t38_core_state_t *s, | |
939 t38_rx_indicator_handler_t *rx_indicator_handler, | |
940 t38_rx_data_handler_t *rx_data_handler, | |
941 t38_rx_missing_handler_t *rx_missing_handler, | |
942 void *rx_user_data, | |
943 t38_tx_packet_handler_t *tx_packet_handler, | |
944 void *tx_packet_user_data) | |
945 { | |
946 if (s == NULL) | |
947 { | |
948 if ((s = (t38_core_state_t *) malloc(sizeof(*s))) == NULL) | |
949 return NULL; | |
950 } | |
951 memset(s, 0, sizeof(*s)); | |
952 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
953 span_log_set_protocol(&s->logging, "T.38"); | |
954 | |
955 /* Set some defaults for the parameters configurable from outside the | |
956 T.38 domain - e.g. from SDP data. */ | |
957 s->data_rate_management_method = T38_DATA_RATE_MANAGEMENT_TRANSFERRED_TCF; | |
958 s->data_transport_protocol = T38_TRANSPORT_UDPTL; | |
959 s->fill_bit_removal = FALSE; | |
960 s->mmr_transcoding = FALSE; | |
961 s->jbig_transcoding = FALSE; | |
962 s->max_buffer_size = 400; | |
963 s->max_datagram_size = 100; | |
964 s->t38_version = 0; | |
965 s->check_sequence_numbers = TRUE; | |
966 | |
967 /* Set some defaults */ | |
968 s->category_control[T38_PACKET_CATEGORY_INDICATOR] = 1; | |
969 s->category_control[T38_PACKET_CATEGORY_CONTROL_DATA] = 1; | |
970 s->category_control[T38_PACKET_CATEGORY_CONTROL_DATA_END] = 1; | |
971 s->category_control[T38_PACKET_CATEGORY_IMAGE_DATA] = 1; | |
972 s->category_control[T38_PACKET_CATEGORY_IMAGE_DATA_END] = 1; | |
973 | |
974 /* Set the initial current receive states to something invalid, so the | |
975 first data received is seen as a change of state. */ | |
976 s->current_rx_indicator = -1; | |
977 s->current_rx_data_type = -1; | |
978 s->current_rx_field_type = -1; | |
979 | |
980 /* Set the initial current indicator state to something invalid, so the | |
981 first attempt to send an indicator will work. */ | |
982 s->current_tx_indicator = -1; | |
983 | |
984 s->rx_indicator_handler = rx_indicator_handler; | |
985 s->rx_data_handler = rx_data_handler; | |
986 s->rx_missing_handler = rx_missing_handler; | |
987 s->rx_user_data = rx_user_data; | |
988 s->tx_packet_handler = tx_packet_handler; | |
989 s->tx_packet_user_data = tx_packet_user_data; | |
990 | |
991 /* We have no initial expectation of the received packet sequence number. | |
992 They most often start at 0 or 1 for a UDPTL transport, but random | |
993 starting numbers are possible. */ | |
994 s->rx_expected_seq_no = -1; | |
995 return s; | |
996 } | |
997 /*- End of function --------------------------------------------------------*/ | |
998 | |
999 SPAN_DECLARE(int) t38_core_release(t38_core_state_t *s) | |
1000 { | |
1001 return 0; | |
1002 } | |
1003 /*- End of function --------------------------------------------------------*/ | |
1004 | |
1005 SPAN_DECLARE(int) t38_core_free(t38_core_state_t *s) | |
1006 { | |
1007 if (s) | |
1008 free(s); | |
1009 return 0; | |
1010 } | |
1011 /*- End of function --------------------------------------------------------*/ | |
1012 /*- End of file ------------------------------------------------------------*/ |