freeswitch/libs/spandsp/src/t30_logging.c
Steve Underwood 70c1c03c93 Addition of logging capability to the DTMF detector in spandsp, to aid debugging
poor detection.
Fixes to how timezones are handled for FAX page headers.
Various cleanups of the spandsp headers.
2011-12-06 22:45:24 +08:00

974 lines
32 KiB
C

/*
* SpanDSP - a series of DSP components for telephony
*
* t30_logging.c - ITU T.30 FAX transfer processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#if defined(HAVE_TGMATH_H)
#include <tgmath.h>
#endif
#if defined(HAVE_MATH_H)
#include <math.h>
#endif
#include "floating_fudge.h"
#include <tiffio.h>
#include "spandsp/telephony.h"
#include "spandsp/logging.h"
#include "spandsp/bit_operations.h"
#include "spandsp/queue.h"
#include "spandsp/power_meter.h"
#include "spandsp/complex.h"
#include "spandsp/tone_generate.h"
#include "spandsp/async.h"
#include "spandsp/hdlc.h"
#include "spandsp/fsk.h"
#include "spandsp/v29rx.h"
#include "spandsp/v29tx.h"
#include "spandsp/v27ter_rx.h"
#include "spandsp/v27ter_tx.h"
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
#include "spandsp/t81_t82_arith_coding.h"
#endif
#if defined(SPANDSP_SUPPORT_T85)
#include "spandsp/t85.h"
#endif
#if defined(SPANDSP_SUPPORT_T42)
#include "spandsp/t42.h"
#endif
#if defined(SPANDSP_SUPPORT_T43)
#include "spandsp/t43.h"
#endif
#include "spandsp/t4_t6_decode.h"
#include "spandsp/t4_t6_encode.h"
#include "spandsp/t30_fcf.h"
#include "spandsp/t35.h"
#include "spandsp/t30.h"
#include "spandsp/t30_logging.h"
#include "spandsp/private/logging.h"
#include "spandsp/private/timezone.h"
#if defined(SPANDSP_SUPPORT_T42) || defined(SPANDSP_SUPPORT_T43) || defined(SPANDSP_SUPPORT_T85)
#include "spandsp/private/t81_t82_arith_coding.h"
#endif
#if defined(SPANDSP_SUPPORT_T85)
#include "spandsp/private/t85.h"
#endif
#if defined(SPANDSP_SUPPORT_T42)
#include "spandsp/private/t42.h"
#endif
#if defined(SPANDSP_SUPPORT_T43)
#include "spandsp/private/t43.h"
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "t30_local.h"
/*! Value string pair structure */
typedef struct
{
int val;
const char *str;
} value_string_t;
enum
{
DISBIT1 = 0x01,
DISBIT2 = 0x02,
DISBIT3 = 0x04,
DISBIT4 = 0x08,
DISBIT5 = 0x10,
DISBIT6 = 0x20,
DISBIT7 = 0x40,
DISBIT8 = 0x80
};
SPAN_DECLARE(const char *) t30_completion_code_to_str(int result)
{
switch (result)
{
case T30_ERR_OK:
return "OK";
case T30_ERR_CEDTONE:
return "The CED tone exceeded 5s";
case T30_ERR_T0_EXPIRED:
return "Timed out waiting for initial communication";
case T30_ERR_T1_EXPIRED:
return "Timed out waiting for the first message";
case T30_ERR_T3_EXPIRED:
return "Timed out waiting for procedural interrupt";
case T30_ERR_HDLC_CARRIER:
return "The HDLC carrier did not stop in a timely manner";
case T30_ERR_CANNOT_TRAIN:
return "Failed to train with any of the compatible modems";
case T30_ERR_OPER_INT_FAIL:
return "Operator intervention failed";
case T30_ERR_INCOMPATIBLE:
return "Far end is not compatible";
case T30_ERR_RX_INCAPABLE:
return "Far end is not able to receive";
case T30_ERR_TX_INCAPABLE:
return "Far end is not able to transmit";
case T30_ERR_NORESSUPPORT:
return "Far end cannot receive at the resolution of the image";
case T30_ERR_NOSIZESUPPORT:
return "Far end cannot receive at the size of image";
case T30_ERR_UNEXPECTED:
return "Unexpected message received";
case T30_ERR_TX_BADDCS:
return "Received bad response to DCS or training";
case T30_ERR_TX_BADPG:
return "Received a DCN from remote after sending a page";
case T30_ERR_TX_ECMPHD:
return "Invalid ECM response received from receiver";
case T30_ERR_TX_GOTDCN:
return "Received a DCN while waiting for a DIS";
case T30_ERR_TX_INVALRSP:
return "Invalid response after sending a page";
case T30_ERR_TX_NODIS:
return "Received other than DIS while waiting for DIS";
case T30_ERR_TX_PHBDEAD:
return "Received no response to DCS or TCF";
case T30_ERR_TX_PHDDEAD:
return "No response after sending a page";
case T30_ERR_TX_T5EXP:
return "Timed out waiting for receiver ready (ECM mode)";
case T30_ERR_RX_ECMPHD:
return "Invalid ECM response received from transmitter";
case T30_ERR_RX_GOTDCS:
return "DCS received while waiting for DTC";
case T30_ERR_RX_INVALCMD:
return "Unexpected command after page received";
case T30_ERR_RX_NOCARRIER:
return "Carrier lost during fax receive";
case T30_ERR_RX_NOEOL:
return "Timed out while waiting for EOL (end Of line)";
case T30_ERR_RX_NOFAX:
return "Timed out while waiting for first line";
case T30_ERR_RX_T2EXPDCN:
return "Timer T2 expired while waiting for DCN";
case T30_ERR_RX_T2EXPD:
return "Timer T2 expired while waiting for phase D";
case T30_ERR_RX_T2EXPFAX:
return "Timer T2 expired while waiting for fax page";
case T30_ERR_RX_T2EXPMPS:
return "Timer T2 expired while waiting for next fax page";
case T30_ERR_RX_T2EXPRR:
return "Timer T2 expired while waiting for RR command";
case T30_ERR_RX_T2EXP:
return "Timer T2 expired while waiting for NSS, DCS or MCF";
case T30_ERR_RX_DCNWHY:
return "Unexpected DCN while waiting for DCS or DIS";
case T30_ERR_RX_DCNDATA:
return "Unexpected DCN while waiting for image data";
case T30_ERR_RX_DCNFAX:
return "Unexpected DCN while waiting for EOM, EOP or MPS";
case T30_ERR_RX_DCNPHD:
return "Unexpected DCN after EOM or MPS sequence";
case T30_ERR_RX_DCNRRD:
return "Unexpected DCN after RR/RNR sequence";
case T30_ERR_RX_DCNNORTN:
return "Unexpected DCN after requested retransmission";
case T30_ERR_FILEERROR:
return "TIFF/F file cannot be opened";
case T30_ERR_NOPAGE:
return "TIFF/F page not found";
case T30_ERR_BADTIFF:
return "TIFF/F format is not compatible";
case T30_ERR_BADPAGE:
return "TIFF/F page number tag missing";
case T30_ERR_BADTAG:
return "Incorrect values for TIFF/F tags";
case T30_ERR_BADTIFFHDR:
return "Bad TIFF/F header - incorrect values in fields";
case T30_ERR_NOMEM:
return "Cannot allocate memory for more pages";
case T30_ERR_RETRYDCN:
return "Disconnected after permitted retries";
case T30_ERR_CALLDROPPED:
return "The call dropped prematurely";
case T30_ERR_NOPOLL:
return "Poll not accepted";
case T30_ERR_IDENT_UNACCEPTABLE:
return "Ident not accepted";
case T30_ERR_PSA_UNACCEPTABLE:
return "Polled sub-address not accepted";
case T30_ERR_SEP_UNACCEPTABLE:
return "Selective polling address not accepted";
case T30_ERR_SID_UNACCEPTABLE:
return "Sender identification not accepted";
case T30_ERR_PWD_UNACCEPTABLE:
return "Password not accepted";
case T30_ERR_SUB_UNACCEPTABLE:
return "Sub-address not accepted";
case T30_ERR_TSA_UNACCEPTABLE:
return "Transmitting subscriber internet address not accepted";
case T30_ERR_IRA_UNACCEPTABLE:
return "Internet routing address not accepted";
case T30_ERR_CIA_UNACCEPTABLE:
return "Calling subscriber internet address not accepted";
case T30_ERR_ISP_UNACCEPTABLE:
return "Internet selective polling address not accepted";
case T30_ERR_CSA_UNACCEPTABLE:
return "Called subscriber internet address not accepted";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) t30_frametype(uint8_t x)
{
switch (x)
{
case T30_DIS:
return "DIS";
case T30_CSI:
return "CSI";
case T30_NSF:
return "NSF";
case T30_DTC:
return "DTC";
case T30_CIG:
return "CIG";
case T30_NSC:
return "NSC";
case T30_PWD:
return "PWD";
case T30_SEP:
return "SEP";
case T30_PSA:
return "PSA";
case T30_CIA:
return "CIA";
case T30_ISP:
return "ISP";
case T30_DCS:
case T30_DCS | 0x01:
return "DCS";
case T30_TSI:
case T30_TSI | 0x01:
return "TSI";
case T30_NSS:
case T30_NSS | 0x01:
return "NSS";
case T30_SUB:
case T30_SUB | 0x01:
return "SUB";
case T30_SID:
case T30_SID | 0x01:
return "SID";
case T30_CTC:
case T30_CTC | 0x01:
return "CTC";
case T30_TSA:
case T30_TSA | 0x01:
return "TSA";
case T30_IRA:
case T30_IRA | 0x01:
return "IRA";
case T30_CFR:
case T30_CFR | 0x01:
return "CFR";
case T30_FTT:
case T30_FTT | 0x01:
return "FTT";
case T30_CTR:
case T30_CTR | 0x01:
return "CTR";
case T30_CSA:
case T30_CSA | 0x01:
return "CSA";
case T30_EOM:
case T30_EOM | 0x01:
return "EOM";
case T30_MPS:
case T30_MPS | 0x01:
return "MPS";
case T30_EOP:
case T30_EOP | 0x01:
return "EOP";
case T30_PRI_EOM:
case T30_PRI_EOM | 0x01:
return "PRI-EOM";
case T30_PRI_MPS:
case T30_PRI_MPS | 0x01:
return "PRI-MPS";
case T30_PRI_EOP:
case T30_PRI_EOP | 0x01:
return "PRI-EOP";
case T30_EOS:
case T30_EOS | 0x01:
return "EOS";
case T30_PPS:
case T30_PPS | 0x01:
return "PPS";
case T30_EOR:
case T30_EOR | 0x01:
return "EOR";
case T30_RR:
case T30_RR | 0x01:
return "RR";
case T30_MCF:
case T30_MCF | 0x01:
return "MCF";
case T30_RTP:
case T30_RTP | 0x01:
return "RTP";
case T30_RTN:
case T30_RTN | 0x01:
return "RTN";
case T30_PIP:
case T30_PIP | 0x01:
return "PIP";
case T30_PIN:
case T30_PIN | 0x01:
return "PIN";
case T30_PPR:
case T30_PPR | 0x01:
return "PPR";
case T30_RNR:
case T30_RNR | 0x01:
return "RNR";
case T30_ERR:
case T30_ERR | 0x01:
return "ERR";
case T30_FDM:
case T30_FDM | 0x01:
return "FDM";
case T30_DCN:
case T30_DCN | 0x01:
return "DCN";
case T30_CRP:
case T30_CRP | 0x01:
return "CRP";
case T30_FNV:
case T30_FNV | 0x01:
return "FNV";
case T30_TNR:
case T30_TNR | 0x01:
return "TNR";
case T30_TR:
case T30_TR | 0x01:
return "TR";
case T30_TK:
return "TK";
case T30_RK:
return "RK";
#if 0
case T30_PSS:
return "PSS";
#endif
case T30_DES:
return "DES";
case T30_DEC:
return "DEC";
case T30_DER:
return "DER";
#if 0
case T30_DTR:
return "DTR";
#endif
case T30_DNK:
case T30_DNK | 0x01:
return "DNK";
case T30_PID:
case T30_PID | 0x01:
return "PID";
case T30_NULL:
return "NULL";
case T4_FCD:
return "FCD";
case T4_RCP:
return "RCP";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
static void octet_reserved_bit(logging_state_t *log,
const uint8_t *msg,
int bit_no,
int expected)
{
char s[10] = ".... ....";
int bit;
uint8_t octet;
/* Break out the octet and the bit number within it. */
octet = msg[((bit_no - 1) >> 3) + 3];
bit_no = (bit_no - 1) & 7;
/* Now get the actual bit. */
bit = (octet >> bit_no) & 1;
/* Is it what it should be. */
if (bit ^ expected)
{
/* Only log unexpected values. */
s[7 - bit_no + ((bit_no < 4) ? 1 : 0)] = (uint8_t) (bit + '0');
span_log(log, SPAN_LOG_FLOW, " %s= Unexpected state for reserved bit: %d\n", s, bit);
}
}
/*- End of function --------------------------------------------------------*/
static void octet_bit_field(logging_state_t *log,
const uint8_t *msg,
int bit_no,
const char *desc,
const char *yeah,
const char *neigh)
{
char s[10] = ".... ....";
int bit;
uint8_t octet;
const char *tag;
/* Break out the octet and the bit number within it. */
octet = msg[((bit_no - 1) >> 3) + 3];
bit_no = (bit_no - 1) & 7;
/* Now get the actual bit. */
bit = (octet >> bit_no) & 1;
/* Edit the bit string for display. */
s[7 - bit_no + ((bit_no < 4) ? 1 : 0)] = (uint8_t) (bit + '0');
/* Find the right tag to display. */
if (bit)
{
if ((tag = yeah) == NULL)
tag = "Set";
}
else
{
if ((tag = neigh) == NULL)
tag = "Not set";
}
/* Eh, voila! */
span_log(log, SPAN_LOG_FLOW, " %s= %s: %s\n", s, desc, tag);
}
/*- End of function --------------------------------------------------------*/
static void octet_field(logging_state_t *log,
const uint8_t *msg,
int start,
int end,
const char *desc,
const value_string_t tags[])
{
char s[10] = ".... ....";
int i;
uint8_t octet;
const char *tag;
/* Break out the octet and the bit number range within it. */
octet = msg[((start - 1) >> 3) + 3];
start = (start - 1) & 7;
end = ((end - 1) & 7) + 1;
/* Edit the bit string for display. */
for (i = start; i < end; i++)
s[7 - i + ((i < 4) ? 1 : 0)] = (uint8_t) ((octet >> i) & 1) + '0';
/* Find the right tag to display. */
octet = (uint8_t) ((octet >> start) & ((0xFF + (1 << (end - start))) & 0xFF));
tag = "Invalid";
for (i = 0; tags[i].str; i++)
{
if (octet == tags[i].val)
{
tag = tags[i].str;
break;
}
}
/* Eh, voila! */
span_log(log, SPAN_LOG_FLOW, " %s= %s: %s\n", s, desc, tag);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *pkt, int len)
{
logging_state_t *log;
uint8_t frame_type;
static const value_string_t available_signalling_rate_tags[] =
{
{ 0x00, "V.27 ter fall-back mode" },
{ 0x01, "V.29" },
{ 0x02, "V.27 ter" },
{ 0x03, "V.27 ter and V.29" },
{ 0x0B, "V.27 ter, V.29, and V.17" },
{ 0x06, "Reserved" },
{ 0x0A, "Reserved" },
{ 0x0E, "Reserved" },
{ 0x0F, "Reserved" },
{ 0x04, "Not used" },
{ 0x05, "Not used" },
{ 0x08, "Not used" },
{ 0x09, "Not used" },
{ 0x0C, "Not used" },
{ 0x0D, "Not used" },
{ 0x00, NULL }
};
static const value_string_t selected_signalling_rate_tags[] =
{
{ 0x00, "V.27ter 2400bps" },
{ 0x01, "V.29, 9600bps" },
{ 0x02, "V.27ter 4800bps" },
{ 0x03, "V.29 7200bps" },
{ 0x08, "V.17 14400bps" },
{ 0x09, "V.17 9600bps" },
{ 0x0A, "V.17 12000bps" },
{ 0x0B, "V.17 7200bps" },
{ 0x05, "Reserved" },
{ 0x07, "Reserved" },
{ 0x0C, "Reserved" },
{ 0x0D, "Reserved" },
{ 0x0E, "Reserved" },
{ 0x0F, "Reserved" },
{ 0x00, NULL }
};
static const value_string_t available_scan_line_length_tags[] =
{
{ 0x00, "215mm +- 1%" },
{ 0x01, "215mm +- 1% and 255mm +- 1%" },
{ 0x02, "215mm +- 1%, 255mm +- 1% and 303mm +- 1%" },
{ 0x00, NULL }
};
static const value_string_t selected_scan_line_length_tags[] =
{
{ 0x00, "215mm +- 1%" },
{ 0x01, "255mm +- 1%" },
{ 0x02, "303mm +- 1%" },
{ 0x00, NULL }
};
static const value_string_t available_recording_length_tags[] =
{
{ 0x00, "A4 (297mm)" },
{ 0x01, "A4 (297mm) and B4 (364mm)" },
{ 0x02, "Unlimited" },
{ 0x00, NULL }
};
static const value_string_t selected_recording_length_tags[] =
{
{ 0x00, "A4 (297mm)" },
{ 0x01, "B4 (364mm)" },
{ 0x02, "Unlimited" },
{ 0x00, NULL }
};
static const value_string_t available_minimum_scan_line_time_tags[] =
{
{ 0x00, "20ms at 3.85 l/mm; T7.7 = T3.85" },
{ 0x01, "5ms at 3.85 l/mm; T7.7 = T3.85" },
{ 0x02, "10ms at 3.85 l/mm; T7.7 = T3.85" },
{ 0x03, "20ms at 3.85 l/mm; T7.7 = 1/2 T3.85" },
{ 0x04, "40ms at 3.85 l/mm; T7.7 = T3.85" },
{ 0x05, "40ms at 3.85 l/mm; T7.7 = 1/2 T3.85" },
{ 0x06, "10ms at 3.85 l/mm; T7.7 = 1/2 T3.85" },
{ 0x07, "0ms at 3.85 l/mm; T7.7 = T3.85" },
{ 0x00, NULL }
};
static const value_string_t selected_minimum_scan_line_time_tags[] =
{
{ 0x00, "20ms" },
{ 0x01, "5ms" },
{ 0x02, "10ms" },
{ 0x04, "40ms" },
{ 0x07, "0ms" },
{ 0x00, NULL }
};
static const value_string_t shared_data_memory_capacity_tags[] =
{
{ 0x00, "Not available" },
{ 0x01, "Level 2 = 2.0 Mbytes" },
{ 0x02, "Level 1 = 1.0 Mbytes" },
{ 0x03, "Level 3 = unlimited (i.e. >= 32 Mbytes)" },
{ 0x00, NULL }
};
static const value_string_t t89_profile_tags[] =
{
{ 0x00, "Not used" },
{ 0x01, "Profiles 2 and 3" },
{ 0x02, "Profile 2" },
{ 0x04, "Profile 1" },
{ 0x06, "Profile 3" },
{ 0x03, "Reserved" },
{ 0x05, "Reserved" },
{ 0x07, "Reserved" },
{ 0x00, NULL }
};
static const value_string_t t44_mixed_raster_content_tags[] =
{
{ 0x00, "0" },
{ 0x01, "1" },
{ 0x02, "2" },
{ 0x32, "3" },
{ 0x04, "4" },
{ 0x05, "5" },
{ 0x06, "6" },
{ 0x07, "7" },
{ 0x00, NULL }
};
if (!span_log_test(&s->logging, SPAN_LOG_FLOW))
return;
frame_type = pkt[2] & 0xFE;
log = &s->logging;
if (len <= 2)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
span_log(log, SPAN_LOG_FLOW, "%s:\n", t30_frametype(pkt[2]));
if (len <= 3)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 1, "Store and forward Internet fax (T.37)", NULL, NULL);
octet_reserved_bit(log, pkt, 2, 0);
octet_bit_field(log, pkt, 3, "Real-time Internet fax (T.38)", NULL, NULL);
octet_bit_field(log, pkt, 4, "3G mobile network", NULL, NULL);
octet_reserved_bit(log, pkt, 5, 0);
if (frame_type == T30_DCS)
{
octet_reserved_bit(log, pkt, 6, 0);
octet_reserved_bit(log, pkt, 7, 0);
}
else
{
octet_bit_field(log, pkt, 6, "V.8 capabilities", NULL, NULL);
octet_bit_field(log, pkt, 7, "Preferred octets", "64 octets", "256 octets");
}
octet_reserved_bit(log, pkt, 8, 0);
if (len <= 4)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
if (frame_type == T30_DCS)
{
octet_reserved_bit(log, pkt, 9, 0);
octet_bit_field(log, pkt, 10, "Receive fax", NULL, NULL);
octet_field(log, pkt, 11, 14, "Selected data signalling rate", selected_signalling_rate_tags);
}
else
{
octet_bit_field(log, pkt, 9, "Ready to transmit a fax document (polling)", NULL, NULL);
octet_bit_field(log, pkt, 10, "Can receive fax", NULL, NULL);
octet_field(log, pkt, 11, 14, "Supported data signalling rates", available_signalling_rate_tags);
}
octet_bit_field(log, pkt, 15, "R8x7.7lines/mm and/or 200x200pels/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 16, "2-D coding", NULL, NULL);
if (len <= 5)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
if (frame_type == T30_DCS)
{
octet_field(log, pkt, 17, 18, "Recording width", selected_scan_line_length_tags);
octet_field(log, pkt, 19, 20, "Recording length", selected_recording_length_tags);
octet_field(log, pkt, 21, 23, "Minimum scan line time", selected_minimum_scan_line_time_tags);
}
else
{
octet_field(log, pkt, 17, 18, "Recording width", available_scan_line_length_tags);
octet_field(log, pkt, 19, 20, "Recording length", available_recording_length_tags);
octet_field(log, pkt, 21, 23, "Receiver's minimum scan line time", available_minimum_scan_line_time_tags);
}
octet_bit_field(log, pkt, 24, "Extension indicator", NULL, NULL);
if (!(pkt[5] & DISBIT8))
return;
if (len <= 6)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_reserved_bit(log, pkt, 25, 0);
octet_bit_field(log, pkt, 26, "Compressed/uncompressed mode", "Uncompressed", "Compressed");
octet_bit_field(log, pkt, 27, "Error correction mode (ECM)", "ECM", "Non-ECM");
if (frame_type == T30_DCS)
octet_bit_field(log, pkt, 28, "Frame size", "64 octets", "256 octets");
else
octet_reserved_bit(log, pkt, 28, 0);
octet_reserved_bit(log, pkt, 29, 0);
octet_reserved_bit(log, pkt, 30, 0);
octet_bit_field(log, pkt, 31, "T.6 coding", NULL, NULL);
octet_bit_field(log, pkt, 32, "Extension indicator", NULL, NULL);
if (!(pkt[6] & DISBIT8))
return;
if (len <= 7)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 33, "\"Field not valid\" supported", NULL, NULL);
if (frame_type == T30_DCS)
{
octet_reserved_bit(log, pkt, 34, 0);
octet_reserved_bit(log, pkt, 35, 0);
}
else
{
octet_bit_field(log, pkt, 34, "Multiple selective polling", NULL, NULL);
octet_bit_field(log, pkt, 35, "Polled sub-address", NULL, NULL);
}
octet_bit_field(log, pkt, 36, "T.43 coding", NULL, NULL);
octet_bit_field(log, pkt, 37, "Plane interleave", NULL, NULL);
octet_bit_field(log, pkt, 38, "Voice coding with 32kbit/s ADPCM (Rec. G.726)", NULL, NULL);
octet_bit_field(log, pkt, 39, "Reserved for the use of extended voice coding set", NULL, NULL);
octet_bit_field(log, pkt, 40, "Extension indicator", NULL, NULL);
if (!(pkt[7] & DISBIT8))
return;
if (len <= 8)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 41, "R8x15.4lines/mm", NULL, NULL);
octet_bit_field(log, pkt, 42, "300x300pels/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 43, "R16x15.4lines/mm and/or 400x400pels/25.4mm", NULL, NULL);
if (frame_type == T30_DCS)
{
octet_bit_field(log, pkt, 44, "Resolution type selection", "Inch", "Metric");
octet_reserved_bit(log, pkt, 45, 0);
octet_reserved_bit(log, pkt, 46, 0);
octet_reserved_bit(log, pkt, 47, 0);
}
else
{
octet_bit_field(log, pkt, 44, "Inch-based resolution preferred", NULL, NULL);
octet_bit_field(log, pkt, 45, "Metric-based resolution preferred", NULL, NULL);
octet_bit_field(log, pkt, 46, "Minimum scan line time for higher resolutions", "T15.4 = 1/2 T7.7", "T15.4 = T7.7");
octet_bit_field(log, pkt, 47, "Selective polling", NULL, NULL);
}
octet_bit_field(log, pkt, 48, "Extension indicator", NULL, NULL);
if (!(pkt[8] & DISBIT8))
return;
if (len <= 9)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 49, "Sub-addressing", NULL, NULL);
if (frame_type == T30_DCS)
{
octet_bit_field(log, pkt, 50, "Sender identification transmission", NULL, NULL);
octet_reserved_bit(log, pkt, 51, 0);
}
else
{
octet_bit_field(log, pkt, 50, "Password", NULL, NULL);
octet_bit_field(log, pkt, 51, "Ready to transmit a data file (polling)", NULL, NULL);
}
octet_reserved_bit(log, pkt, 52, 0);
octet_bit_field(log, pkt, 53, "Binary file transfer (BFT)", NULL, NULL);
octet_bit_field(log, pkt, 54, "Document transfer mode (DTM)", NULL, NULL);
octet_bit_field(log, pkt, 55, "Electronic data interchange (EDI)", NULL, NULL);
octet_bit_field(log, pkt, 56, "Extension indicator", NULL, NULL);
if (!(pkt[9] & DISBIT8))
return;
if (len <= 10)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 57, "Basic transfer mode (BTM)", NULL, NULL);
octet_reserved_bit(log, pkt, 58, 0);
if (frame_type == T30_DCS)
octet_reserved_bit(log, pkt, 59, 0);
else
octet_bit_field(log, pkt, 59, "Ready to transfer a character or mixed mode document (polling)", NULL, NULL);
octet_bit_field(log, pkt, 60, "Character mode", NULL, NULL);
octet_reserved_bit(log, pkt, 61, 0);
octet_bit_field(log, pkt, 62, "Mixed mode (Annex E/T.4)", NULL, NULL);
octet_reserved_bit(log, pkt, 63, 0);
octet_bit_field(log, pkt, 64, "Extension indicator", NULL, NULL);
if (!(pkt[10] & DISBIT8))
return;
if (len <= 11)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 65, "Processable mode 26 (Rec. T.505)", NULL, NULL);
octet_bit_field(log, pkt, 66, "Digital network capability", NULL, NULL);
octet_bit_field(log, pkt, 67, "Duplex capability", "Full", "Half only");
if (frame_type == T30_DCS)
octet_bit_field(log, pkt, 68, "Full colour mode", NULL, NULL);
else
octet_bit_field(log, pkt, 68, "JPEG coding", NULL, NULL);
octet_bit_field(log, pkt, 69, "Full colour mode", NULL, NULL);
if (frame_type == T30_DCS)
octet_bit_field(log, pkt, 70, "Preferred Huffman tables", NULL, NULL);
else
octet_reserved_bit(log, pkt, 70, 0);
octet_bit_field(log, pkt, 71, "12bits/pel component", NULL, NULL);
octet_bit_field(log, pkt, 72, "Extension indicator", NULL, NULL);
if (!(pkt[11] & DISBIT8))
return;
if (len <= 12)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 73, "No subsampling (1:1:1)", NULL, NULL);
octet_bit_field(log, pkt, 74, "Custom illuminant", NULL, NULL);
octet_bit_field(log, pkt, 75, "Custom gamut range", NULL, NULL);
octet_bit_field(log, pkt, 76, "North American Letter (215.9mm x 279.4mm)", NULL, NULL);
octet_bit_field(log, pkt, 77, "North American Legal (215.9mm x 355.6mm)", NULL, NULL);
octet_bit_field(log, pkt, 78, "Single-progression sequential coding (Rec. T.85) basic", NULL, NULL);
octet_bit_field(log, pkt, 79, "Single-progression sequential coding (Rec. T.85) optional L0", NULL, NULL);
octet_bit_field(log, pkt, 80, "Extension indicator", NULL, NULL);
if (!(pkt[12] & DISBIT8))
return;
if (len <= 13)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 81, "HKM key management", NULL, NULL);
octet_bit_field(log, pkt, 82, "RSA key management", NULL, NULL);
octet_bit_field(log, pkt, 83, "Override", NULL, NULL);
octet_bit_field(log, pkt, 84, "HFX40 cipher", NULL, NULL);
octet_bit_field(log, pkt, 85, "Alternative cipher number 2", NULL, NULL);
octet_bit_field(log, pkt, 86, "Alternative cipher number 3", NULL, NULL);
octet_bit_field(log, pkt, 87, "HFX40-I hashing", NULL, NULL);
octet_bit_field(log, pkt, 88, "Extension indicator", NULL, NULL);
if (!(pkt[13] & DISBIT8))
return;
if (len <= 14)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 89, "Alternative hashing system 2", NULL, NULL);
octet_bit_field(log, pkt, 90, "Alternative hashing system 3", NULL, NULL);
octet_bit_field(log, pkt, 91, "Reserved for future security features", NULL, NULL);
octet_field(log, pkt, 92, 94, "T.44 (Mixed Raster Content)", t44_mixed_raster_content_tags);
octet_bit_field(log, pkt, 95, "Page length maximum stripe size for T.44 (Mixed Raster Content)", NULL, NULL);
octet_bit_field(log, pkt, 96, "Extension indicator", NULL, NULL);
if (!(pkt[14] & DISBIT8))
return;
if (len <= 15)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 97, "Colour/gray-scale 300pels/25.4mm x 300lines/25.4mm or 400pels/25.4mm x 400lines/25.4mm resolution", NULL, NULL);
octet_bit_field(log, pkt, 98, "100pels/25.4mm x 100lines/25.4mm for colour/gray scale", NULL, NULL);
octet_bit_field(log, pkt, 99, "Simple phase C BFT negotiations", NULL, NULL);
if (frame_type == T30_DCS)
{
octet_reserved_bit(log, pkt, 100, 0);
octet_reserved_bit(log, pkt, 101, 0);
}
else
{
octet_bit_field(log, pkt, 100, "Extended BFT Negotiations capable", NULL, NULL);
octet_bit_field(log, pkt, 101, "Internet Selective Polling address (ISP)", NULL, NULL);
}
octet_bit_field(log, pkt, 102, "Internet Routing Address (IRA)", NULL, NULL);
octet_reserved_bit(log, pkt, 103, 0);
octet_bit_field(log, pkt, 104, "Extension indicator", NULL, NULL);
if (!(pkt[15] & DISBIT8))
return;
if (len <= 16)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 105, "600pels/25.4mm x 600lines/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 106, "1200pels/25.4mm x 1200lines/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 107, "300pels/25.4mm x 600lines/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 108, "400pels/25.4mm x 800lines/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 109, "600pels/25.4mm x 1200lines/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 110, "Colour/gray scale 600pels/25.4mm x 600lines/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 111, "Colour/gray scale 1200pels/25.4mm x 1200lines/25.4mm", NULL, NULL);
octet_bit_field(log, pkt, 112, "Extension indicator", NULL, NULL);
if (!(pkt[16] & DISBIT8))
return;
if (len <= 17)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 113, "Double sided printing capability (alternate mode)", NULL, NULL);
octet_bit_field(log, pkt, 114, "Double sided printing capability (continuous mode)", NULL, NULL);
if (frame_type == T30_DCS)
octet_bit_field(log, pkt, 115, "Black and white mixed raster content profile (MRCbw)", NULL, NULL);
else
octet_reserved_bit(log, pkt, 115, 0);
octet_bit_field(log, pkt, 116, "T.45 (run length colour encoded)", NULL, NULL);
octet_field(log, pkt, 117, 118, "Shared memory", shared_data_memory_capacity_tags);
octet_bit_field(log, pkt, 119, "T.44 colour space", NULL, NULL);
octet_bit_field(log, pkt, 120, "Extension indicator", NULL, NULL);
if (!(pkt[17] & DISBIT8))
return;
if (len <= 18)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");
return;
}
octet_bit_field(log, pkt, 121, "Flow control capability for T.38 communication", NULL, NULL);
octet_bit_field(log, pkt, 122, "K>4", NULL, NULL);
octet_bit_field(log, pkt, 123, "Internet aware T.38 mode fax (not affected by data signal rate bits)", NULL, NULL);
octet_field(log, pkt, 124, 126, "T.89 (Application profiles for ITU-T Rec T.88)", t89_profile_tags);
octet_bit_field(log, pkt, 127, "sYCC-JPEG coding", NULL, NULL);
octet_bit_field(log, pkt, 128, "Extension indicator", NULL, NULL);
if (!(pkt[18] & DISBIT8))
return;
span_log(log, SPAN_LOG_FLOW, " Extended beyond the current T.30 specification!\n");
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/