]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Make spandsp's T.38 features tolerate the non-compliant inclusion of data
authorSteve Underwood <steveu@coppice.org>
Fri, 25 Jan 2013 17:54:20 +0000 (01:54 +0800)
committerSteve Underwood <steveu@coppice.org>
Fri, 25 Jan 2013 17:54:20 +0000 (01:54 +0800)
in some T.38 packets from Commetrex and Cisco machines.

libs/spandsp/src/t31.c
libs/spandsp/src/t38_gateway.c
libs/spandsp/src/t38_terminal.c

index 86682107dfbddb2a05644d5795884b48a9d62052..20e7666bd96d62fef48fa8472a4ba55910db40fb 100644 (file)
@@ -396,6 +396,21 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
 }
 /*- End of function --------------------------------------------------------*/
 
+static void process_hdlc_data(t31_t38_front_end_state_t *fe, const uint8_t *buf, int len)
+{
+    if (fe->hdlc_rx.len + len <= T31_T38_MAX_HDLC_LEN)
+    {
+        bit_reverse(fe->hdlc_rx.buf + fe->hdlc_rx.len, buf, len);
+        fe->hdlc_rx.len += len;
+    }
+    else
+    {
+        fe->rx_data_missing = TRUE;
+    }
+    /*endif*/
+}
+/*- End of function --------------------------------------------------------*/
+
 static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len)
 {
     t31_state_t *s;
@@ -451,16 +466,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         /*endif*/
         if (len > 0)
         {
-            if (fe->hdlc_rx.len + len <= T31_T38_MAX_HDLC_LEN)
-            {
-                bit_reverse(fe->hdlc_rx.buf + fe->hdlc_rx.len, buf, len);
-                fe->hdlc_rx.len += len;
-            }
-            else
-            {
-                fe->rx_data_missing = TRUE;
-            }
-            /*endif*/
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
@@ -469,14 +475,15 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK!\n");
-            /* The sender has incorrectly included data in this message. It is unclear what we should do
-               with it, to maximise tolerance of buggy implementations. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             if (data_type == T38_DATA_V21)
@@ -504,9 +511,9 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
                 hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing);
             }
             /*endif*/
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
         fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
         break;
@@ -514,14 +521,15 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD!\n");
-            /* The sender has incorrectly included data in this message. We can safely ignore it, as the
-               bad FCS means we will throw away the whole message, anyway. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             if (data_type == T38_DATA_V21)
@@ -529,9 +537,9 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
             else
                 hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE);
             /*endif*/
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
         fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
         break;
@@ -539,14 +547,15 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK_SIG_END!\n");
-            /* The sender has incorrectly included data in this message. It is unclear what we should do
-               with it, to maximise tolerance of buggy implementations. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK_SIG_END messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK, sig end (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             if (data_type == T38_DATA_V21)
@@ -568,49 +577,60 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
                 /*endif*/
                 crc_itu16_append(fe->hdlc_rx.buf, fe->hdlc_rx.len);
                 hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing);
-                hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN);
             }
             else
             {
                 hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing);
-                non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN);
             }
             /*endif*/
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
+        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        {
+            if (data_type == T38_DATA_V21)
+                hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN);
+            else
+                non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN);
+            /*endif*/
+        }
+        /*endif*/
         fe->timeout_rx_samples = 0;
         break;
     case T38_FIELD_HDLC_FCS_BAD_SIG_END:
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n");
-            /* The sender has incorrectly included data in this message. We can safely ignore it, as the
-               bad FCS means we will throw away the whole message, anyway. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD_SIG_END messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad, sig end (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             if (data_type == T38_DATA_V21)
-            {
                 hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE);
-                hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN);
-            }
             else
-            {
                 hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE);
-                non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN);
-            }
             /*endif*/
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
+        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        {
+            if (data_type == T38_DATA_V21)
+                hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN);
+            else
+                non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN);
+            /*endif*/
+        }
+        /*endif*/
         fe->timeout_rx_samples = 0;
         break;
     case T38_FIELD_HDLC_SIG_END:
index 4fb42a52ee3d9a2fa08c0eedcfa04add52d53d7c..acc8d311568bbbda2ef5e30daa18b0fa01f4b8bd 100644 (file)
@@ -935,9 +935,55 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
 }
 /*- End of function --------------------------------------------------------*/
 
-static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len)
+static void process_hdlc_data(t38_gateway_state_t *s, int data_type, const uint8_t *buf, int len)
 {
+    t38_gateway_hdlc_buf_t *hdlc_buf;
     int i;
+
+    hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
+    /* Check if this data would overflow the buffer. */
+    if (hdlc_buf->len + len > T38_MAX_HDLC_LEN)
+    {
+        s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].flags |= HDLC_FLAG_MISSING_DATA;
+        return;
+    }
+    /*endif*/
+    hdlc_buf->contents = (data_type | FLAG_DATA);
+    bit_reverse(&hdlc_buf->buf[hdlc_buf->len], buf, len);
+    /* We need to send out the control messages as they are arriving. They are
+       too slow to capture a whole frame before starting to pass it on.
+       For the faster frames, take in the whole frame before sending it out. Also, there
+       is no need to monitor, or modify, the contents of the faster frames. */
+    if (data_type == T38_DATA_V21)
+    {
+        for (i = 1;  i <= len;  i++)
+            edit_control_messages(s, 0, hdlc_buf->buf, hdlc_buf->len + i);
+        /*endfor*/
+        /* Don't start pumping data into the actual output stream until there is
+           enough backlog to create some elasticity for jitter tolerance. */
+        if (hdlc_buf->len + len >= HDLC_START_BUFFER_LEVEL)
+        {
+            if (s->core.hdlc_to_modem.in == s->core.hdlc_to_modem.out)
+            {
+                /* Output is not running, so kick it into life. */
+                if ((hdlc_buf->flags & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0)
+                    hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf, hdlc_buf->len + len);
+                else
+                    hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf + hdlc_buf->len, len);
+                /*endif*/
+            }
+            /*endif*/
+            hdlc_buf->flags |= HDLC_FLAG_PROCEED_WITH_OUTPUT;
+        }
+        /*endif*/
+    }
+    /*endif*/
+    hdlc_buf->len += len;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len)
+{
     t38_gateway_state_t *s;
     t38_gateway_t38_state_t *xx;
     t38_gateway_hdlc_buf_t *hdlc_buf;
@@ -1016,47 +1062,9 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
             hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
         }
         /*endif*/
-        /* Check if this data would overflow the buffer. */
-        if (len <= 0)
-            break;
-        /*endif*/
-        if (hdlc_buf->len + len > T38_MAX_HDLC_LEN)
-        {
-            s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].flags |= HDLC_FLAG_MISSING_DATA;
-            break;
-        }
-        /*endif*/
-        hdlc_buf->contents = (data_type | FLAG_DATA);
-        bit_reverse(&hdlc_buf->buf[hdlc_buf->len], buf, len);
-        /* We need to send out the control messages as they are arriving. They are
-           too slow to capture a whole frame before starting to pass it on.
-           For the faster frames, take in the whole frame before sending it out. Also, there
-           is no need to monitor, or modify, the contents of the faster frames. */
-        if (data_type == T38_DATA_V21)
-        {
-            for (i = 1;  i <= len;  i++)
-                edit_control_messages(s, 0, hdlc_buf->buf, hdlc_buf->len + i);
-            /*endfor*/
-            /* Don't start pumping data into the actual output stream until there is
-               enough backlog to create some elasticity for jitter tolerance. */
-            if (hdlc_buf->len + len >= HDLC_START_BUFFER_LEVEL)
-            {
-                if (s->core.hdlc_to_modem.in == s->core.hdlc_to_modem.out)
-                {
-                    /* Output is not running, so kick it into life. */
-                    if ((hdlc_buf->flags & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0)
-                        hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf, hdlc_buf->len + len);
-                    else
-                        hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf + hdlc_buf->len, len);
-                    /*endif*/
-                }
-                /*endif*/
-                hdlc_buf->flags |= HDLC_FLAG_PROCEED_WITH_OUTPUT;
-            }
-            /*endif*/
-        }
+        if (len > 0)
+            process_hdlc_data(s, data_type, buf, len);
         /*endif*/
-        s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].len += len;
         break;
     case T38_FIELD_HDLC_FCS_OK:
         xx->current_rx_field_class = T38_FIELD_CLASS_HDLC;
@@ -1064,14 +1072,15 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK!\n");
-            /* The sender has incorrectly included data in this message. It is unclear what we should do
-               with it, to maximise tolerance of buggy implementations. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(s, data_type, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (hdlc_buf->len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC OK\n", t30_frametype(hdlc_buf->buf[2]));
             if (hdlc_buf->contents != (data_type | FLAG_DATA))
@@ -1112,14 +1121,15 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD!\n");
-            /* The sender has incorrectly included data in this message. We can safely ignore it, as the
-               bad FCS means we will throw away the whole message, anyway. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(s, data_type, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (hdlc_buf->len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad\n", t30_frametype(hdlc_buf->buf[2]));
             /* Only bother with frames that have a bad CRC, if they also have some content. */
@@ -1150,14 +1160,15 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK_SIG_END!\n");
-            /* The sender has incorrectly included data in this message. It is unclear what we should do
-               with it, to maximise tolerance of buggy implementations. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(s, data_type, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK_SIG_END messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (hdlc_buf->len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC OK, sig end\n", t30_frametype(hdlc_buf->buf[2]));
             if (hdlc_buf->contents != (data_type | FLAG_DATA))
@@ -1188,6 +1199,10 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
             /*endif*/
             hdlc_buf->contents = (data_type | FLAG_DATA);
             finalise_hdlc_frame(s, TRUE);
+        }
+        /*endif*/
+        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        {
             queue_missing_indicator(s, T38_DATA_NONE);
             xx->current_rx_field_class = T38_FIELD_CLASS_NONE;
         }
@@ -1200,14 +1215,15 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n");
-            /* The sender has incorrectly included data in this message. We can safely ignore it, as the
-               bad FCS means we will throw away the whole message, anyway. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(s, data_type, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD_SIG_END messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (hdlc_buf->len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad, sig end\n", t30_frametype(hdlc_buf->buf[2]));
             if (hdlc_buf->contents != (data_type | FLAG_DATA))
@@ -1228,6 +1244,10 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
                 hdlc_buf->contents = 0;
             }
             /*endif*/
+        }
+        /*endif*/
+        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        {
             queue_missing_indicator(s, T38_DATA_NONE);
             xx->current_rx_field_class = T38_FIELD_CLASS_NONE;
         }
index 747832cabd4e30d524350a50174a100a5300013b..ca000e1ac79bad52f2789247e9cf46ffa71ba695 100644 (file)
@@ -318,6 +318,20 @@ static int fake_rx_indicator(t38_core_state_t *t, t38_terminal_state_t *s, int i
 }
 /*- End of function --------------------------------------------------------*/
 
+static void process_hdlc_data(t38_terminal_front_end_state_t *fe, const uint8_t *buf, int len)
+{
+    if (fe->hdlc_rx.len + len <= T38_MAX_HDLC_LEN)
+    {
+        bit_reverse(fe->hdlc_rx.buf + fe->hdlc_rx.len, buf, len);
+        fe->hdlc_rx.len += len;
+    }
+    else
+    {
+        fe->rx_data_missing = TRUE;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
 static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len)
 {
     t38_terminal_state_t *s;
@@ -416,16 +430,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         /*endif*/
         if (len > 0)
         {
-            if (fe->hdlc_rx.len + len <= T38_MAX_HDLC_LEN)
-            {
-                bit_reverse(fe->hdlc_rx.buf + fe->hdlc_rx.len, buf, len);
-                fe->hdlc_rx.len += len;
-            }
-            else
-            {
-                fe->rx_data_missing = TRUE;
-            }
-            /*endif*/
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
@@ -434,20 +439,21 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK!\n");
-            /* The sender has incorrectly included data in this message. It is unclear what we should do
-               with it, to maximise tolerance of buggy implementations. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing);
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
         fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
         break;
@@ -455,20 +461,21 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD!\n");
-            /* The sender has incorrectly included data in this message. We can safely ignore it, as the
-               bad FCS means we will throw away the whole message, anyway. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE);
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
         fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
         break;
@@ -476,22 +483,25 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK_SIG_END!\n");
-            /* The sender has incorrectly included data in this message. It is unclear what we should do
-               with it, to maximise tolerance of buggy implementations. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK_SIG_END messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK, sig end (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing);
-            hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
+        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+            hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
+        /*endif*/
         /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */
         fake_rx_indicator(t, s, T38_IND_NO_SIGNAL);
         break;
@@ -499,22 +509,25 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
         if (len > 0)
         {
             span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n");
-            /* The sender has incorrectly included data in this message. We can safely ignore it, as the
-               bad FCS means we will throw away the whole message, anyway. */
+            /* The sender has incorrectly included data in this message. Cisco implemented inserting
+               HDLC data here and Commetrex followed for compatibility reasons. We should, too. */
+            process_hdlc_data(fe, buf, len);
         }
         /*endif*/
         /* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_BAD_SIG_END messages, in IFP packets with
            incrementing sequence numbers, which are actually repeats. They get through to this point because
            of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
-        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+        if (fe->hdlc_rx.len > 0)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad, sig end (%s)\n", (fe->hdlc_rx.len >= 3)  ?  t30_frametype(fe->hdlc_rx.buf[2])  :  "???", (fe->rx_data_missing)  ?  "missing octets"  :  "clean");
             hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE);
-            hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
+            fe->hdlc_rx.len = 0;
         }
         /*endif*/
-        fe->hdlc_rx.len = 0;
         fe->rx_data_missing = FALSE;
+        if (t->current_rx_data_type != data_type  ||  t->current_rx_field_type != field_type)
+            hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
+        /*endif*/
         /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */
         fake_rx_indicator(t, s, T38_IND_NO_SIGNAL);
         break;