From d30e82e226e44be113c744863b0ecbbcace17620 Mon Sep 17 00:00:00 2001
From: Steve Underwood <steveu@coppice.org>
Date: Sat, 2 Jul 2011 14:45:27 +0800
Subject: [PATCH] Numerous little changes to spandsp that haven't been pushed
 to Freeswitch for a while. The only big changes are a majorly rewritten V.42
 and V.42bis which are now basically functional.

---
 libs/spandsp/src/async.c                      |    6 +
 libs/spandsp/src/dds_int.c                    |   19 +-
 libs/spandsp/src/fsk.c                        |    4 +-
 libs/spandsp/src/gsm0610_preprocess.c         |    7 +-
 libs/spandsp/src/hdlc.c                       |    2 +-
 libs/spandsp/src/image_translate.c            |    2 +-
 libs/spandsp/src/lpc10_decode.c               |    2 +-
 libs/spandsp/src/plc.c                        |    2 -
 libs/spandsp/src/power_meter.c                |    4 +-
 libs/spandsp/src/silence_gen.c                |    2 +-
 libs/spandsp/src/spandsp/arctan2.h            |   28 +-
 libs/spandsp/src/spandsp/async.h              |   15 +-
 libs/spandsp/src/spandsp/bit_operations.h     |    2 +-
 libs/spandsp/src/spandsp/complex.h            |    6 +
 libs/spandsp/src/spandsp/fsk.h                |    4 +-
 libs/spandsp/src/spandsp/hdlc.h               |    2 +-
 libs/spandsp/src/spandsp/private/fsk.h        |    4 +-
 libs/spandsp/src/spandsp/private/hdlc.h       |    2 +-
 .../spandsp/src/spandsp/private/silence_gen.h |    2 +-
 libs/spandsp/src/spandsp/private/v17rx.h      |    2 +-
 libs/spandsp/src/spandsp/private/v17tx.h      |    2 +-
 libs/spandsp/src/spandsp/private/v22bis.h     |    2 +-
 libs/spandsp/src/spandsp/private/v27ter_rx.h  |    2 +-
 libs/spandsp/src/spandsp/private/v27ter_tx.h  |    2 +-
 libs/spandsp/src/spandsp/private/v29rx.h      |    2 +-
 libs/spandsp/src/spandsp/private/v29tx.h      |    4 +-
 libs/spandsp/src/spandsp/private/v42.h        |  160 +-
 libs/spandsp/src/spandsp/private/v42bis.h     |  152 +-
 libs/spandsp/src/spandsp/silence_gen.h        |    2 +-
 libs/spandsp/src/spandsp/t30.h                |    2 +-
 libs/spandsp/src/spandsp/telephony.h          |   21 +
 libs/spandsp/src/spandsp/v17rx.h              |    2 +-
 libs/spandsp/src/spandsp/v17tx.h              |    2 +-
 libs/spandsp/src/spandsp/v22bis.h             |    2 +-
 libs/spandsp/src/spandsp/v27ter_rx.h          |    2 +-
 libs/spandsp/src/spandsp/v27ter_tx.h          |    2 +-
 libs/spandsp/src/spandsp/v29rx.h              |    2 +-
 libs/spandsp/src/spandsp/v29tx.h              |    2 +-
 libs/spandsp/src/spandsp/v42.h                |  103 +-
 libs/spandsp/src/spandsp/v42bis.h             |   35 +-
 libs/spandsp/src/timezone.c                   |   15 +-
 libs/spandsp/src/v17rx.c                      |    2 +-
 libs/spandsp/src/v17tx.c                      |    2 +-
 libs/spandsp/src/v22bis_tx.c                  |    2 +-
 libs/spandsp/src/v27ter_rx.c                  |    2 +-
 libs/spandsp/src/v27ter_tx.c                  |    2 +-
 libs/spandsp/src/v29rx.c                      |    2 +-
 libs/spandsp/src/v29tx.c                      |    2 +-
 libs/spandsp/src/v42.c                        | 2280 +++++++++--------
 libs/spandsp/src/v42bis.c                     | 1082 ++++----
 libs/spandsp/tests/Makefile.am                |   18 +-
 libs/spandsp/tests/fax_tests.c                |    6 +-
 libs/spandsp/tests/oki_adpcm_tests.c          |    3 +
 libs/spandsp/tests/pcap_parse.c               |   95 +-
 libs/spandsp/tests/regression_tests.sh        |   34 +-
 libs/spandsp/tests/t31_tests.c                |    6 +-
 libs/spandsp/tests/t38_decode.c               |   28 +-
 .../tests/t38_gateway_to_terminal_tests.c     |    2 +-
 libs/spandsp/tests/timezone_tests.c           |  172 +-
 libs/spandsp/tests/tsb85_tests.c              |    4 +-
 libs/spandsp/tests/v17_tests.c                |    1 +
 libs/spandsp/tests/v27ter_tests.c             |    1 +
 libs/spandsp/tests/v29_tests.c                |    1 +
 libs/spandsp/tests/v42_tests.c                |  124 +-
 libs/spandsp/tests/v42bis_tests.c             |  100 +-
 libs/spandsp/tests/v42bis_tests.sh            |   23 +-
 libs/spandsp/unpack_gsm0610_data.sh           |    4 +-
 libs/spandsp/wrapper.xsl                      |    2 +-
 68 files changed, 2517 insertions(+), 2118 deletions(-)

diff --git a/libs/spandsp/src/async.c b/libs/spandsp/src/async.c
index e24d84343b..518642111e 100644
--- a/libs/spandsp/src/async.c
+++ b/libs/spandsp/src/async.c
@@ -69,6 +69,12 @@ SPAN_DECLARE(const char *) signal_status_to_str(int status)
         return "Poor signal quality";
     case SIG_STATUS_MODEM_RETRAIN_OCCURRED:
         return "Modem retrain occurred";
+    case SIG_STATUS_LINK_CONNECTED:
+        return "Link connected";
+    case SIG_STATUS_LINK_DISCONNECTED:
+        return "Link disconnected";
+    case SIG_STATUS_LINK_ERROR:
+        return "Link error";
     }
     return "???";
 }
diff --git a/libs/spandsp/src/dds_int.c b/libs/spandsp/src/dds_int.c
index cf75ecc9c3..73eecb4077 100644
--- a/libs/spandsp/src/dds_int.c
+++ b/libs/spandsp/src/dds_int.c
@@ -56,7 +56,7 @@
 /* This is a simple set of direct digital synthesis (DDS) functions to generate sine
    waves. This version uses a 128 entry sin/cos table to cover one quadrant. */
 
-static const int16_t sine_table[DDS_STEPS] =
+static const int16_t sine_table[DDS_STEPS + 1] =
 {
        201,
        603,
@@ -186,6 +186,7 @@ static const int16_t sine_table[DDS_STEPS] =
      32753,
      32762,
      32767,
+     32767
 };
 
 SPAN_DECLARE(int32_t) dds_phase_rate(float frequency)
@@ -220,7 +221,7 @@ SPAN_DECLARE(int16_t) dds_lookup(uint32_t phase)
     phase >>= DDS_SHIFT;
     step = phase & (DDS_STEPS - 1);
     if ((phase & DDS_STEPS))
-        step = (DDS_STEPS - 1) - step;
+        step = DDS_STEPS - step;
     amp = sine_table[step];
     if ((phase & (2*DDS_STEPS)))
     	amp = -amp;
@@ -254,7 +255,7 @@ SPAN_DECLARE(int16_t) dds_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t s
 {
     int16_t amp;
 
-    amp = (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15);
+    amp = (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15);
     *phase_acc += phase_rate;
     return amp;
 }
@@ -280,8 +281,8 @@ SPAN_DECLARE(complexi_t) dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rat
 {
     complexi_t amp;
 
-    amp = complex_seti(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*(int32_t) scale) >> 15,
-                       ((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15);
+    amp = complex_seti(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15,
+                       ((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15);
     *phase_acc += phase_rate;
     return amp;
 }
@@ -307,8 +308,8 @@ SPAN_DECLARE(complexi16_t) dds_complexi16_mod(uint32_t *phase_acc, int32_t phase
 {
     complexi16_t amp;
 
-    amp = complex_seti16((int16_t) (((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*(int32_t) scale) >> 15),
-                         (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15));
+    amp = complex_seti16((int16_t) (((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15),
+                         (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15));
     *phase_acc += phase_rate;
     return amp;
 }
@@ -334,8 +335,8 @@ SPAN_DECLARE(complexi32_t) dds_complexi32_mod(uint32_t *phase_acc, int32_t phase
 {
     complexi32_t amp;
 
-    amp = complex_seti32(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*(int32_t) scale) >> 15,
-                         ((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15);
+    amp = complex_seti32(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15,
+                         ((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15);
     *phase_acc += phase_rate;
     return amp;
 }
diff --git a/libs/spandsp/src/fsk.c b/libs/spandsp/src/fsk.c
index 088c54bb88..19941637c0 100644
--- a/libs/spandsp/src/fsk.c
+++ b/libs/spandsp/src/fsk.c
@@ -220,7 +220,7 @@ SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit,
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
@@ -248,7 +248,7 @@ SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit,
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/gsm0610_preprocess.c b/libs/spandsp/src/gsm0610_preprocess.c
index ea0edfd64e..d48d164f87 100644
--- a/libs/spandsp/src/gsm0610_preprocess.c
+++ b/libs/spandsp/src/gsm0610_preprocess.c
@@ -91,15 +91,16 @@ void gsm0610_preprocess(gsm0610_state_t *s, const int16_t amp[GSM0610_FRAME_LEN]
         /* 4.2.1   Downscaling of the input signal */
         SO = (amp[k] >> 1) & ~3;
 
-        assert(SO >= -0x4000); // downscaled by
-        assert(SO <=  0x3FFC); // previous routine.
+        /* This is supposed to have been downscaled by previous routine. */
+        assert(SO >= -0x4000);
+        assert(SO <=  0x3FFC);
 
         /* 4.2.2   Offset compensation */
 
         /*  This part implements a high-pass filter and requires extended
             arithmetic precision for the recursive part of this filter.
             The input of this procedure is the array so[0...159] and the
-            output the array sof[ 0...159 ].
+            output the array sof[0...159].
         */
         /* Compute the non-recursive part */
         s1 = SO - z1;
diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c
index a07eb3e9fc..fc401fb5d1 100644
--- a/libs/spandsp/src/hdlc.c
+++ b/libs/spandsp/src/hdlc.c
@@ -332,7 +332,7 @@ SPAN_DECLARE(void) hdlc_rx_set_frame_handler(hdlc_rx_state_t *s, hdlc_frame_hand
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_rx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c
index 9221a9afa7..1b14c2286c 100644
--- a/libs/spandsp/src/image_translate.c
+++ b/libs/spandsp/src/image_translate.c
@@ -146,12 +146,12 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le
     int input_length;
     double c1;
     double c2;
-    double int_part;
     int x;
 #if defined(SPANDSP_USE_FIXED_POINT)
     int frac_row;
     int frac_col;
 #else
+    double int_part;
     double frac_row;
     double frac_col;
 #endif
diff --git a/libs/spandsp/src/lpc10_decode.c b/libs/spandsp/src/lpc10_decode.c
index bfb169edaa..3ccee7c18c 100644
--- a/libs/spandsp/src/lpc10_decode.c
+++ b/libs/spandsp/src/lpc10_decode.c
@@ -86,7 +86,7 @@ static __inline__ int32_t pow_ii(int32_t x, int32_t n)
         if (n == 0  ||  x == 1)
             return 1;
         if (x != -1)
-            return (x == 0)  ?  1/x  :  0;
+            return (x != 0)  ?  1/x  :  0;
         n = -n;
     }
     u = n;
diff --git a/libs/spandsp/src/plc.c b/libs/spandsp/src/plc.c
index 392a7b01a6..3d07417f68 100644
--- a/libs/spandsp/src/plc.c
+++ b/libs/spandsp/src/plc.c
@@ -165,10 +165,8 @@ SPAN_DECLARE(int) plc_fillin(plc_state_t *s, int16_t amp[], int len)
     float old_weight;
     float new_weight;
     float gain;
-    //int16_t *orig_amp;
     int orig_len;
 
-    //orig_amp = amp;
     orig_len = len;
     if (s->missing_samples == 0)
     {
diff --git a/libs/spandsp/src/power_meter.c b/libs/spandsp/src/power_meter.c
index fc752c3846..f4fb2afa8f 100644
--- a/libs/spandsp/src/power_meter.c
+++ b/libs/spandsp/src/power_meter.c
@@ -122,7 +122,7 @@ SPAN_DECLARE(float) power_meter_current_dbm0(power_meter_t *s)
     if (s->reading <= 0)
         return -96.329f + DBM0_MAX_POWER;
     /* This is based on A-law, but u-law is only 0.03dB different, so don't worry. */
-    return log10f((float) s->reading/(32767.0f*32767.0f))*10.0f + DBM0_MAX_POWER;
+    return 10.0f*log10f((float) s->reading/(32767.0f*32767.0f) + 1.0e-10f) + DBM0_MAX_POWER;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -130,7 +130,7 @@ SPAN_DECLARE(float) power_meter_current_dbov(power_meter_t *s)
 {
     if (s->reading <= 0)
         return -96.329f;
-    return log10f((float) s->reading/(32767.0f*32767.0f))*10.0f;
+    return 10.0f*log10f((float) s->reading/(32767.0f*32767.0f) + 1.0e-10f);
 }
 /*- End of function --------------------------------------------------------*/
 
diff --git a/libs/spandsp/src/silence_gen.c b/libs/spandsp/src/silence_gen.c
index 96559d5d14..ad7d7caed0 100644
--- a/libs/spandsp/src/silence_gen.c
+++ b/libs/spandsp/src/silence_gen.c
@@ -108,7 +108,7 @@ SPAN_DECLARE(int) silence_gen_generated(silence_gen_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/spandsp/arctan2.h b/libs/spandsp/src/spandsp/arctan2.h
index 628a559987..321476715a 100644
--- a/libs/spandsp/src/spandsp/arctan2.h
+++ b/libs/spandsp/src/spandsp/arctan2.h
@@ -49,8 +49,18 @@ static __inline__ int32_t arctan2(float y, float x)
     float abs_y;
     float angle;
 
-    if (x == 0.0f  ||  y == 0.0f)
-        return 0;
+    if (y == 0.0f)
+    {
+        if (x < 0.0f)
+            return 0x80000000;
+        return 0x00000000;
+    }
+    if (x == 0.0f)
+    {
+        if (y < 0.0f)
+            return 0xc0000000;
+        return 0x40000000;
+    }
     
     abs_y = fabsf(y);
 
@@ -77,8 +87,18 @@ static __inline__ float arctan2f(float y, float x)
     float fx;
     float fy;
 
-    if (x == 0.0f  ||  y == 0.0f)
-        return 0;
+    if (y == 0.0f)
+    {
+        if (x < 0.0f)
+            return 3.1415926f;
+        return 0.0f;
+    }
+    if (x == 0.0f)
+    {
+        if (y < 0.0f)
+            return 3.1415926f*1.5f;
+        return 3.1415926f*0.5f;
+    }
     fx = fabsf(x);
     fy = fabsf(y);
     /* Deal with the octants */
diff --git a/libs/spandsp/src/spandsp/async.h b/libs/spandsp/src/spandsp/async.h
index 9c6c66cf8a..e0124e55c2 100644
--- a/libs/spandsp/src/spandsp/async.h
+++ b/libs/spandsp/src/spandsp/async.h
@@ -80,7 +80,13 @@ enum
     /*! \brief Notification that a modem has detected signal quality degradation. */
     SIG_STATUS_POOR_SIGNAL_QUALITY = -12,
     /*! \brief Notification that a modem retrain has occurred. */
-    SIG_STATUS_MODEM_RETRAIN_OCCURRED = -13
+    SIG_STATUS_MODEM_RETRAIN_OCCURRED = -13,
+    /*! \brief The link protocol (e.g. V.42) has connected. */
+    SIG_STATUS_LINK_CONNECTED = -14,
+    /*! \brief The link protocol (e.g. V.42) has disconnected. */
+    SIG_STATUS_LINK_DISCONNECTED = -15,
+    /*! \brief An error has occurred in the link protocol (e.g. V.42). */
+    SIG_STATUS_LINK_ERROR = -16
 };
 
 /*! Message put function for data pumps */
@@ -101,11 +107,8 @@ typedef void (*put_bit_func_t)(void *user_data, int bit);
 /*! Bit get function for data pumps */
 typedef int (*get_bit_func_t)(void *user_data);
 
-/*! Completion callback function for tx data pumps */
-typedef void (*modem_tx_status_func_t)(void *user_data, int status);
-
-/*! Completion callback function for rx data pumps */
-typedef void (*modem_rx_status_func_t)(void *user_data, int status);
+/*! Status change callback function for data pumps */
+typedef void (*modem_status_func_t)(void *user_data, int status);
 
 enum
 {
diff --git a/libs/spandsp/src/spandsp/bit_operations.h b/libs/spandsp/src/spandsp/bit_operations.h
index df308d9ec2..8ce3c44430 100644
--- a/libs/spandsp/src/spandsp/bit_operations.h
+++ b/libs/spandsp/src/spandsp/bit_operations.h
@@ -225,7 +225,7 @@ SPAN_DECLARE(uint32_t) bit_reverse_4bytes(uint32_t data);
 SPAN_DECLARE(uint64_t) bit_reverse_8bytes(uint64_t data);
 #endif
 
-/*! \brief Bit reverse each bytes in a buffer.
+/*! \brief Bit reverse each byte in a buffer.
     \param to The buffer to place the reversed data in.
     \param from The buffer containing the data to be reversed.
     \param len The length of the data in the buffer. */
diff --git a/libs/spandsp/src/spandsp/complex.h b/libs/spandsp/src/spandsp/complex.h
index 3bc8c5407d..af98c078d1 100644
--- a/libs/spandsp/src/spandsp/complex.h
+++ b/libs/spandsp/src/spandsp/complex.h
@@ -477,6 +477,12 @@ static __inline__ complexi32_t complex_conji32(const complexi32_t *x)
 }
 /*- End of function --------------------------------------------------------*/
 
+static __inline__ int32_t poweri16(const complexi16_t *x)
+{
+    return (int32_t) x->re*x->re + (int32_t) x->im*x->im;
+}
+/*- End of function --------------------------------------------------------*/
+
 static __inline__ float powerf(const complexf_t *x)
 {
     return x->re*x->re + x->im*x->im;
diff --git a/libs/spandsp/src/spandsp/fsk.h b/libs/spandsp/src/spandsp/fsk.h
index df6829514e..03082ce3d0 100644
--- a/libs/spandsp/src/spandsp/fsk.h
+++ b/libs/spandsp/src/spandsp/fsk.h
@@ -175,7 +175,7 @@ SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit,
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_tx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Generate a block of FSK modem audio samples.
     \brief Generate a block of FSK modem audio samples.
@@ -243,7 +243,7 @@ SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit,
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_rx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_status_func_t handler, void *user_data);
 
 #if defined(__cplusplus)
 }
diff --git a/libs/spandsp/src/spandsp/hdlc.h b/libs/spandsp/src/spandsp/hdlc.h
index a6259a4544..ce37a701fc 100644
--- a/libs/spandsp/src/spandsp/hdlc.h
+++ b/libs/spandsp/src/spandsp/hdlc.h
@@ -113,7 +113,7 @@ SPAN_DECLARE(void) hdlc_rx_set_frame_handler(hdlc_rx_state_t *s, hdlc_frame_hand
     \param handler The callback routine used to report status changes.
     \param user_data An opaque parameter for the callback routine.
 */
-SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_rx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Release an HDLC receiver context.
     \brief Release an HDLC receiver context.
diff --git a/libs/spandsp/src/spandsp/private/fsk.h b/libs/spandsp/src/spandsp/private/fsk.h
index b08a9294fd..c1c1720157 100644
--- a/libs/spandsp/src/spandsp/private/fsk.h
+++ b/libs/spandsp/src/spandsp/private/fsk.h
@@ -39,7 +39,7 @@ struct fsk_tx_state_s
     void *get_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_tx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
@@ -66,7 +66,7 @@ struct fsk_rx_state_s
     void *put_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_tx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/hdlc.h b/libs/spandsp/src/spandsp/private/hdlc.h
index e58ef8720c..b5a677887d 100644
--- a/libs/spandsp/src/spandsp/private/hdlc.h
+++ b/libs/spandsp/src/spandsp/private/hdlc.h
@@ -40,7 +40,7 @@ struct hdlc_rx_state_s
     /*! \brief An opaque parameter passed to the frame callback routine. */
     void *frame_user_data;
     /*! \brief The callback routine called to report status changes. */
-    modem_rx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief An opaque parameter passed to the status callback routine. */
     void *status_user_data;
     /*! \brief TRUE if bad frames are to be reported. */
diff --git a/libs/spandsp/src/spandsp/private/silence_gen.h b/libs/spandsp/src/spandsp/private/silence_gen.h
index 6068c41171..695e472c3c 100644
--- a/libs/spandsp/src/spandsp/private/silence_gen.h
+++ b/libs/spandsp/src/spandsp/private/silence_gen.h
@@ -29,7 +29,7 @@
 struct silence_gen_state_s
 {
     /*! \brief The callback function used to report status changes. */
-    modem_tx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/v17rx.h b/libs/spandsp/src/spandsp/private/v17rx.h
index 03b320c11b..da97bf05c7 100644
--- a/libs/spandsp/src/spandsp/private/v17rx.h
+++ b/libs/spandsp/src/spandsp/private/v17rx.h
@@ -61,7 +61,7 @@ struct v17_rx_state_s
     void *put_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_rx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/v17tx.h b/libs/spandsp/src/spandsp/private/v17tx.h
index 4d4582f69d..07d29f6dd9 100644
--- a/libs/spandsp/src/spandsp/private/v17tx.h
+++ b/libs/spandsp/src/spandsp/private/v17tx.h
@@ -45,7 +45,7 @@ struct v17_tx_state_s
     void *get_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_tx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/v22bis.h b/libs/spandsp/src/spandsp/private/v22bis.h
index 92317f6d72..d81bd039c5 100644
--- a/libs/spandsp/src/spandsp/private/v22bis.h
+++ b/libs/spandsp/src/spandsp/private/v22bis.h
@@ -84,7 +84,7 @@ struct v22bis_state_s
     /*! \brief A user specified opaque pointer passed to the put_bit callback routine. */
     void *put_bit_user_data;
     /*! \brief The callback function used to report modem status changes. */
-    modem_rx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/v27ter_rx.h b/libs/spandsp/src/spandsp/private/v27ter_rx.h
index bc26c2d106..8ae99b4f81 100644
--- a/libs/spandsp/src/spandsp/private/v27ter_rx.h
+++ b/libs/spandsp/src/spandsp/private/v27ter_rx.h
@@ -58,7 +58,7 @@ struct v27ter_rx_state_s
     void *put_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_rx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/v27ter_tx.h b/libs/spandsp/src/spandsp/private/v27ter_tx.h
index 12d77510d4..f9781aeb0f 100644
--- a/libs/spandsp/src/spandsp/private/v27ter_tx.h
+++ b/libs/spandsp/src/spandsp/private/v27ter_tx.h
@@ -43,7 +43,7 @@ struct v27ter_tx_state_s
     void *get_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_tx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/v29rx.h b/libs/spandsp/src/spandsp/private/v29rx.h
index 3f6433bad9..ee7cd9932c 100644
--- a/libs/spandsp/src/spandsp/private/v29rx.h
+++ b/libs/spandsp/src/spandsp/private/v29rx.h
@@ -50,7 +50,7 @@ struct v29_rx_state_s
     void *put_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_rx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
diff --git a/libs/spandsp/src/spandsp/private/v29tx.h b/libs/spandsp/src/spandsp/private/v29tx.h
index bb95dba527..062ef7ee5c 100644
--- a/libs/spandsp/src/spandsp/private/v29tx.h
+++ b/libs/spandsp/src/spandsp/private/v29tx.h
@@ -43,7 +43,7 @@ struct v29_tx_state_s
     void *get_bit_user_data;
 
     /*! \brief The callback function used to report modem status changes. */
-    modem_tx_status_func_t status_handler;
+    modem_status_func_t status_handler;
     /*! \brief A user specified opaque pointer passed to the status function. */
     void *status_user_data;
 
@@ -68,7 +68,7 @@ struct v29_tx_state_s
     int rrc_filter_step;
 
     /*! \brief The register for the data scrambler. */
-    unsigned int scramble_reg;
+    uint32_t scramble_reg;
     /*! \brief The register for the training scrambler. */
     uint8_t training_scramble_reg;
     /*! \brief TRUE if transmitting the training sequence, or shutting down transmission.
diff --git a/libs/spandsp/src/spandsp/private/v42.h b/libs/spandsp/src/spandsp/private/v42.h
index 0689c1d01a..b45b716349 100644
--- a/libs/spandsp/src/spandsp/private/v42.h
+++ b/libs/spandsp/src/spandsp/private/v42.h
@@ -5,7 +5,7 @@
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
- * Copyright (C) 2003 Steve Underwood
+ * Copyright (C) 2003, 2011 Steve Underwood
  *
  * All rights reserved.
  *
@@ -26,75 +26,94 @@
 #if !defined(_SPANDSP_PRIVATE_V42_H_)
 #define _SPANDSP_PRIVATE_V42_H_
 
+/*! Max retries (9.2.2) */
+#define V42_DEFAULT_N_400               5
+/*! Default for max octets in an information field (9.2.3) */
+#define V42_DEFAULT_N_401               128
+/*! Maximum supported value for max octets in an information field */
+#define V42_MAX_N_401                   128
+/*! Default window size (k) (9.2.4) */
+#define V42_DEFAULT_WINDOW_SIZE_K       15
+/*! Maximum supported window size (k) */
+#define V42_MAX_WINDOW_SIZE_K           15
+
+/*! The number of info frames to allocate */
+#define V42_INFO_FRAMES                 (V42_MAX_WINDOW_SIZE_K + 1)
+/*! The number of control frames to allocate */
+#define V42_CTRL_FRAMES                 8
+
+typedef struct
+{
+    /* V.42 LAP.M parameters */
+    uint8_t v42_tx_window_size_k;
+    uint8_t v42_rx_window_size_k;
+    uint16_t v42_tx_n401;
+    uint16_t v42_rx_n401;
+
+    /* V.42bis compressor parameters */
+    uint8_t comp;
+    int comp_dict_size;
+    int comp_max_string;
+} v42_config_parameters_t;
+
+typedef struct frame_s
+{
+    int len;
+    uint8_t buf[4 + V42_MAX_N_401];
+} v42_frame_t;
+
 /*!
     LAP-M descriptor. This defines the working state for a single instance of LAP-M.
 */
-struct lapm_state_s
+typedef struct
 {
-    int handle;
+    get_msg_func_t iframe_get;
+    void *iframe_get_user_data;
+
+    put_msg_func_t iframe_put;
+    void *iframe_put_user_data;
+
+    modem_status_func_t status_handler;
+    void *status_user_data;
+
     hdlc_rx_state_t hdlc_rx;
     hdlc_tx_state_t hdlc_tx;
-    
-    v42_frame_handler_t iframe_receive;
-    void *iframe_receive_user_data;
 
-    v42_status_func_t status_callback;
-    void *status_callback_user_data;
+    /*! Negotiated values for the window and maximum info sizes */
+    uint8_t tx_window_size_k;
+    uint8_t rx_window_size_k;
+    uint16_t tx_n401;
+    uint16_t rx_n401;
 
+    uint8_t cmd_addr;
+    uint8_t rsp_addr;
+    uint8_t vs;
+    uint8_t va;
+    uint8_t vr;
     int state;
-    int tx_waiting;
-    int debug;
-    /*! TRUE if originator. FALSE if answerer */
-    int we_are_originator;
-    /*! Remote network type (unknown, answerer. originator) */
-    int peer_is_originator;
-    /*! Next N(S) for transmission */
-    int next_tx_frame;
-    /*! The last of our frames which the peer acknowledged */
-    int last_frame_peer_acknowledged;
-    /*! Next N(R) for reception */
-    int next_expected_frame;
-    /*! The last of the peer's frames which we acknowledged */
-    int last_frame_we_acknowledged;
-    /*! TRUE if we sent an I or S frame with the F-bit set */
-    int solicit_f_bit;
-    /*! Retransmission count */
-    int retransmissions;
-    /*! TRUE if peer is busy */
-    int busy;
+    int configuring;
+    int local_busy;
+    int far_busy;
+    int rejected;
+    int retry_count;
 
-    /*! Acknowledgement timer */
-    int t401_timer;
-    /*! Reply delay timer - optional */
-    int t402_timer;
-    /*! Inactivity timer - optional */
-    int t403_timer;
-    /*! Maximum number of octets in an information field */
-    int n401;
-    /*! Window size */
-    int window_size_k;
-	
-    lapm_frame_queue_t *txqueue;
-    lapm_frame_queue_t *tx_next;
-    lapm_frame_queue_t *tx_last;
-    queue_state_t *tx_queue;
-    
-    span_sched_state_t sched;
-    /*! \brief Error and flow logging control */
-    logging_state_t logging;
-};
+    /* The control frame buffer, and its pointers */
+    int ctrl_put;
+    int ctrl_get;
+    v42_frame_t ctrl_buf[V42_CTRL_FRAMES];
 
-/*!
-    V.42 descriptor. This defines the working state for a single instance of V.42.
-*/
-struct v42_state_s
+    /* The info frame buffer, and its pointers */
+    int info_put;
+    int info_get;
+    int info_acked;
+    v42_frame_t info_buf[V42_INFO_FRAMES];
+
+    void (*packer_process)(v42_state_t *m, int bits);
+} lapm_state_t;
+
+/*! V.42 support negotiation parameters */
+typedef struct
 {
-    /*! TRUE if we are the calling party, otherwise FALSE */
-    int calling_party;
-    /*! TRUE if we should detect whether the far end is V.42 capable. FALSE if we go
-        directly to protocol establishment */
-    int detect;
-
     /*! Stage in negotiating V.42 support */
     int rx_negotiation_step;
     int rxbits;
@@ -104,11 +123,30 @@ struct v42_state_s
     int txbits;
     int txstream;
     int txadps;
-    /*! The LAP.M context */
+} v42_negotiation_t;
+
+/*!
+    V.42 descriptor. This defines the working state for a single
+    instance of a V.42 error corrector.
+*/
+struct v42_state_s
+{
+    /*! TRUE if we are the calling party, otherwise FALSE. */
+    int calling_party;
+    /*! TRUE if we should detect whether the far end is V.42 capable. FALSE if we go
+        directly to protocol establishment. */
+    int detect;
+
+    /*! The bit rate, used to time events */
+    int tx_bit_rate;
+
+    v42_config_parameters_t config;
+    v42_negotiation_t neg;
     lapm_state_t lapm;
 
-    /*! V.42 support detection timer */
-    int t400_timer;
+    int bit_timer;
+    void (*bit_timer_func)(v42_state_t *m);
+
     /*! \brief Error and flow logging control */
     logging_state_t logging;
 };
diff --git a/libs/spandsp/src/spandsp/private/v42bis.h b/libs/spandsp/src/spandsp/private/v42bis.h
index 287c26bd2c..2c801ebe24 100644
--- a/libs/spandsp/src/spandsp/private/v42bis.h
+++ b/libs/spandsp/src/spandsp/private/v42bis.h
@@ -28,100 +28,85 @@
 
 /*!
     V.42bis dictionary node.
+    Note that 0 is not a valid node to point to (0 is always a control code), so 0 is used
+    as a "no such value" marker in this structure.
 */
 typedef struct
 {
-    /*! \brief The prior code for each defined code. */
-    uint16_t parent_code;
-    /*! \brief The number of leaf nodes this node has */
-    int16_t leaves;
-    /*! \brief This leaf octet for each defined code. */
+    /*! \brief The value of the octet represented by the current dictionary node */
     uint8_t node_octet;
-    /*! \brief Bit map of the children which exist */
-    uint32_t children[8];
+    /*! \brief The parent of this node */
+    uint16_t parent;
+    /*! \brief The first child of this node */
+    uint16_t child;
+    /*! \brief The next node at the same depth */
+    uint16_t next;
 } v42bis_dict_node_t;
 
 /*!
-    V.42bis compression. This defines the working state for a single instance
-    of V.42bis compression.
+    V.42bis compression or decompression. This defines the working state for a single instance
+    of V.42bis compression or decompression.
 */
 typedef struct
 {
+    /*! \brief Compression enabled. */
+    int v42bis_parm_p0;
     /*! \brief Compression mode. */
     int compression_mode;
-    /*! \brief Callback function to handle received frames. */
-    v42bis_frame_handler_t handler;
-    /*! \brief An opaque pointer passed in calls to frame_handler. */
+    /*! \brief Callback function to handle output data. */
+    put_msg_func_t handler;
+    /*! \brief An opaque pointer passed in calls to the data handler. */
     void *user_data;
-    /*! \brief The maximum frame length allowed */
-    int max_len;
+    /*! \brief The maximum amount to be passed to the data handler. */
+    int max_output_len;
 
-    uint32_t string_code;
-    uint32_t latest_code;
+    /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
+    int transparent;
+    /*! \brief Next empty dictionary entry */
+    uint16_t v42bis_parm_c1;
+    /*! \brief Current codeword size */
+    uint16_t v42bis_parm_c2;
+    /*! \brief Threshold for codeword size change */
+    uint16_t v42bis_parm_c3;
+    /*! \brief The current update point in the dictionary */
+    uint16_t update_at;
+    /*! \brief The last entry matched in the dictionary */
+    uint16_t last_matched;
+    /*! \brief The last entry added to the dictionary */
+    uint16_t last_added;
+    /*! \brief Total number of codewords in the dictionary */
+    int v42bis_parm_n2;
+    /*! \brief Maximum permitted string length */
+    int v42bis_parm_n7;
+    /*! \brief The dictionary */
+    v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
+
+    /*! \brief The octet string in progress */
+    uint8_t string[V42BIS_MAX_STRING_SIZE];
+    /*! \brief The current length of the octet string in progress */
     int string_length;
-    uint32_t output_bit_buffer;
-    int output_bit_count;
+    /*! \brief The amount of the octet string in progress which has already
+        been flushed out of the buffer */
+    int flushed_length;
+
+    /*! \brief Compression performance metric */
+    uint16_t compression_performance;
+
+    /*! \brief Outgoing bit buffer (compression), or incoming bit buffer (decompression) */ 
+    uint32_t bit_buffer;
+    /*! \brief Outgoing bit count (compression), or incoming bit count (decompression) */ 
+    int bit_count;
+
+    /*! \brief The output composition buffer */
+    uint8_t output_buf[V42BIS_MAX_OUTPUT_LENGTH];
+    /*! \brief The length of the contents of the output composition buffer */    
     int output_octet_count;
-    uint8_t output_buf[1024];
-    v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
-    /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
-    int transparent;
-    int change_transparency;
-    /*! \brief IIR filter state, used in assessing compressibility. */
-    int compressibility_filter;
-    int compressibility_persistence;
-    
-    /*! \brief Next empty dictionary entry */
-    uint32_t v42bis_parm_c1;
-    /*! \brief Current codeword size */
-    int v42bis_parm_c2;
-    /*! \brief Threshold for codeword size change */
-    uint32_t v42bis_parm_c3;
 
-    /*! \brief Mark that this is the first octet/code to be processed */
-    int first;
-    uint8_t escape_code;
-} v42bis_compress_state_t;
-
-/*!
-    V.42bis decompression. This defines the working state for a single instance
-    of V.42bis decompression.
-*/
-typedef struct
-{
-    /*! \brief Callback function to handle decompressed data. */
-    v42bis_data_handler_t handler;
-    /*! \brief An opaque pointer passed in calls to data_handler. */
-    void *user_data;
-    /*! \brief The maximum decompressed data block length allowed */
-    int max_len;
-
-    uint32_t old_code;
-    uint32_t last_old_code;
-    uint32_t input_bit_buffer;
-    int input_bit_count;
-    int octet;
-    int last_length;
-    int output_octet_count;
-    uint8_t output_buf[1024];
-    v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
-    /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
-    int transparent;
-
-    int last_extra_octet;
-
-    /*! \brief Next empty dictionary entry */
-    uint32_t v42bis_parm_c1;
-    /*! \brief Current codeword size */
-    int v42bis_parm_c2;
-    /*! \brief Threshold for codeword size change */
-    uint32_t v42bis_parm_c3;
-        
-    /*! \brief Mark that this is the first octet/code to be processed */
-    int first;
+    /*! \brief The current value of the escape code */
     uint8_t escape_code;
+    /*! \brief TRUE if we just hit an escape code, and are waiting for the following octet */
     int escaped;
-} v42bis_decompress_state_t;
+} v42bis_comp_state_t;
 
 /*!
     V.42bis compression/decompression descriptor. This defines the working state for a
@@ -129,20 +114,13 @@ typedef struct
 */
 struct v42bis_state_s
 {
-    /*! \brief V.42bis data compression directions. */
-    int v42bis_parm_p0;
-
     /*! \brief Compression state. */
-    v42bis_compress_state_t compress;
+    v42bis_comp_state_t compress;
     /*! \brief Decompression state. */
-    v42bis_decompress_state_t decompress;
-    
-    /*! \brief Maximum codeword size (bits) */
-    int v42bis_parm_n1;
-    /*! \brief Total number of codewords */
-    uint32_t v42bis_parm_n2;
-    /*! \brief Maximum string length */
-    int v42bis_parm_n7;
+    v42bis_comp_state_t decompress;
+
+    /*! \brief Error and flow logging control */
+    logging_state_t logging;
 };
 
 #endif
diff --git a/libs/spandsp/src/spandsp/silence_gen.h b/libs/spandsp/src/spandsp/silence_gen.h
index c2300c845c..df90ec0e9e 100644
--- a/libs/spandsp/src/spandsp/silence_gen.h
+++ b/libs/spandsp/src/spandsp/silence_gen.h
@@ -84,7 +84,7 @@ SPAN_DECLARE(int) silence_gen_generated(silence_gen_state_t *s);
     \param s The silence generator context.
     \param handler The callback routine used to report status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_tx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Initialise a timed silence generator context.
     \brief Initialise a timed silence generator context.
diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h
index a2fff2d28c..6fde8caf48 100644
--- a/libs/spandsp/src/spandsp/t30.h
+++ b/libs/spandsp/src/spandsp/t30.h
@@ -261,7 +261,7 @@ enum
     T30_ERR_RX_GOTDCS,          /*! DCS received while waiting for DTC */
     T30_ERR_RX_INVALCMD,        /*! Unexpected command after page received */
     T30_ERR_RX_NOCARRIER,       /*! Carrier lost during fax receive */
-    T30_ERR_RX_NOEOL,           /*! Timed out while waiting for EOL (end Of line) */
+    T30_ERR_RX_NOEOL,           /*! Timed out while waiting for EOL (end of line) */
     T30_ERR_RX_NOFAX,           /*! Timed out while waiting for first line */
     T30_ERR_RX_T2EXPDCN,        /*! Timer T2 expired while waiting for DCN */
     T30_ERR_RX_T2EXPD,          /*! Timer T2 expired while waiting for phase D */
diff --git a/libs/spandsp/src/spandsp/telephony.h b/libs/spandsp/src/spandsp/telephony.h
index f6998e09f5..49d7200e83 100644
--- a/libs/spandsp/src/spandsp/telephony.h
+++ b/libs/spandsp/src/spandsp/telephony.h
@@ -77,6 +77,27 @@ typedef int (span_tx_handler_t)(void *s, int16_t amp[], int max_len);
 #define TRUE (!FALSE)
 #endif
 
+/* Fixed point constant macros */
+#define FP_Q_9_7(x) ((int16_t) (128.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_8_8(x) ((int16_t) (256.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_7_9(x) ((int16_t) (512.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_6_10(x) ((int16_t) (1024.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_5_11(x) ((int16_t) (2048.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_4_12(x) ((int16_t) (4096.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_3_13(x) ((int16_t) (8192.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_2_14(x) ((int16_t) (16384.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_1_15(x) ((int16_t) (32768.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+
+#define FP_Q_9_23(x) ((int32_t) (65536.0*128.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_8_24(x) ((int32_t) (65536.0*256.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_7_25(x) ((int32_t) (65536.0*512.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_6_26(x) ((int32_t) (65536.0*1024.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_5_27(x) ((int32_t) (65536.0*2048.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_4_28(x) ((int32_t) (65536.0*4096.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_3_29(x) ((int32_t) (65536.0*8192.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_2_30(x) ((int32_t) (65536.0*16384.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+#define FP_Q_1_31(x) ((int32_t) (65536.0*32768.0*x + ((x >= 0.0)  ?  0.5  :  -0.5)))
+
 #if defined(__cplusplus)
 /* C++ doesn't seem to have sane rounding functions/macros yet */
 #if !defined(WIN32)
diff --git a/libs/spandsp/src/spandsp/v17rx.h b/libs/spandsp/src/spandsp/v17rx.h
index 164fa25232..d6ac46caa1 100644
--- a/libs/spandsp/src/spandsp/v17rx.h
+++ b/libs/spandsp/src/spandsp/v17rx.h
@@ -267,7 +267,7 @@ SPAN_DECLARE(void) v17_rx_set_put_bit(v17_rx_state_t *s, put_bit_func_t put_bit,
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_rx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Process a block of received V.17 modem audio samples.
     \brief Process a block of received V.17 modem audio samples.
diff --git a/libs/spandsp/src/spandsp/v17tx.h b/libs/spandsp/src/spandsp/v17tx.h
index e288817e7a..91fd595149 100644
--- a/libs/spandsp/src/spandsp/v17tx.h
+++ b/libs/spandsp/src/spandsp/v17tx.h
@@ -146,7 +146,7 @@ SPAN_DECLARE(void) v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit,
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_tx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Generate a block of V.17 modem audio samples.
     \brief Generate a block of V.17 modem audio samples.
diff --git a/libs/spandsp/src/spandsp/v22bis.h b/libs/spandsp/src/spandsp/v22bis.h
index 5bdc1791a3..073fb7135a 100644
--- a/libs/spandsp/src/spandsp/v22bis.h
+++ b/libs/spandsp/src/spandsp/v22bis.h
@@ -213,7 +213,7 @@ SPAN_DECLARE(void) v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit,
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_rx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_status_func_t handler, void *user_data);
 
 #if defined(__cplusplus)
 }
diff --git a/libs/spandsp/src/spandsp/v27ter_rx.h b/libs/spandsp/src/spandsp/v27ter_rx.h
index baa04b54fe..bb12801b50 100644
--- a/libs/spandsp/src/spandsp/v27ter_rx.h
+++ b/libs/spandsp/src/spandsp/v27ter_rx.h
@@ -102,7 +102,7 @@ SPAN_DECLARE(void) v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t pu
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_rx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Process a block of received V.27ter modem audio samples.
     \brief Process a block of received V.27ter modem audio samples.
diff --git a/libs/spandsp/src/spandsp/v27ter_tx.h b/libs/spandsp/src/spandsp/v27ter_tx.h
index ce5f440272..8a04e2018c 100644
--- a/libs/spandsp/src/spandsp/v27ter_tx.h
+++ b/libs/spandsp/src/spandsp/v27ter_tx.h
@@ -127,7 +127,7 @@ SPAN_DECLARE(void) v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t ge
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_tx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Generate a block of V.27ter modem audio samples.
     \brief Generate a block of V.27ter modem audio samples.
diff --git a/libs/spandsp/src/spandsp/v29rx.h b/libs/spandsp/src/spandsp/v29rx.h
index dc8c7b4367..d7874b68dc 100644
--- a/libs/spandsp/src/spandsp/v29rx.h
+++ b/libs/spandsp/src/spandsp/v29rx.h
@@ -178,7 +178,7 @@ SPAN_DECLARE(void) v29_rx_set_put_bit(v29_rx_state_t *s, put_bit_func_t put_bit,
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_rx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Process a block of received V.29 modem audio samples.
     \brief Process a block of received V.29 modem audio samples.
diff --git a/libs/spandsp/src/spandsp/v29tx.h b/libs/spandsp/src/spandsp/v29tx.h
index 8a765445c2..3cb14fea94 100644
--- a/libs/spandsp/src/spandsp/v29tx.h
+++ b/libs/spandsp/src/spandsp/v29tx.h
@@ -158,7 +158,7 @@ SPAN_DECLARE(void) v29_tx_set_get_bit(v29_tx_state_t *s, get_bit_func_t get_bit,
     \param s The modem context.
     \param handler The callback routine used to report modem status changes.
     \param user_data An opaque pointer. */
-SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_tx_status_func_t handler, void *user_data);
+SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_status_func_t handler, void *user_data);
 
 /*! Generate a block of V.29 modem audio samples.
     \brief Generate a block of V.29 modem audio samples.
diff --git a/libs/spandsp/src/spandsp/v42.h b/libs/spandsp/src/spandsp/v42.h
index 22d6122b60..0341c28a03 100644
--- a/libs/spandsp/src/spandsp/v42.h
+++ b/libs/spandsp/src/spandsp/v42.h
@@ -5,7 +5,7 @@
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
- * Copyright (C) 2003 Steve Underwood
+ * Copyright (C) 2003, 2011 Steve Underwood
  *
  * All rights reserved.
  *
@@ -36,45 +36,8 @@ far modem supports V.42 is also defined.
 #if !defined(_SPANDSP_V42_H_)
 #define _SPANDSP_V42_H_
 
-enum
-{
-    LAPM_DETECT = 0,
-    LAPM_ESTABLISH = 1,
-    LAPM_DATA = 2,
-    LAPM_RELEASE = 3,
-    LAPM_SIGNAL = 4,
-    LAPM_SETPARM = 5,
-    LAPM_TEST = 6,
-    LAPM_UNSUPPORTED = 7
-};
-
-typedef void (*v42_status_func_t)(void *user_data, int status);
-typedef void (*v42_frame_handler_t)(void *user_data, const uint8_t *pkt, int len);
-
-typedef struct lapm_frame_queue_s
-{
-    struct lapm_frame_queue_s *next;
-    int len;
-    uint8_t frame[];
-} lapm_frame_queue_t;
-
-/*!
-    LAP-M descriptor. This defines the working state for a single instance of LAP-M.
-*/
-typedef struct lapm_state_s lapm_state_t;
-
-/*!
-    V.42 descriptor. This defines the working state for a single instance of V.42.
-*/
 typedef struct v42_state_s v42_state_t;
 
-/*! Log the raw HDLC frames */
-#define LAPM_DEBUG_LAPM_RAW         (1 << 0)
-/*! Log the interpreted frames */
-#define LAPM_DEBUG_LAPM_DUMP        (1 << 1)
-/*! Log state machine changes */
-#define LAPM_DEBUG_LAPM_STATE 	    (1 << 2)
-
 #if defined(__cplusplus)
 extern "C"
 {
@@ -82,58 +45,46 @@ extern "C"
 
 SPAN_DECLARE(const char *) lapm_status_to_str(int status);
 
-/*! Dump LAP.M frames in a raw and/or decoded forms
-    \param frame The frame itself
-    \param len The length of the frame, in octets
-    \param showraw TRUE if the raw octets should be dumped
-    \param txrx TRUE if tx, FALSE if rx. Used to highlight the packet's direction.
-*/
-SPAN_DECLARE(void) lapm_dump(lapm_state_t *s, const uint8_t *frame, int len, int showraw, int txrx);
+SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok);
 
-/*! Accept an HDLC packet
-*/
-SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *buf, int len, int ok);
+SPAN_DECLARE(void) v42_start(v42_state_t *s);
 
-/*! Transmit a LAP.M frame
-*/
-SPAN_DECLARE(int) lapm_tx(lapm_state_t *s, const void *buf, int len);
+SPAN_DECLARE(void) v42_stop(v42_state_t *s);
 
-/*! Transmit a LAP.M information frame
+/*! Set the busy status of the local end of a V.42 context.
+    \param s The V.42 context.
+    \param busy The new local end busy status.
+    \return The previous local end busy status.
 */
-SPAN_DECLARE(int) lapm_tx_iframe(lapm_state_t *s, const void *buf, int len, int cr);
+SPAN_DECLARE(int) v42_set_local_busy_status(v42_state_t *s, int busy);
 
-/*! Send a break over a LAP.M connection
+/*! Get the busy status of the far end of a V.42 context.
+    \param s The V.42 context.
+    \return The far end busy status.
 */
-SPAN_DECLARE(int) lapm_break(lapm_state_t *s, int enable);
+SPAN_DECLARE(int) v42_get_far_busy_status(v42_state_t *s);
 
-/*! Initiate an orderly release of a LAP.M connection
-*/
-SPAN_DECLARE(int) lapm_release(lapm_state_t *s);
-
-/*! Enable or disable loopback of a LAP.M connection
-*/
-SPAN_DECLARE(int) lapm_loopback(lapm_state_t *s, int enable);
-
-/*! Assign or remove a callback routine used to deal with V.42 status changes.
-*/
-SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, v42_status_func_t callback, void *user_data);
-
-/*! Process a newly received bit for a V.42 context.
-*/
 SPAN_DECLARE(void) v42_rx_bit(void *user_data, int bit);
 
-/*! Get the next transmit bit for a V.42 context.
-*/
 SPAN_DECLARE(int) v42_tx_bit(void *user_data);
 
+SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, modem_status_func_t callback, void *user_data);
+
 /*! Initialise a V.42 context.
     \param s The V.42 context.
     \param calling_party TRUE if caller mode, else answerer mode.
-    \param frame_handler A callback function to handle received frames of data.
-    \param user_data An opaque pointer passed to the frame handler routine.
+    \param detect TRUE to perform the V.42 detection, else go straight into LAP.M 
+    \param iframe_get A callback function to handle received frames of data.
+    \param iframe_put A callback function to get frames of data for transmission.
+    \param user_data An opaque pointer passed to the frame handler routines.
     \return ???
 */
-SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data);
+SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s,
+                                     int calling_party,
+                                     int detect,
+                                     get_msg_func_t iframe_get,
+                                     put_msg_func_t iframe_put,
+                                     void *user_data);
 
 /*! Restart a V.42 context.
     \param s The V.42 context.
@@ -143,12 +94,12 @@ SPAN_DECLARE(void) v42_restart(v42_state_t *s);
 /*! Release a V.42 context.
     \param s The V.42 context.
     \return 0 if OK */
-SPAN_DECLARE(int) v42_release(v42_state_t *s);
+SPAN_DECLARE(void) v42_release(v42_state_t *s);
 
 /*! Free a V.42 context.
     \param s The V.42 context.
     \return 0 if OK */
-SPAN_DECLARE(int) v42_free(v42_state_t *s);
+SPAN_DECLARE(void) v42_free(v42_state_t *s);
 
 #if defined(__cplusplus)
 }
diff --git a/libs/spandsp/src/spandsp/v42bis.h b/libs/spandsp/src/spandsp/v42bis.h
index 35d5be3f42..b947a61cd3 100644
--- a/libs/spandsp/src/spandsp/v42bis.h
+++ b/libs/spandsp/src/spandsp/v42bis.h
@@ -5,7 +5,7 @@
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
- * Copyright (C) 2005 Steve Underwood
+ * Copyright (C) 2005, 2011 Steve Underwood
  *
  * All rights reserved.
  *
@@ -39,7 +39,7 @@ conjunction with the error correction scheme defined in V.42.
 #define V42BIS_MIN_DICTIONARY_SIZE  512
 #define V42BIS_MAX_BITS             12
 #define V42BIS_MAX_CODEWORDS        4096    /* 2^V42BIS_MAX_BITS */
-#define V42BIS_TABLE_SIZE           5021    /* This should be a prime >(2^V42BIS_MAX_BITS) */
+#define V42BIS_MAX_OUTPUT_LENGTH    1024
 
 enum
 {
@@ -56,9 +56,6 @@ enum
     V42BIS_COMPRESSION_MODE_NEVER
 };
 
-typedef void (*v42bis_frame_handler_t)(void *user_data, const uint8_t *pkt, int len);
-typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len);
-
 /*!
     V.42bis compression/decompression descriptor. This defines the working state for a
     single instance of V.42bis compress/decompression.
@@ -75,7 +72,7 @@ extern "C"
     \param buf The data to be compressed.
     \param len The length of the data buffer.
     \return 0 */
-SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len);
+SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t buf[], int len);
 
 /*! Flush out any data remaining in a compression buffer.
     \param s The V.42bis context.
@@ -87,7 +84,7 @@ SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s);
     \param buf The data to be decompressed.
     \param len The length of the data buffer.
     \return 0 */
-SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len);
+SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t buf[], int len);
     
 /*! Flush out any data remaining in the decompression buffer.
     \param s The V.42bis context.
@@ -107,23 +104,23 @@ SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode);
     \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec.
     \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec.
     \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec.
-    \param frame_handler Frame callback handler.
-    \param frame_user_data An opaque pointer passed to the frame callback handler.
-    \param max_frame_len The maximum length that should be passed to the frame handler.
-    \param data_handler data callback handler.
-    \param data_user_data An opaque pointer passed to the data callback handler.
-    \param max_data_len The maximum length that should be passed to the data handler.
+    \param encode_handler Encode callback handler.
+    \param encode_user_data An opaque pointer passed to the encode callback handler.
+    \param max_encode_len The maximum length that should be passed to the encode handler.
+    \param decode_handler Decode callback handler.
+    \param decode_user_data An opaque pointer passed to the decode callback handler.
+    \param max_decode_len The maximum length that should be passed to the decode handler.
     \return The V.42bis context. */
 SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s,
                                            int negotiated_p0,
                                            int negotiated_p1,
                                            int negotiated_p2,
-                                           v42bis_frame_handler_t frame_handler,
-                                           void *frame_user_data,
-                                           int max_frame_len,
-                                           v42bis_data_handler_t data_handler,
-                                           void *data_user_data,
-                                           int max_data_len);
+                                           put_msg_func_t encode_handler,
+                                           void *encode_user_data,
+                                           int max_encode_len,
+                                           put_msg_func_t decode_handler,
+                                           void *decode_user_data,
+                                           int max_decode_len);
 
 /*! Release a V.42bis context.
     \param s The V.42bis context.
diff --git a/libs/spandsp/src/timezone.c b/libs/spandsp/src/timezone.c
index b991531e69..04dfa51daf 100644
--- a/libs/spandsp/src/timezone.c
+++ b/libs/spandsp/src/timezone.c
@@ -114,11 +114,11 @@ static const int year_lengths[2] =
 
 static int increment_overflow(int *number, int delta)
 {
-    int number0;
+    int last_number;
 
-    number0 = *number;
+    last_number = *number;
     *number += delta;
-    return (*number < number0) != (delta < 0);
+    return (*number < last_number) != (delta < 0);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -164,6 +164,10 @@ static struct tm *time_sub(const time_t * const timep, const long int offset, co
     int y;
     int hit;
     int i;
+    int newy;
+    time_t tdelta;
+    int idelta;
+    int leapdays;
 
     corr = 0;
     hit = 0;
@@ -198,11 +202,6 @@ static struct tm *time_sub(const time_t * const timep, const long int offset, co
     rem = *timep - tdays*SECS_PER_DAY;
     while (tdays < 0  ||  tdays >= year_lengths[isleap(y)])
     {
-        int newy;
-        time_t tdelta;
-        int idelta;
-        int leapdays;
-
         tdelta = tdays / DAYS_PER_LEAP_YEAR;
         idelta = tdelta;
         if (tdelta - idelta >= 1  ||  idelta - tdelta >= 1)
diff --git a/libs/spandsp/src/v17rx.c b/libs/spandsp/src/v17rx.c
index 974448b46a..3fac6a00ad 100644
--- a/libs/spandsp/src/v17rx.c
+++ b/libs/spandsp/src/v17rx.c
@@ -1248,7 +1248,7 @@ SPAN_DECLARE(void) v17_rx_set_put_bit(v17_rx_state_t *s, put_bit_func_t put_bit,
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/v17tx.c b/libs/spandsp/src/v17tx.c
index 8cce8940e9..0e4f603c0b 100644
--- a/libs/spandsp/src/v17tx.c
+++ b/libs/spandsp/src/v17tx.c
@@ -364,7 +364,7 @@ SPAN_DECLARE(void) v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit,
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/v22bis_tx.c b/libs/spandsp/src/v22bis_tx.c
index 5619e87120..39ad4dd240 100644
--- a/libs/spandsp/src/v22bis_tx.c
+++ b/libs/spandsp/src/v22bis_tx.c
@@ -552,7 +552,7 @@ SPAN_DECLARE(void) v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit,
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/v27ter_rx.c b/libs/spandsp/src/v27ter_rx.c
index 8685ef1d77..22ce185408 100644
--- a/libs/spandsp/src/v27ter_rx.c
+++ b/libs/spandsp/src/v27ter_rx.c
@@ -1019,7 +1019,7 @@ SPAN_DECLARE(void) v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t pu
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/v27ter_tx.c b/libs/spandsp/src/v27ter_tx.c
index 5f35510231..bff8bb7071 100644
--- a/libs/spandsp/src/v27ter_tx.c
+++ b/libs/spandsp/src/v27ter_tx.c
@@ -374,7 +374,7 @@ SPAN_DECLARE(void) v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t ge
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/v29rx.c b/libs/spandsp/src/v29rx.c
index 17ddada9e8..a94af80574 100644
--- a/libs/spandsp/src/v29rx.c
+++ b/libs/spandsp/src/v29rx.c
@@ -1052,7 +1052,7 @@ SPAN_DECLARE(void) v29_rx_set_put_bit(v29_rx_state_t *s, put_bit_func_t put_bit,
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/v29tx.c b/libs/spandsp/src/v29tx.c
index 39c6c99b9a..10007a93fb 100644
--- a/libs/spandsp/src/v29tx.c
+++ b/libs/spandsp/src/v29tx.c
@@ -316,7 +316,7 @@ SPAN_DECLARE(void) v29_tx_set_get_bit(v29_tx_state_t *s, get_bit_func_t get_bit,
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
+SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_status_func_t handler, void *user_data)
 {
     s->status_handler = handler;
     s->status_user_data = user_data;
diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c
index 74630ee84d..7aea3f2116 100644
--- a/libs/spandsp/src/v42.c
+++ b/libs/spandsp/src/v42.c
@@ -5,7 +5,7 @@
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
- * Copyright (C) 2004 Steve Underwood
+ * Copyright (C) 2004, 2011 Steve Underwood
  *
  * All rights reserved.
  *
@@ -36,323 +36,125 @@
 #include <inttypes.h>
 #include <string.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <assert.h>
 
 #include "spandsp/telephony.h"
 #include "spandsp/logging.h"
+#include "spandsp/bit_operations.h"
 #include "spandsp/async.h"
 #include "spandsp/hdlc.h"
-#include "spandsp/schedule.h"
-#include "spandsp/queue.h"
 #include "spandsp/v42.h"
 
 #include "spandsp/private/logging.h"
-#include "spandsp/private/schedule.h"
 #include "spandsp/private/hdlc.h"
 #include "spandsp/private/v42.h"
 
-#if !defined(FALSE)
-#define FALSE   0
-#endif
-#if !defined(TRUE)
-#define TRUE    (!FALSE)
-#endif
+#define FALSE 0
+#define TRUE (!FALSE)
 
-#define LAPM_FRAMETYPE_MASK         0x03
-
-#define LAPM_FRAMETYPE_I            0x00
-#define LAPM_FRAMETYPE_I_ALT        0x02
-#define LAPM_FRAMETYPE_S            0x01
-#define LAPM_FRAMETYPE_U            0x03
-
-/* Timer values */
-
-#define T_WAIT_MIN                  2000
-#define T_WAIT_MAX                  10000
 /* Detection phase timer */
-#define T_400                       750000
+#define T_400                           750
 /* Acknowledgement timer - 1 second between SABME's */
-#define T_401                       1000000
+#define T_401                           1000
 /* Replay delay timer (optional) */
-#define T_402                       1000000
+#define T_402                           1000
 /* Inactivity timer (optional). No default - use 10 seconds with no packets */
-#define T_403                       10000000
-/* Max retries */
-#define N_400                       3
-/* Max octets in an information field */
-#define N_401                       128
+#define T_403                           10000
 
-#define LAPM_DLCI_DTE_TO_DTE        0
-#define LAPM_DLCI_LAYER2_MANAGEMENT 63
+#define LAPM_DLCI_DTE_TO_DTE            0
+#define LAPM_DLCI_LAYER2_MANAGEMENT     63
 
-static void t401_expired(span_sched_state_t *s, void *user_data);
-static void t403_expired(span_sched_state_t *s, void *user_data);
+#define elements(a) (sizeof(a)/sizeof((a)[0]))
 
-SPAN_DECLARE(void) lapm_reset(lapm_state_t *s);
-SPAN_DECLARE(void) lapm_restart(lapm_state_t *s);
+/* LAPM definitions */
 
-static void lapm_link_down(lapm_state_t *s);
+#define LAPM_FRAMETYPE_MASK             0x03
 
-static __inline__ void lapm_init_header(uint8_t *frame, int command)
+enum
 {
-    /* Data link connection identifier (0) */
-    /* Command/response (0 if answerer, 1 if originator) */
-    /* Extended address (1) */
-    frame[0] = (LAPM_DLCI_DTE_TO_DTE << 2) | ((command)  ?  0x02  :  0x00) | 0x01;
-}
-/*- End of function --------------------------------------------------------*/
+    LAPM_FRAMETYPE_I = 0x00,
+    LAPM_FRAMETYPE_I_ALT = 0x02,
+    LAPM_FRAMETYPE_S = 0x01,
+    LAPM_FRAMETYPE_U = 0x03
+};
 
-static int lapm_tx_frame(lapm_state_t *s, uint8_t *frame, int len)
+/* Supervisory headers */
+enum
 {
-    if ((s->debug & LAPM_DEBUG_LAPM_DUMP))
-        lapm_dump(s, frame, len, s->debug & LAPM_DEBUG_LAPM_RAW, TRUE);
-    /*endif*/
-    hdlc_tx_frame(&s->hdlc_tx, frame, len);
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
+    LAPM_S_RR = 0x00,       /* cr */
+    LAPM_S_RNR = 0x04,      /* cr */
+    LAPM_S_REJ = 0x08,      /* cr */
+    LAPM_S_SREJ = 0x0C      /* cr */
+};
 
-static void t400_expired(span_sched_state_t *ss, void *user_data)
+#define LAPM_S_PF                       0x01
+
+/* Unnumbered headers */
+enum
 {
-    v42_state_t *s;
-    
-    /* Give up trying to detect a V.42 capable peer. */
-    s = (v42_state_t *) user_data;
-    s->t400_timer = -1;
-    s->lapm.state = LAPM_UNSUPPORTED;
-    if (s->lapm.status_callback)
-        s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state);
-    /*endif*/
-}
-/*- End of function --------------------------------------------------------*/
+    LAPM_U_UI = 0x00,       /* cr */
+    LAPM_U_DM = 0x0C,       /*  r */
+    LAPM_U_DISC = 0x40,     /* c  */
+    LAPM_U_UA = 0x60,       /*  r */
+    LAPM_U_SABME = 0x6C,    /* c  */
+    LAPM_U_FRMR = 0x84,     /*  r */
+    LAPM_U_XID = 0xAC,      /* cr */
+    LAPM_U_TEST = 0xE0      /* c  */
+};
 
-static void lapm_send_ua(lapm_state_t *s, int pfbit)
+#define LAPM_U_PF                       0x10
+
+/* XID sub-field definitions */
+#define FI_GENERAL                      0x82
+#define GI_PARAM_NEGOTIATION            0x80
+#define GI_PRIVATE_NEGOTIATION          0xF0
+#define GI_USER_DATA                    0xFF
+
+/* Param negotiation (Table 11a/V.42) */
+enum
 {
-    uint8_t frame[3];
+    PI_HDLC_OPTIONAL_FUNCTIONS = 0x03,
+    PI_TX_INFO_MAXSIZE = 0x05,
+    PI_RX_INFO_MAXSIZE = 0x06,
+    PI_TX_WINDOW_SIZE = 0x07,
+    PI_RX_WINDOW_SIZE = 0x08
+};
 
-    lapm_init_header(frame, !s->we_are_originator);
-    frame[1] = (uint8_t) (0x63 | (pfbit << 4));
-    frame[2] = 0;
-    span_log(&s->logging, SPAN_LOG_FLOW, "Sending unnumbered acknowledgement\n");
-    lapm_tx_frame(s, frame, 3);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void lapm_send_sabme(span_sched_state_t *ss, void *user_data)
+/* Private param negotiation (Table 11b/V.42) */
+enum
 {
-    lapm_state_t *s;
-    uint8_t frame[3];
+    PI_PARAMETER_SET_ID = 0x00,
+    PI_V42BIS_COMPRESSION_REQUEST = 0x01,
+    PI_V42BIS_NUM_CODEWORDS = 0x02,
+    PI_V42BIS_MAX_STRING_LENGTH = 0x03
+};
 
-    s = (lapm_state_t *) user_data;
-    if (s->t401_timer >= 0)
-    {
-fprintf(stderr, "Deleting T401 q [%p] %d\n", (void *) s, s->t401_timer);
-        span_schedule_del(&s->sched, s->t401_timer);
-        s->t401_timer = -1;
-    }
-    /*endif*/
-    if (++s->retransmissions > N_400)
-    {
-        /* 8.3.2.2 Too many retries */
-        s->state = LAPM_RELEASE;
-        if (s->status_callback)
-            s->status_callback(s->status_callback_user_data, s->state);
-        /*endif*/
-        return;
-    }
-    /*endif*/
-fprintf(stderr, "Setting T401 a1 [%p]\n", (void *) s);
-    s->t401_timer = span_schedule_event(&s->sched, T_401, lapm_send_sabme, s);
-    lapm_init_header(frame, s->we_are_originator);
-    frame[1] = 0x7F;
-    frame[2] = 0;
-    span_log(&s->logging, SPAN_LOG_FLOW, "Sending SABME (set asynchronous balanced mode extended)\n");
-    lapm_tx_frame(s, frame, 3);
-}
-/*- End of function --------------------------------------------------------*/
+#define LAPM_DLCI_DTE_TO_DTE            0
+#define LAPM_DLCI_LAYER2_MANAGEMENT     63
 
-static int lapm_ack_packet(lapm_state_t *s, int num)
+/* Type definitions */
+enum
 {
-    lapm_frame_queue_t *f;
-    lapm_frame_queue_t *prev;
+    LAPM_DETECT = 0,
+    LAPM_IDLE = 1,
+    LAPM_ESTABLISH = 2,
+    LAPM_DATA = 3,
+    LAPM_RELEASE = 4,
+    LAPM_SIGNAL = 5,
+    LAPM_SETPARM = 6,
+    LAPM_TEST = 7,
+    LAPM_V42_UNSUPPORTED = 8
+};
 
-    for (prev = NULL, f = s->txqueue;  f;  prev = f, f = f->next)
-    {
-        if ((f->frame[1] >> 1) == num)
-        {
-            /* Cancel each packet, as necessary */
-            if (prev)
-                prev->next = f->next;
-            else
-                s->txqueue = f->next;
-            /*endif*/
-            span_log(&s->logging,
-                     SPAN_LOG_FLOW,
-                     "-- ACKing packet %d. New txqueue is %d (-1 means empty)\n",
-                     (f->frame[1] >> 1),
-                     (s->txqueue)  ?  (s->txqueue->frame[1] >> 1)  :  -1);
-            s->last_frame_peer_acknowledged = num;
-            free(f);
-            /* Reset retransmission count if we actually acked something */
-            s->retransmissions = 0;
-            return 1;
-        }
-        /*endif*/
-    }
-    /*endfor*/
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
+/* Prototypes */
+static int lapm_connect(v42_state_t *ss);
+static int lapm_disconnect(v42_state_t *s);
+static void reset_lapm(v42_state_t *s);
+static void lapm_hdlc_underflow(void *user_data);
 
-static void lapm_ack_rx(lapm_state_t *s, int ack)
-{
-    int i;
-    int cnt;
-
-    /* This might not be acking anything new */
-    if (s->last_frame_peer_acknowledged == ack)
-        return;
-    /*endif*/
-    /* It should be acking something that is actually outstanding */
-    if ((s->last_frame_peer_acknowledged < s->next_tx_frame  &&  (ack < s->last_frame_peer_acknowledged  ||  ack > s->next_tx_frame))
-        ||
-        (s->last_frame_peer_acknowledged > s->next_tx_frame  &&  (ack > s->last_frame_peer_acknowledged  ||  ack < s->next_tx_frame)))
-    {
-        /* ACK was outside our window --- ignore */
-        span_log(&s->logging, SPAN_LOG_FLOW, "ACK received outside window, ignoring\n");
-        return;
-    }
-    /*endif*/
-    
-    /* Cancel each packet, as necessary */
-    span_log(&s->logging,
-             SPAN_LOG_FLOW,
-             "-- ACKing all packets from %d to (but not including) %d\n",
-             s->last_frame_peer_acknowledged,
-             ack);
-    for (cnt = 0, i = s->last_frame_peer_acknowledged;  i != ack;  i = (i + 1) & 0x7F) 
-        cnt += lapm_ack_packet(s, i);
-    /*endfor*/
-    s->last_frame_peer_acknowledged = ack;
-    if (s->txqueue == NULL)
-    {
-        span_log(&s->logging, SPAN_LOG_FLOW, "-- Since there was nothing left, stopping timer T_401\n");
-        /* Something was ACK'd.  Stop timer T_401. */
-fprintf(stderr, "T401 a2 is %d [%p]\n", s->t401_timer, (void *) s);
-        if (s->t401_timer >= 0)
-        {
-fprintf(stderr, "Deleting T401 a3 [%p] %d\n", (void *) s, s->t401_timer);
-            span_schedule_del(&s->sched, s->t401_timer);
-            s->t401_timer = -1;
-        }
-        /*endif*/
-    }
-    /*endif*/
-    if (s->t403_timer >= 0)
-    {
-        span_log(&s->logging, SPAN_LOG_FLOW, "-- Stopping timer T_403, since we got an ACK\n");
-        if (s->t403_timer >= 0)
-        {
-fprintf(stderr, "Deleting T403 b %d\n", s->t403_timer);
-            span_schedule_del(&s->sched, s->t403_timer);
-            s->t403_timer = -1;
-        }
-        /*endif*/
-    }
-    /*endif*/
-    if (s->txqueue)
-    {
-        /* Something left to transmit. Start timer T_401 again if it is stopped */
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW,
-                 "-- Something left to transmit (%d). Restarting timer T_401\n",
-                 s->txqueue->frame[1] >> 1);
-        if (s->t401_timer < 0)
-        {
-fprintf(stderr, "Setting T401 b [%p]\n", (void *) s);
-            s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s);
-        }
-        /*endif*/
-    }
-    else
-    {
-        span_log(&s->logging, SPAN_LOG_FLOW, "-- Nothing left, starting timer T_403\n");
-        /* Nothing to transmit. Start timer T_403. */
-fprintf(stderr, "Setting T403 c\n");
-        s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s);
-    }
-    /*endif*/
-}
-/*- End of function --------------------------------------------------------*/
-
-static void lapm_reject(lapm_state_t *s)
-{
-    uint8_t frame[4];
-
-    lapm_init_header(frame, !s->we_are_originator);
-    frame[1] = (uint8_t) (0x00 | 0x08 | LAPM_FRAMETYPE_S);
-    /* Where to start retransmission */
-    frame[2] = (uint8_t) ((s->next_expected_frame << 1) | 0x01);
-    span_log(&s->logging, SPAN_LOG_FLOW, "Sending REJ (reject (%d)\n", s->next_expected_frame);
-    lapm_tx_frame(s, frame, 4);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void lapm_rr(lapm_state_t *s, int pfbit)
-{
-    uint8_t frame[4];
-
-    lapm_init_header(frame, !s->we_are_originator);
-    frame[1] = (uint8_t) (0x00 | 0x00 | LAPM_FRAMETYPE_S);
-    frame[2] = (uint8_t) ((s->next_expected_frame << 1) | pfbit);
-    /* Note that we have already ACKed this */
-    s->last_frame_we_acknowledged = s->next_expected_frame;
-    span_log(&s->logging, SPAN_LOG_FLOW, "Sending RR (receiver ready) (%d)\n", s->next_expected_frame);
-    lapm_tx_frame(s, frame, 4);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void t401_expired(span_sched_state_t *ss, void *user_data)
-{
-    lapm_state_t *s;
-    
-    s = (lapm_state_t *) user_data;
-fprintf(stderr, "Expiring T401 a4 [%p]\n", (void *) s);
-    s->t401_timer = -1;
-    if (s->txqueue)
-    {
-        /* Retransmit first packet in the queue, setting the poll bit */
-        span_log(&s->logging, SPAN_LOG_FLOW, "-- Timer T_401 expired, What to do...\n");
-        /* Update N(R), and set the poll bit */
-        s->txqueue->frame[2] = (uint8_t)((s->next_expected_frame << 1) | 0x01);
-        s->last_frame_we_acknowledged = s->next_expected_frame;
-        s->solicit_f_bit = TRUE;
-        if (++s->retransmissions <= N_400)
-        {
-            /* Reschedule timer T401 */
-            span_log(&s->logging, SPAN_LOG_FLOW, "-- Retransmitting %d bytes\n", s->txqueue->len);
-            lapm_tx_frame(s, s->txqueue->frame, s->txqueue->len);
-            span_log(&s->logging, SPAN_LOG_FLOW, "-- Scheduling retransmission (%d)\n", s->retransmissions);
-fprintf(stderr, "Setting T401 d [%p]\n", (void *) s);
-            s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s);
-        }
-        else
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "-- Timeout occured\n");
-            s->state = LAPM_RELEASE;
-            if (s->status_callback)
-                s->status_callback(s->status_callback_user_data, s->state);
-            lapm_link_down(s);
-            lapm_restart(s);
-        }
-        /*endif*/
-    }
-    else
-    {
-        span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_401 expired. Nothing to send...\n");
-    }
-    /*endif*/
-}
-/*- End of function --------------------------------------------------------*/
+static int lapm_config(v42_state_t *ss);
 
 SPAN_DECLARE(const char *) lapm_status_to_str(int status)
 {
@@ -360,6 +162,8 @@ SPAN_DECLARE(const char *) lapm_status_to_str(int status)
     {
     case LAPM_DETECT:
         return "LAPM_DETECT";
+    case LAPM_IDLE:
+        return "LAPM_IDLE";
     case LAPM_ESTABLISH:
         return "LAPM_ESTABLISH";
     case LAPM_DATA:
@@ -372,740 +176,1048 @@ SPAN_DECLARE(const char *) lapm_status_to_str(int status)
         return "LAPM_SETPARM";
     case LAPM_TEST:
         return "LAPM_TEST";
-    case LAPM_UNSUPPORTED:
-        return "LAPM_UNSUPPORTED";
+    case LAPM_V42_UNSUPPORTED:
+        return "LAPM_V42_UNSUPPORTED";
     }
     /*endswitch*/
     return "???";
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(int) lapm_tx(lapm_state_t *s, const void *buf, int len)
+static void report_rx_status_change(v42_state_t *s, int status)
 {
-    return queue_write(s->tx_queue, buf, len);
+    if (s->lapm.status_handler)
+        s->lapm.status_handler(s->lapm.status_user_data, status);
+    else if (s->lapm.iframe_put)
+        s->lapm.iframe_put(s->lapm.iframe_put_user_data, NULL, status);
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(int) lapm_release(lapm_state_t *s)
+static inline uint32_t pack_value(const uint8_t *buf, int len)
 {
-    s->state = LAPM_RELEASE;
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
+    uint32_t val;
 
-SPAN_DECLARE(int) lapm_loopback(lapm_state_t *s, int enable)
-{
-    s->state = LAPM_TEST;
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(int) lapm_break(lapm_state_t *s, int enable)
-{
-    s->state = LAPM_SIGNAL;
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(int) lapm_tx_iframe(lapm_state_t *s, const void *buf, int len, int cr)
-{
-    lapm_frame_queue_t *f;
-
-    if ((f = malloc(sizeof(*f) + len + 4)) == NULL)
+    val = 0;
+    while (len--)
     {
-        span_log(&s->logging, SPAN_LOG_FLOW, "Out of memory\n");
+        val <<= 8;
+        val |= *buf++;
+    }
+    return val;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline v42_frame_t *get_next_free_ctrl_frame(lapm_state_t *s)
+{
+    v42_frame_t *f;
+    int ctrl_put_next;
+
+    if ((ctrl_put_next = s->ctrl_put + 1) >= V42_CTRL_FRAMES)
+        ctrl_put_next = 0;
+    if (ctrl_put_next == s->ctrl_get)
+        return NULL;
+    f = &s->ctrl_buf[s->ctrl_put];
+    s->ctrl_put = ctrl_put_next;
+    return f;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int tx_unnumbered_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint8_t *info, int len)
+{
+    v42_frame_t *f;
+    uint8_t *buf;
+
+    if ((f = get_next_free_ctrl_frame(s)) == NULL)
+        return -1;
+    buf = f->buf;
+    buf[0] = addr;
+    buf[1] = LAPM_FRAMETYPE_U | ctrl;
+    f->len = 2;
+    if (info  &&  len)
+    {
+        memcpy(buf + f->len, info, len);
+        f->len += len;
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int tx_supervisory_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint8_t pf_mask)
+{
+    v42_frame_t *f;
+    uint8_t *buf;
+    
+    if ((f = get_next_free_ctrl_frame(s)) == NULL)
+        return -1;
+    buf = f->buf;
+    buf[0] = addr;
+    buf[1] = LAPM_FRAMETYPE_S | ctrl;
+    buf[2] = (s->vr << 1) | pf_mask;
+    f->len = 3;
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int set_param(int param, int value, int def)
+{
+    if ((value < def  &&  param >= def)  ||  (value >= def  &&  param < def))
+        return def;
+    if ((value < def  &&  param < value)  ||  (value >= def  &&  param > value))
+        return value;
+    return param;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int receive_xid(v42_state_t *ss, const uint8_t *frame, int len)
+{
+    lapm_state_t *s;
+    v42_config_parameters_t config;
+    const uint8_t *buf;
+    uint8_t group_id;
+    uint16_t group_len;
+    uint32_t param_val;
+    uint8_t param_id;
+    uint8_t param_len;
+
+    s = &ss->lapm;
+    if (frame[2] != FI_GENERAL)
+        return -1;
+    memset(&config, 0, sizeof(config));
+    /* Skip the header octets */
+    frame += 3;
+    len -= 3;
+    while (len > 0)
+    {
+        group_id = frame[0];
+        group_len = frame[1];
+        group_len = (group_len << 8) | frame[2];
+        frame += 3;
+        len -= (3 + group_len);
+        if (len < 0)
+            break;
+        buf = frame;
+        frame += group_len;
+        switch (group_id)
+        {
+        case GI_PARAM_NEGOTIATION:
+            while (group_len > 0)
+            {
+                param_id = buf[0];
+                param_len = buf[1];
+                buf += 2;
+                group_len -= (2 + param_len);
+                if (group_len < 0)
+                    break;
+                switch (param_id)
+                {
+                case PI_HDLC_OPTIONAL_FUNCTIONS:
+                    param_val = pack_value(buf, param_len);
+                    break;
+                case PI_TX_INFO_MAXSIZE:
+                    param_val = pack_value(buf, param_len);
+                    param_val >>= 3;
+                    config.v42_tx_n401 =
+                    s->tx_n401 = set_param(s->tx_n401, param_val, ss->config.v42_tx_n401);
+                    break;
+                case PI_RX_INFO_MAXSIZE:
+                    param_val = pack_value(buf, param_len);
+                    param_val >>= 3;
+                    config.v42_rx_n401 =
+                    s->rx_n401 = set_param(s->rx_n401, param_val, ss->config.v42_rx_n401);
+                    break;
+                case PI_TX_WINDOW_SIZE:
+                    param_val = pack_value(buf, param_len);
+                    config.v42_tx_window_size_k =
+                    s->tx_window_size_k = set_param(s->tx_window_size_k, param_val, ss->config.v42_tx_window_size_k);
+                    break;
+                case PI_RX_WINDOW_SIZE:
+                    param_val = pack_value(buf, param_len);
+                    config.v42_rx_window_size_k =
+                    s->rx_window_size_k = set_param(s->rx_window_size_k, param_val, ss->config.v42_rx_window_size_k);
+                    break;
+                default:
+                    break;
+                }
+                buf += param_len;
+            }
+            break;
+        case GI_PRIVATE_NEGOTIATION:
+            while (group_len > 0)
+            {
+                param_id = buf[0];
+                param_len = buf[1];
+                buf += 2;
+                group_len -= (2 + param_len);
+                if (group_len < 0)
+                    break;
+                switch (param_id)
+                {
+                case PI_PARAMETER_SET_ID:
+                    /* This might be worth monitoring, but it doesn't serve mnuch other purpose */
+                    break;
+                case PI_V42BIS_COMPRESSION_REQUEST:
+                    config.comp = pack_value(buf, param_len);
+                    break;
+                case PI_V42BIS_NUM_CODEWORDS:
+                    config.comp_dict_size = pack_value(buf, param_len);
+                    break;
+                case PI_V42BIS_MAX_STRING_LENGTH:
+                    config.comp_max_string = pack_value(buf, param_len);
+                    break;
+                default:
+                    break;
+                }
+                buf += param_len;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    //v42_update_config(ss, &config);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void transmit_xid(v42_state_t *ss, uint8_t addr)
+{
+    lapm_state_t *s;
+    uint8_t *buf;
+    int len;
+    int group_len;
+    uint32_t param_val;
+    v42_frame_t *f;
+
+    s = &ss->lapm;
+    if ((f = get_next_free_ctrl_frame(s)) == NULL)
+        return;
+
+    buf = f->buf;
+    len = 0;
+
+    /* Figure 11/V.42 */
+    *buf++ = addr;
+    *buf++ = LAPM_U_XID | LAPM_FRAMETYPE_U;
+    /* Format identifier subfield */
+    *buf++ = FI_GENERAL;
+    len += 3;
+
+    /* Parameter negotiation group */
+    group_len = 20;
+    *buf++ = GI_PARAM_NEGOTIATION;
+    *buf++ = (group_len >> 8) & 0xFF;
+    *buf++ = group_len & 0xFF;
+    len += 3;
+
+    /* For conformance with the encoding rules in ISO/IEC 8885, the transmitter of an XID command frame shall
+       set bit positions 2, 4, 8, 9, 12 and 16 to 1. (Table 11a/V.42)
+       Optional bits are:
+         3 Selective retransmission procedure (SREJ frame) single I frame request
+        14 Loop-back test procedure (TEST frame)
+        17
+        Extended FCS procedure (32-bit FCS)
+        24 Selective retransmission procedure (SREJ frame) multiple I frame request with span list
+           capability. */
+    *buf++ = PI_HDLC_OPTIONAL_FUNCTIONS;
+    *buf++ = 4;
+    *buf++ = 0x8A;  /* Bits 2, 4, and 8 set */
+    *buf++ = 0x89;  /* Bits 9, 12, and 16 set */
+    *buf++ = 0x00;
+    *buf++ = 0x00;
+
+    /* Send the maximum as a number of bits, rather than octets */
+    param_val = ss->config.v42_tx_n401 << 3;
+    *buf++ = PI_TX_INFO_MAXSIZE;
+    *buf++ = 2;
+    *buf++ = (param_val >> 8) & 0xFF;
+    *buf++ = (param_val & 0xFF);
+
+    /* Send the maximum as a number of bits, rather than octets */
+    param_val = ss->config.v42_rx_n401 << 3;
+    *buf++ = PI_RX_INFO_MAXSIZE;
+    *buf++ = 2;
+    *buf++ = (param_val >> 8) & 0xFF;
+    *buf++ = (param_val & 0xFF);
+    
+    *buf++ = PI_TX_WINDOW_SIZE;
+    *buf++ = 1;
+    *buf++ = ss->config.v42_tx_window_size_k;
+
+    *buf++ = PI_RX_WINDOW_SIZE;
+    *buf++ = 1;
+    *buf++ = ss->config.v42_rx_window_size_k;
+
+    len += group_len;
+
+    if (ss->config.comp)
+    {
+        /* Private parameter negotiation group */
+        group_len = 15;
+        *buf++ = GI_PRIVATE_NEGOTIATION;
+        *buf++ = (group_len >> 8) & 0xFF;
+        *buf++ = group_len & 0xFF;
+        len += 3;
+
+        /* Private parameter for V.42 (ASCII for V42). V.42 says ".42", but V.42bis says "V42",
+           and that seems to be what should be used. */
+        *buf++ = PI_PARAMETER_SET_ID;
+        *buf++ = 3;
+        *buf++ = 'V';
+        *buf++ = '4';
+        *buf++ = '2';
+
+        /* V.42bis P0 
+           00 Compression in neither direction (default);
+           01 Negotiation initiator-responder direction only;
+           10 Negotiation responder-initiator direction only;
+           11 Both directions. */
+        *buf++ = PI_V42BIS_COMPRESSION_REQUEST;
+        *buf++ = 1;
+        *buf++ = ss->config.comp;
+
+        /* V.42bis P1 */
+        param_val = ss->config.comp_dict_size;
+        *buf++ = PI_V42BIS_NUM_CODEWORDS;
+        *buf++ = 2;
+        *buf++ = (param_val >> 8) & 0xFF;
+        *buf++ = param_val & 0xFF;
+
+        /* V.42bis P2 */
+        *buf++ = PI_V42BIS_MAX_STRING_LENGTH;
+        *buf++ = 1;
+        *buf++ = ss->config.comp_max_string;
+
+        len += group_len;
+    }
+
+    f->len = len;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int ms_to_bits(v42_state_t *s, int time)
+{
+    return ((time*s->tx_bit_rate)/1000);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void t400_expired(v42_state_t *ss)
+{
+    /* Give up trying to detect a V.42 capable peer. */
+    ss->bit_timer = 0;
+    ss->lapm.state = LAPM_V42_UNSUPPORTED;
+    report_rx_status_change(ss, ss->lapm.state);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void t400_start(v42_state_t *s)
+{
+    s->bit_timer = ms_to_bits(s, T_400);
+    s->bit_timer_func = t400_expired;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void t400_stop(v42_state_t *s)
+{
+    s->bit_timer = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void t401_expired(v42_state_t *ss)
+{
+    lapm_state_t *s;
+
+    span_log(&ss->logging, SPAN_LOG_FLOW, "T.401 expired\n");
+    s = &ss->lapm;
+    if (s->retry_count > V42_DEFAULT_N_400)
+    {
+        s->retry_count = 0;
+        switch (s->state)
+        {
+        case LAPM_ESTABLISH:
+        case LAPM_RELEASE:
+            s->state = LAPM_IDLE;
+            report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED);
+            break;
+        case LAPM_DATA:
+            lapm_disconnect(ss);
+            break;
+        }
+        return ;
+    }
+    s->retry_count++;
+    if (s->configuring)
+    {
+        transmit_xid(ss, s->cmd_addr);
+    }
+    else
+    {
+        switch (s->state)
+        {
+        case LAPM_ESTABLISH:
+            tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_SABME | LAPM_U_PF, NULL, 0);
+            break;
+        case LAPM_RELEASE:
+            tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_DISC | LAPM_U_PF, NULL, 0);
+            break;
+        case LAPM_DATA:
+            tx_supervisory_frame(s, s->cmd_addr, (s->local_busy)  ?  LAPM_S_RNR  :  LAPM_S_RR, 1);
+            break;
+        }
+    }
+    ss->bit_timer = ms_to_bits(ss, T_401);
+    ss->bit_timer_func = t401_expired;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void t401_start(v42_state_t *s)
+{
+    s->bit_timer = ms_to_bits(s, T_401);
+    s->bit_timer_func = t401_expired;
+    s->lapm.retry_count = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void t401_stop(v42_state_t *s)
+{
+    s->bit_timer = 0;
+    s->lapm.retry_count = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void t403_expired(v42_state_t *ss)
+{
+    lapm_state_t *s;
+
+    span_log(&ss->logging, SPAN_LOG_FLOW, "T.403 expired\n");
+    if (ss->lapm.state != LAPM_DATA)
+        return;
+    s = &ss->lapm;
+    tx_supervisory_frame(s, s->cmd_addr, (ss->lapm.local_busy)  ?  LAPM_S_RNR  :  LAPM_S_RR, 1);
+    t401_start(ss);
+    ss->lapm.retry_count = 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void t401_stop_t403_start(v42_state_t *s)
+{
+    s->bit_timer = ms_to_bits(s, T_403);
+    s->bit_timer_func = t403_expired;
+    s->lapm.retry_count = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void initiate_negotiation_expired(v42_state_t *s)
+{
+    /* Timer service routine */
+    span_log(&s->logging, SPAN_LOG_FLOW, "Start negotiation\n");
+    lapm_config(s);
+    lapm_hdlc_underflow(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int tx_information_frame(v42_state_t *ss)
+{
+    lapm_state_t *s;
+    v42_frame_t *f;
+    uint8_t *buf;
+    int n;
+    int info_put_next;
+
+    s = &ss->lapm;
+    if (s->far_busy  ||  ((s->vs - s->va) & 0x7F) >= s->tx_window_size_k)
+        return FALSE;
+    if (s->info_get != s->info_put)
+        return TRUE;
+    if ((info_put_next = s->info_put + 1) >= V42_INFO_FRAMES)
+        info_put_next = 0;
+    if (info_put_next == s->info_get  ||  info_put_next == s->info_acked)
+        return FALSE;
+    f = &s->info_buf[s->info_put];
+    buf = f->buf;
+    if (s->iframe_get == NULL)
+        return FALSE;
+    n = s->iframe_get(s->iframe_get_user_data, buf + 3, s->tx_n401);
+    if (n < 0)
+    {
+        /* Error */
+        report_rx_status_change(ss, SIG_STATUS_LINK_ERROR);
+        return FALSE;
+    }
+    if (n == 0)
+        return FALSE;
+
+    f->len = n + 3;
+    s->info_put = info_put_next;
+    return TRUE;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void tx_information_rr_rnr_response(v42_state_t *ss, const uint8_t *frame, int len)
+{
+    lapm_state_t *s;
+
+    s = &ss->lapm;
+    /* Respond with information frame, RR, or RNR, as appropriate */
+    /* p = 1 may be used for status checking */
+    if ((frame[2] & 0x1)  ||  !tx_information_frame(ss))
+        tx_supervisory_frame(s, frame[0], (s->local_busy)  ?  LAPM_S_RNR  :  LAPM_S_RR, 1);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int reject_info(lapm_state_t *s)
+{
+    uint8_t n;
+
+    /* Reject all non-acked frames */
+    if (s->state != LAPM_DATA)
+        return 0;
+    n = (s->vs - s->va) & 0x7F;
+    s->vs = s->va;
+    s->info_get = s->info_acked;
+    return n;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int ack_info(v42_state_t *ss, uint8_t nr)
+{
+    lapm_state_t *s;
+    int n;
+
+    s = &ss->lapm;
+    /* Check that NR is valid - i.e.  VA <= NR <= VS  &&  VS-VA <= k */
+    if (!((((nr - s->va) & 0x7F) + ((s->vs - nr) & 0x7F)) <= s->tx_window_size_k
+         &&
+         ((s->vs - s->va) & 0x7F) <= s->tx_window_size_k))
+    {
+        lapm_disconnect(ss);
         return -1;
     }
-    /*endif*/
+    n = 0;
+    while (s->va != nr  &&  s->info_acked != s->info_get)
+    {
+        if (++s->info_acked >= V42_INFO_FRAMES)
+            s->info_acked = 0;
+        s->va = (s->va + 1) & 0x7F;
+        n++;
+    }
+    if (n > 0  &&  s->retry_count == 0)
+    {
+        t401_stop_t403_start(ss);
+        /* 8.4.8 */
+        if (((s->vs - s->va) & 0x7F))
+            t401_start(ss);
+    }
+    return n;
+}
+/*- End of function --------------------------------------------------------*/
 
-    lapm_init_header(f->frame, (s->peer_is_originator)  ?  cr  :  !cr);
-    f->next = NULL;
-    f->len = len + 4;
-    f->frame[1] = (uint8_t) (s->next_tx_frame << 1);
-    f->frame[2] = (uint8_t) (s->next_expected_frame << 1);
-    memcpy(f->frame + 3, buf, len);
-    s->next_tx_frame = (s->next_tx_frame + 1) & 0x7F;
-    s->last_frame_we_acknowledged = s->next_expected_frame;
-    /* Clear poll bit */
-    f->frame[2] &= ~0x01;
-    if (s->tx_last)
-        s->tx_last->next = f;
-    else
-        s->txqueue = f;
-    /*endif*/
-    s->tx_last = f;
-    /* Immediately transmit unless we're in a recovery state */
-    if (s->retransmissions == 0)
-        lapm_tx_frame(s, f->frame, f->len);
-    /*endif*/
-    if (s->t403_timer >= 0)
+static int valid_data_state(v42_state_t *ss)
+{
+    lapm_state_t *s;
+
+    s = &ss->lapm;
+    switch (s->state)
     {
-        span_log(&s->logging, SPAN_LOG_FLOW, "Stopping T_403 timer\n");
-fprintf(stderr, "Deleting T403 c %d\n", s->t403_timer);
-        span_schedule_del(&s->sched, s->t403_timer);
-        s->t403_timer = -1;
+    case LAPM_DETECT:
+    case LAPM_IDLE:
+        break;
+    case LAPM_ESTABLISH:
+        reset_lapm(ss);
+        s->state = LAPM_DATA;
+        report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED);
+        return 1;
+    case LAPM_DATA:
+        return 1;
+    case LAPM_RELEASE:
+        reset_lapm(ss);
+        s->state = LAPM_IDLE;
+        report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED);
+        break;
+    case LAPM_SIGNAL:
+    case LAPM_SETPARM:
+    case LAPM_TEST:
+    case LAPM_V42_UNSUPPORTED:
+        break;
     }
-    /*endif*/
-    if (s->t401_timer < 0)
-    {
-        span_log(&s->logging, SPAN_LOG_FLOW, "Starting timer T_401\n");
-        s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s);
-fprintf(stderr, "Setting T401 e %d [%p]\n", s->t401_timer, (void *) s);
-    }
-    else
-    {
-        span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_401 already running (%d)\n", s->t401_timer);
-    }
-    /*endif*/
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
 
-static void t403_expired(span_sched_state_t *ss, void *user_data)
+static void receive_information_frame(v42_state_t *ss, const uint8_t *frame, int len)
+{
+    lapm_state_t *s;
+    int ret;
+    int n;
+
+    s = &ss->lapm;
+    if (!valid_data_state(ss))
+        return;
+    if (len > s->rx_n401 + 3)
+        return;
+    ret = 0;
+    /* Ack I frames: NR - 1 */
+    n = ack_info(ss, frame[2] >> 1);
+    if (s->local_busy)
+    {
+        /* 8.4.7 */
+        if ((frame[2] & 0x1))
+            tx_supervisory_frame(s, s->rsp_addr, LAPM_S_RNR, 1);
+        return;
+    }
+    /* NS sequence error */
+    if ((frame[1] >> 1) != s->vr)
+    {
+        if (!s->rejected)
+        {
+            tx_supervisory_frame(s, s->rsp_addr, LAPM_S_REJ, (frame[2] & 0x1));
+            s->rejected = TRUE;
+        }
+        return;
+    }
+    s->rejected = FALSE;
+
+    s->iframe_put(s->iframe_put_user_data, frame + 3, len - 3);
+    /* Increment vr */
+    s->vr = (s->vr + 1) & 0x7F;
+    tx_information_rr_rnr_response(ss, frame, len);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void rx_supervisory_cmd_frame(v42_state_t *ss, const uint8_t *frame, int len)
+{
+    lapm_state_t *s;
+    int n;
+
+    s = &ss->lapm;
+    /* If l->local_busy each RR,RNR,REJ with p=1 should be replied by RNR with f=1 (8.4.7) */
+    switch (frame[1] & 0x0C)
+    {
+    case LAPM_S_RR:
+        s->far_busy = FALSE;
+        n = ack_info(ss, frame[2] >> 1);
+        /* If p = 1 may be used for status checking? */
+        tx_information_rr_rnr_response(ss, frame, len);
+        break;
+    case LAPM_S_RNR:
+        s->far_busy = TRUE;
+        n = ack_info(ss, frame[2] >> 1);
+        /* If p = 1 may be used for status checking? */
+        if ((frame[2] & 0x1))
+            tx_supervisory_frame(s, s->rsp_addr, (s->local_busy)  ?  LAPM_S_RNR  :  LAPM_S_RR, 1);
+        break;
+    case LAPM_S_REJ:
+        s->far_busy = FALSE;
+        n = ack_info(ss, frame[2] >> 1);
+        if (s->retry_count == 0)
+        {
+            t401_stop_t403_start(ss);
+            reject_info(s);
+        }
+        tx_information_rr_rnr_response(ss, frame, len);
+        break;
+    case LAPM_S_SREJ:
+        /* TODO: */
+        return;
+    default:
+        return;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void rx_supervisory_rsp_frame(v42_state_t *ss, const uint8_t *frame, int len)
+{
+    lapm_state_t *s;
+    int n;
+
+    s = &ss->lapm;
+    if (s->retry_count == 0  &&  (frame[2] & 0x1))
+        return;
+    /* Ack I frames <= NR - 1 */
+    switch (frame[1] & 0x0C)
+    {
+    case LAPM_S_RR:
+        s->far_busy = FALSE;
+        n = ack_info(ss, frame[2] >> 1);
+        if (s->retry_count  &&  (frame[2] & 0x1))
+        {
+            reject_info(s);
+            t401_stop_t403_start(ss);
+        }
+        break;
+    case LAPM_S_RNR:
+        s->far_busy = TRUE;
+        n = ack_info(ss, frame[2] >> 1);
+        if (s->retry_count  &&  (frame[2] & 0x1))
+        {
+            reject_info(s);
+            t401_stop_t403_start(ss);
+        }
+        if (s->retry_count == 0)
+            t401_start(ss);
+        break;
+    case LAPM_S_REJ:
+        s->far_busy = FALSE;
+        n = ack_info(ss, frame[2] >> 1);
+        if (s->retry_count == 0  ||  (frame[2] & 0x1))
+        {
+            reject_info(s);
+            t401_stop_t403_start(ss);
+        }
+        break;
+    case LAPM_S_SREJ:
+        /* TODO: */
+        return;
+    default:
+        return;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static int rx_unnumbered_cmd_frame(v42_state_t *ss, const uint8_t *frame, int len)
 {
     lapm_state_t *s;
 
-    s = (lapm_state_t *) user_data;
-    span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_403 expired. Sending RR and scheduling T_403 again\n");
-    s->t403_timer = -1;
-    s->retransmissions = 0;
-    /* Solicit an F-bit in the other end's RR */
-    s->solicit_f_bit = TRUE;
-    lapm_rr(s, 1);
-    /* Restart ourselves */
-fprintf(stderr, "Setting T403 f\n");
-    s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s);
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(void) lapm_dump(lapm_state_t *s, const uint8_t *frame, int len, int showraw, int txrx)
-{
-    const char *type;
-    char direction_tag[2];
-    
-    direction_tag[0] = txrx  ?  '>'  :  '<';
-    direction_tag[1] = '\0';
-    if (showraw)
-        span_log_buf(&s->logging, SPAN_LOG_FLOW, direction_tag, frame, len);
-    /*endif*/
-
-    switch ((frame[1] & LAPM_FRAMETYPE_MASK))
+    s = &ss->lapm;
+    switch (frame[1] & 0xEC)
     {
-    case LAPM_FRAMETYPE_I:
-    case LAPM_FRAMETYPE_I_ALT:
-        span_log(&s->logging, SPAN_LOG_FLOW, "%c Information frame:\n", direction_tag[0]);
+    case LAPM_U_SABME:
+        /* Discard un-acked I frames. Reset vs, vr, and va. Clear exceptions */
+        reset_lapm(ss);
+        /* Going to connected state */
+        s->state = LAPM_DATA;
+        /* Respond UA (or DM on error) */
+        // fixme: why may be error and LAPM_U_DM ??
+        tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_UA | (frame[1] & 0x10), NULL, 0);
+        t401_stop_t403_start(ss);
+        report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED);
         break;
-    case LAPM_FRAMETYPE_S:
-        span_log(&s->logging, SPAN_LOG_FLOW, "%c Supervisory frame:\n", direction_tag[0]);
+    case LAPM_U_UI:
+        /* Break signal */
+        /* TODO: */
         break;
-    case LAPM_FRAMETYPE_U:
-        span_log(&s->logging, SPAN_LOG_FLOW, "%c Unnumbered frame:\n", direction_tag[0]);
-        break;
-    }
-    /*endswitch*/
-    
-    span_log(&s->logging,
-             SPAN_LOG_FLOW,
-             "%c DLCI: %2d  C/R: %d  EA: %d\n",
-             direction_tag[0],
-             (frame[0] >> 2),
-             (frame[0] & 0x02)  ?  1  :  0,
-             (frame[0] & 0x01),
-             direction_tag[0]);
-    switch ((frame[1] & LAPM_FRAMETYPE_MASK))
-    {
-    case LAPM_FRAMETYPE_I:
-    case LAPM_FRAMETYPE_I_ALT:
-        /* Information frame */
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW, 
-                 "%c N(S): %03d\n",
-                 direction_tag[0],
-                 (frame[1] >> 1));
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW, 
-                 "%c N(R): %03d   P: %d\n",
-                 direction_tag[0],
-                 (frame[2] >> 1),
-                 (frame[2] & 0x01));
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW, 
-                 "%c %d bytes of data\n",
-                 direction_tag[0],
-                 len - 4);
-        break;
-    case LAPM_FRAMETYPE_S:
-        /* Supervisory frame */
-        switch (frame[1] & 0x0C)
+    case LAPM_U_DISC:
+        /* Respond UA (or DM) */
+        if (s->state == LAPM_IDLE)
         {
-        case 0x00:
-            type = "RR (receive ready)";
-            break;
-        case 0x04:
-            type = "RNR (receive not ready)";
-            break;
-        case 0x08:
-            type = "REJ (reject)";
-            break;
-        case 0x0C:
-            type = "SREJ (selective reject)";
-            break;
-        default:
-            type = "???";
-            break;
-        }
-        /*endswitch*/
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW,
-                 "%c S: %03d [ %s ]\n",
-                 direction_tag[0],
-                 frame[1],
-                 type);
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW,
-                 "%c N(R): %03d P/F: %d\n",
-                 direction_tag[0],
-                 frame[2] >> 1,
-                 frame[2] & 0x01);
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW,
-                 "%c %d bytes of data\n",
-                 direction_tag[0],
-                 len - 4);
-        break;
-    case LAPM_FRAMETYPE_U:
-        /* Unnumbered frame */
-        switch (frame[1] & 0xEC)
-        {
-        case 0x00:
-            type = "UI (unnumbered information)";
-            break;
-        case 0x0C:
-            type = "DM (disconnect mode)";
-            break;
-        case 0x40:
-            type = "DISC (disconnect)";
-            break;
-        case 0x60:
-            type = "UA (unnumbered acknowledgement)";
-            break;
-        case 0x6C:
-            type = "SABME (set asynchronous balanced mode extended)";
-            break;
-        case 0x84:
-            type = "FRMR (frame reject)";
-            break;
-        case 0xAC:
-            type = "XID (exchange identification)";
-            break;
-        case 0xE0:
-            type = "TEST (test)";
-            break;
-        default:
-            type = "???";
-            break;
-        }
-        /*endswitch*/
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW,
-                 "%c   M: %03d [ %s ] P/F: %d\n",
-                 direction_tag[0],
-                 frame[1],
-                 type,
-                 (frame[1] >> 4) & 1);
-        span_log(&s->logging,
-                 SPAN_LOG_FLOW,
-                 "%c %d bytes of data\n",
-                 direction_tag[0],
-                 len - 3);
-        break;
-    }
-    /*endswitch*/
-}
-/*- End of function --------------------------------------------------------*/
-
-static void lapm_link_up(lapm_state_t *s)
-{
-    uint8_t buf[1024];
-    int len;
-
-    lapm_reset(s);
-    /* Go into connection established state */
-    s->state = LAPM_DATA;
-    if (s->status_callback)
-        s->status_callback(s->status_callback_user_data, s->state);
-    /*endif*/
-    if (!queue_empty(s->tx_queue))
-    {
-        if ((len = queue_read(s->tx_queue, buf, s->n401)) > 0)
-            lapm_tx_iframe(s, buf, len, TRUE);
-        /*endif*/
-    }
-    /*endif*/
-    if (s->t401_timer >= 0)
-    {
-fprintf(stderr, "Deleting T401 x [%p] %d\n", (void *) s, s->t401_timer);
-        span_schedule_del(&s->sched, s->t401_timer);
-        s->t401_timer = -1;
-    }
-    /*endif*/
-    /* Start the T403 timer */
-fprintf(stderr, "Setting T403 g\n");
-    s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void lapm_link_down(lapm_state_t *s)
-{
-    lapm_reset(s);
-
-    if (s->status_callback)
-        s->status_callback(s->status_callback_user_data, s->state);
-    /*endif*/
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(void) lapm_reset(lapm_state_t *s)
-{
-    lapm_frame_queue_t *f;
-    lapm_frame_queue_t *p;
-
-    /* Having received a SABME, we need to reset our entire state */
-    s->next_tx_frame = 0;
-    s->last_frame_peer_acknowledged = 0;
-    s->next_expected_frame = 0;
-    s->last_frame_we_acknowledged = 0;
-    s->window_size_k = 15;
-    s->n401 = 128;
-    if (s->t401_timer >= 0)
-    {
-fprintf(stderr, "Deleting T401 d [%p] %d\n", (void *) s, s->t401_timer);
-        span_schedule_del(&s->sched, s->t401_timer);
-        s->t401_timer = -1;
-    }
-    /*endif*/
-    if (s->t403_timer >= 0)
-    {
-fprintf(stderr, "Deleting T403 e %d\n", s->t403_timer);
-        span_schedule_del(&s->sched, s->t403_timer);
-        s->t403_timer = -1;
-    }
-    /*endif*/
-    s->busy = FALSE;
-    s->solicit_f_bit = FALSE;
-    s->state = LAPM_RELEASE;
-    s->retransmissions = 0;
-    /* Discard anything waiting to go out */
-    for (f = s->txqueue;  f;  )
-    {
-        p = f;
-        f = f->next;
-        free(p);
-    }
-    /*endfor*/
-    s->txqueue = NULL;
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok)
-{
-    lapm_state_t *s;
-    lapm_frame_queue_t *f;
-    int sendnow;
-    int octet;
-    int s_field;
-    int m_field;
-
-fprintf(stderr, "LAPM receive %d %d\n", ok, len);
-    if (!ok  ||  len == 0)
-        return;
-    /*endif*/
-    s = (lapm_state_t *) user_data;
-    if (len < 0)
-    {
-        /* Special conditions */
-        span_log(&s->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(len), len);
-        return;
-    }
-    /*endif*/
-
-    if ((s->debug & LAPM_DEBUG_LAPM_DUMP))
-        lapm_dump(s, frame, len, s->debug & LAPM_DEBUG_LAPM_RAW, FALSE);
-    /*endif*/
-    octet = 0;
-    /* We do not expect extended addresses */
-    if ((frame[octet] & 0x01) == 0)
-        return;
-    /*endif*/
-    /* Check for DLCIs we do not recognise */
-    if ((frame[octet] >> 2) != LAPM_DLCI_DTE_TO_DTE)
-        return;
-    /*endif*/
-    octet++;
-    switch (frame[octet] & LAPM_FRAMETYPE_MASK)
-    {
-    case LAPM_FRAMETYPE_I:
-    case LAPM_FRAMETYPE_I_ALT:
-        if (s->state != LAPM_DATA)
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! Got an I-frame while link state is %d\n", s->state);
-            break;
-        }
-        /*endif*/
-        /* Information frame */
-        if (len < 4)
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! Received short I-frame (expected 4, got %d)\n", len);
-            break;
-        }
-        /*endif*/
-        /* Make sure this is a valid packet */
-        if ((frame[1] >> 1) == s->next_expected_frame)
-        {
-            /* Increment next expected I-frame */
-            s->next_expected_frame = (s->next_expected_frame + 1) & 0x7F;
-            /* Handle their ACK */
-            lapm_ack_rx(s, frame[2] >> 1);
-            if ((frame[2] & 0x01))
-            {
-                /* If the Poll/Final bit is set, send the RR immediately */
-                lapm_rr(s, 1);
-            }
-            /*endif*/
-            s->iframe_receive(s->iframe_receive_user_data, frame + 3, len - 4);
-            /* Send an RR if one wasn't sent already */
-            if (s->last_frame_we_acknowledged != s->next_expected_frame) 
-                lapm_rr(s, 0);
-            /*endif*/
+            tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_DM | LAPM_U_PF, NULL, 0);
         }
         else
         {
-            if (((s->next_expected_frame - (frame[1] >> 1)) & 127) < s->window_size_k)
-            {
-                /* It's within our window -- send back an RR */
-                lapm_rr(s, 0);
-            }
-            else
-            {
-                lapm_reject(s);
-            }
-            /*endif*/
+            /* Going to disconnected state, discard unacked I frames, reset all. */
+            s->state = LAPM_IDLE;
+            reset_lapm(ss);
+            tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_UA | (frame[1] & 0x10), NULL, 0);
+            t401_stop(ss);
+            /* TODO: notify CF */
+            report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED);
         }
-        /*endif*/
         break;
-    case LAPM_FRAMETYPE_S:
-        if (s->state != LAPM_DATA)
+    case LAPM_U_XID:
+        /* Exchange general ID info */
+        receive_xid(ss, frame, len);
+        transmit_xid(ss, s->rsp_addr);
+        break;
+    case LAPM_U_TEST:
+        /* TODO: */
+        break;
+    default:
+        return -1;
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int rx_unnumbered_rsp_frame(v42_state_t *ss, const uint8_t *frame, int len)
+{
+    lapm_state_t *s;
+
+    s = &ss->lapm;
+    switch (frame[1] & 0xEC)
+    {
+    case LAPM_U_DM:
+        switch (s->state)
         {
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! Got S-frame while link down\n");
-            break;
-        }
-        /*endif*/
-        if (len < 4)
-        {
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! Received short S-frame (expected 4, got %d)\n", len);
-            break;
-        }
-        /*endif*/
-        s_field = frame[octet] & 0xEC;
-        switch (s_field)
-        {
-        case 0x00:
-            /* RR (receive ready) */
-            s->busy = FALSE;
-            /* Acknowledge frames as necessary */
-            lapm_ack_rx(s, frame[2] >> 1);
-            if ((frame[2] & 0x01))
+        case LAPM_IDLE:
+            if (!(frame[1] & 0x10))
             {
-                /* If P/F is one, respond with an RR with the P/F bit set */
-                if (s->solicit_f_bit)
-                {
-                    span_log(&s->logging, SPAN_LOG_FLOW, "-- Got RR response to our frame\n");
-                }
-                else
-                {
-                    span_log(&s->logging, SPAN_LOG_FLOW, "-- Unsolicited RR with P/F bit, responding\n");
-                    lapm_rr(s, 1);
-                }
-                /*endif*/
-                s->solicit_f_bit = FALSE;
+                /* TODO: notify CF */
+                report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED);
             }
-            /*endif*/
             break;
-        case 0x04:
-            /* RNR (receive not ready) */
-            span_log(&s->logging, SPAN_LOG_FLOW, "-- Got receiver not ready\n");
-            s->busy = TRUE;
-            break;   
-        case 0x08:
-            /* REJ (reject) */
-            /* Just retransmit */
-            span_log(&s->logging, SPAN_LOG_FLOW, "-- Got reject requesting packet %d...  Retransmitting.\n", frame[2] >> 1);
-            if ((frame[2] & 0x01))
+        case LAPM_ESTABLISH:
+        case LAPM_RELEASE:
+            if ((frame[1] & 0x10))
             {
-                /* If it has the poll bit set, send an appropriate supervisory response */
-                lapm_rr(s, 1);
+                s->state = LAPM_IDLE;
+                reset_lapm(ss);
+                t401_stop(ss);
+                /* TODO: notify CF */
+                report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED);
             }
-            /*endif*/
-            sendnow = FALSE;
-            /* Resend the appropriate I-frame */
-            for (f = s->txqueue;  f;  f = f->next)
-            {
-                if (sendnow  ||  (f->frame[1] >> 1) == (frame[2] >> 1))
-                {
-                    /* Matches the request, or follows in our window */
-                    sendnow = TRUE;
-                    span_log(&s->logging,
-                             SPAN_LOG_FLOW,
-                             "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n",
-                             frame[2] >> 1,
-                             f->frame[1] >> 1);
-                    f->frame[2] = (uint8_t) (s->next_expected_frame << 1);
-                    lapm_tx_frame(s, f->frame, f->len);
-                }
-                /*endif*/
-            }
-            /*endfor*/
-            if (!sendnow)
-            {
-                if (s->txqueue)
-                {
-                    /* This should never happen */
-                    if ((frame[2] & 0x01) == 0  ||  (frame[2] >> 1))
-                    {
-                        span_log(&s->logging,
-                                 SPAN_LOG_FLOW,
-                                 "!! Got reject for frame %d, but we only have others!\n",
-                                 frame[2] >> 1);
-                    }
-                    /*endif*/
-                }
-                else
-                {
-                    /* Hrm, we have nothing to send, but have been REJ'd.  Reset last_frame_peer_acknowledged, next_tx_frame, etc */
-                    span_log(&s->logging, SPAN_LOG_FLOW, "!! Got reject for frame %d, but we have nothing -- resetting!\n", frame[2] >> 1);
-                    s->last_frame_peer_acknowledged =
-                    s->next_tx_frame = frame[2] >> 1;
-                    /* Reset t401 timer if it was somehow going */
-                    if (s->t401_timer >= 0)
-                    {
-fprintf(stderr, "Deleting T401 f [%p] %d\n", (void *) s, s->t401_timer);
-                        span_schedule_del(&s->sched, s->t401_timer);
-                        s->t401_timer = -1;
-                    }
-                    /*endif*/
-                    /* Reset and restart t403 timer */
-                    if (s->t403_timer >= 0)
-                    {
-fprintf(stderr, "Deleting T403 g %d\n", s->t403_timer);
-                        span_schedule_del(&s->sched, s->t403_timer);
-                        s->t403_timer = -1;
-                    }
-                    /*endif*/
-fprintf(stderr, "Setting T403 h\n");
-                    s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s);
-                }
-                /*endif*/
-            }
-            /*endif*/
             break;
-        case 0x0C:
-            /* SREJ (selective reject) */
+        case LAPM_DATA:
+            if (s->retry_count  ||  !(frame[1] & 0x10))
+            {
+                s->state = LAPM_IDLE;
+                reset_lapm(ss);
+                /* TODO: notify CF */
+                report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED);
+            }
             break;
         default:
-            span_log(&s->logging,
-                     SPAN_LOG_FLOW,
-                     "!! XXX Unknown Supervisory frame sd=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n",
-                     s_field,
-                     frame[2] & 0x01,
-                     frame[2] >> 1,
-                     s->next_tx_frame,
-                     s->last_frame_peer_acknowledged);
             break;
         }
-        /*endswitch*/
         break;
-    case LAPM_FRAMETYPE_U:
-        if (len < 3)
+    case LAPM_U_UI:
+        /* TODO: */
+        break;
+    case LAPM_U_UA:
+        switch (s->state)
         {
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! Received too short unnumbered frame\n");
+        case LAPM_ESTABLISH:
+            s->state = LAPM_DATA;
+            reset_lapm(ss);
+            t401_stop_t403_start(ss);
+            report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED);
             break;
-        }
-        /*endif*/
-        m_field = frame[octet] & 0xEC;
-        switch (m_field)
-        {
-        case 0x00:
-            /* UI (unnumbered information) */
-            switch (frame[++octet] & 0x7F)
-            {
-            case 0x40:
-                /* BRK */
-                span_log(&s->logging, SPAN_LOG_FLOW, "BRK - option %d, length %d\n", (frame[octet] >> 5), frame[octet + 1]);
-                octet += 2;
-                break;
-            case 0x60:
-                /* BRKACK */
-                span_log(&s->logging, SPAN_LOG_FLOW, "BRKACK\n");
-                break;
-            default:
-                /* Unknown */
-                span_log(&s->logging, SPAN_LOG_FLOW, "Unknown UI type\n");
-                break;
-            }
-            /*endswitch*/
-            break;
-        case 0x0C:
-            /* DM (disconnect mode) */
-            if ((frame[octet] & 0x10))
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "-- Got Unconnected Mode from peer.\n");
-                /* Disconnected mode, try again */
-                lapm_link_down(s);
-                lapm_restart(s);
-            }
-            else
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "-- DM (disconnect mode) requesting SABME, starting.\n");
-                /* Requesting that we start */
-                lapm_restart(s);
-            }
-            /*endif*/
-            break;
-        case 0x40:
-            /* DISC (disconnect) */
-            span_log(&s->logging, SPAN_LOG_FLOW, "-- Got DISC (disconnect) from peer.\n");
-            /* Acknowledge */
-            lapm_send_ua(s, (frame[octet] & 0x10));
-            lapm_link_down(s);
-            break;
-        case 0x60:
-            /* UA (unnumbered acknowledgement) */
-            if (s->state == LAPM_ESTABLISH)
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "-- Got UA (unnumbered acknowledgement) from %s peer. Link up.\n", (frame[0] & 0x02)  ?  "xxx"  :  "yyy");
-                lapm_link_up(s);
-            }
-            else
-            {
-                span_log(&s->logging, SPAN_LOG_FLOW, "!! Got a UA (unnumbered acknowledgement) in state %d\n", s->state);
-            }
-            /*endif*/
-            break;
-        case 0x6C:
-            /* SABME (set asynchronous balanced mode extended) */
-            span_log(&s->logging, SPAN_LOG_FLOW, "-- Got SABME (set asynchronous balanced mode extended) from %s peer.\n", (frame[0] & 0x02)  ?  "yyy"  :  "xxx");
-            if ((frame[0] & 0x02))
-            {
-                s->peer_is_originator = TRUE;
-                if (s->we_are_originator)
-                {
-                    /* We can't both be originators */
-                    span_log(&s->logging, SPAN_LOG_FLOW, "We think we are the originator, but they think so too.");
-                    break;
-                }
-                /*endif*/
-            }
-            else
-            {
-                s->peer_is_originator = FALSE;
-                if (!s->we_are_originator)
-                {
-                    /* We can't both be answerers */
-                    span_log(&s->logging, SPAN_LOG_FLOW, "We think we are the answerer, but they think so too.\n");
-                    break;
-                }
-                /*endif*/
-            }
-            /*endif*/
-            /* Send unnumbered acknowledgement */
-            lapm_send_ua(s, (frame[octet] & 0x10));
-            lapm_link_up(s);
-            break;
-        case 0x84:
-            /* FRMR (frame reject) */
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! FRMR (frame reject).\n");
-            break;
-        case 0xAC:
-            /* XID (exchange identification) */
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! XID (exchange identification) frames not supported\n");
-            break;
-        case 0xE0:
-            /* TEST (test) */
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! TEST (test) frames not supported\n");
+        case LAPM_RELEASE:
+            s->state = LAPM_IDLE;
+            reset_lapm(ss);
+            t401_stop(ss);
+            report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED);
             break;
         default:
-            span_log(&s->logging, SPAN_LOG_FLOW, "!! Don't know what to do with M=%X u-frames\n", m_field);
+            /* Unsolicited UA */
+            /* TODO: */
             break;
         }
-        /*endswitch*/
+        /* Clear all exceptions, busy states (self and peer) */
+        /* Reset vars */
+        break;
+    case LAPM_U_FRMR:
+        /* Non-recoverable error */
+        /* TODO: */
+        break;
+    case LAPM_U_XID:
+        if (s->configuring)
+        {
+            receive_xid(ss, frame, len);
+            s->configuring = FALSE;
+            t401_stop(ss);
+            switch (s->state)
+            {
+            case LAPM_IDLE:
+                lapm_connect(ss);
+                break;
+            case LAPM_DATA:
+                s->local_busy = FALSE;
+                tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RR, 0);
+                break;
+            }
+        }
+        break;
+    default:
         break;
     }
-    /*endswitch*/
+    return 0;
 }
 /*- End of function --------------------------------------------------------*/
 
 static void lapm_hdlc_underflow(void *user_data)
 {
     lapm_state_t *s;
-    uint8_t buf[1024];
-    int len;
+    v42_state_t *ss;
+    v42_frame_t *f;
 
-    s = (lapm_state_t *) user_data;
-    span_log(&s->logging, SPAN_LOG_FLOW, "HDLC underflow\n");
-    if (s->state == LAPM_DATA)
+    ss = (v42_state_t *) user_data;
+    s = &ss->lapm;
+    if (s->ctrl_get != s->ctrl_put)
     {
-        if (!queue_empty(s->tx_queue))
-        {
-            if ((len = queue_read(s->tx_queue, buf, s->n401)) > 0)
-                lapm_tx_iframe(s, buf, len, TRUE);
-            /*endif*/
-        }
-        /*endif*/
+        /* Send control frame */
+        f = &s->ctrl_buf[s->ctrl_get];
+        if (++s->ctrl_get >= V42_CTRL_FRAMES)
+            s->ctrl_get = 0;
     }
-    /*endif*/
+    else
+    {
+        if (s->far_busy  ||  s->configuring  ||  s->state != LAPM_DATA)
+        {
+            hdlc_tx_flags(&s->hdlc_tx, 10);
+            return;
+        }
+        if (s->info_get == s->info_put  &&  !tx_information_frame(ss))
+        {
+            hdlc_tx_flags(&s->hdlc_tx, 10);
+            return;
+        }
+        /* Send info frame */
+        f = &s->info_buf[s->info_get];
+        if (++s->info_get >= V42_INFO_FRAMES)
+            s->info_get = 0;
+
+        f->buf[0] = s->cmd_addr;
+        f->buf[1] = s->vs << 1;
+        f->buf[2] = s->vr << 1;
+        s->vs = (s->vs + 1) & 0x7F;
+        if (ss->bit_timer == 0)
+            t401_start(ss);
+    }
+    hdlc_tx_frame(&s->hdlc_tx, f->buf, f->len);
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) lapm_restart(lapm_state_t *s)
+SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok)
 {
-#if 0
-    if (s->state != LAPM_RELEASE)
+    lapm_state_t *s;
+    v42_state_t *ss;
+
+    ss = (v42_state_t *) user_data;
+    s = &ss->lapm;
+    if (len < 0)
     {
-        span_log(&s->logging, SPAN_LOG_FLOW, "!! lapm_restart: Not in 'Link Connection Released' state\n");
+        span_log(&ss->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(len), len);
         return;
     }
-    /*endif*/
-#endif
-    span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
-    span_log_set_protocol(&s->logging, "LAP.M");
-    hdlc_tx_init(&s->hdlc_tx, FALSE, 1, TRUE, lapm_hdlc_underflow, s);
-    hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, 1, lapm_receive, s);
-    /* TODO: This is a bodge! */
-    s->t401_timer = -1;
-    s->t402_timer = -1;
-    s->t403_timer = -1;
-    lapm_reset(s);
-    /* TODO: Maybe we should implement T_WAIT? */
-    lapm_send_sabme(NULL, s);
+    if (!ok)
+        return;
+
+    switch ((frame[1] & LAPM_FRAMETYPE_MASK))
+    {
+    case LAPM_FRAMETYPE_I:
+    case LAPM_FRAMETYPE_I_ALT:
+        receive_information_frame(ss, frame, len);
+        break;
+    case LAPM_FRAMETYPE_S:
+        if (!valid_data_state(ss))
+            return;
+        if (frame[0] == s->rsp_addr)
+            rx_supervisory_cmd_frame(ss, frame, len);
+        else
+            rx_supervisory_rsp_frame(ss, frame, len);
+        break;
+    case LAPM_FRAMETYPE_U:
+        if (frame[0] == s->rsp_addr)
+            rx_unnumbered_cmd_frame(ss, frame, len);
+        else
+            rx_unnumbered_rsp_frame(ss, frame, len);
+        break;
+    default:
+        break;
+    }
 }
 /*- End of function --------------------------------------------------------*/
 
-#if 0
-static void lapm_init(lapm_state_t *s)
+static int lapm_connect(v42_state_t *ss)
 {
-    lapm_restart(s);
+    lapm_state_t *s;
+
+    s = &ss->lapm;
+    if (s->state != LAPM_IDLE)
+        return -1;
+
+    /* Negotiate params */
+    //transmit_xid(s, s->cmd_addr);
+
+    reset_lapm(ss);
+    /* Connect */
+    s->state = LAPM_ESTABLISH;
+    tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_SABME | LAPM_U_PF, NULL, 0);
+    /* Start T401 (and not T403) */
+    t401_start(ss);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int lapm_disconnect(v42_state_t *ss)
+{
+    lapm_state_t *s;
+
+    s = &ss->lapm;
+    s->state = LAPM_RELEASE;
+    tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_DISC | LAPM_U_PF, NULL, 0);
+    t401_start(ss);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int lapm_config(v42_state_t *ss)
+{
+    lapm_state_t *s;
+
+    s = &ss->lapm;
+    s->configuring = TRUE;
+    if (s->state == LAPM_DATA)
+    {
+        s->local_busy = TRUE;
+        tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RNR, 1);
+    }
+    transmit_xid(ss, s->cmd_addr);
+    t401_start(ss);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void reset_lapm(v42_state_t *ss)
+{
+    lapm_state_t *s;
+    
+    s = &ss->lapm;
+    /* Reset the LAP.M state */
+    s->local_busy = FALSE;
+    s->far_busy = FALSE;
+    s->vs = 0;
+    s->va = 0;
+    s->vr = 0;
+    /* Discard any info frames still queued for transmission */
+    s->info_put = 0;
+    s->info_acked = 0;
+    s->info_get = 0;
+    /* Discard any control frames */
+    s->ctrl_put = 0;
+    s->ctrl_get = 0;
+
+    s->tx_window_size_k = ss->config.v42_tx_window_size_k;
+    s->rx_window_size_k = ss->config.v42_rx_window_size_k;
+    s->tx_n401 = ss->config.v42_tx_n401;
+    s->rx_n401 = ss->config.v42_rx_n401;
+}
+/*- End of function --------------------------------------------------------*/
+
+void v42_stop(v42_state_t *ss)
+{
+    lapm_state_t *s;
+
+    s = &ss->lapm;
+    ss->bit_timer = 0;
+    s->packer_process = NULL;
+    lapm_disconnect(ss);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void restart_lapm(v42_state_t *s)
+{
+    if (s->calling_party)
+    {
+        s->bit_timer = 48*8;
+        s->bit_timer_func = initiate_negotiation_expired;
+    }
+    else
+    {
+        lapm_hdlc_underflow(s);
+    }
+    s->lapm.packer_process = NULL;
+    s->lapm.state = LAPM_IDLE;
 }
 /*- End of function --------------------------------------------------------*/
-#endif
 
 static void negotiation_rx_bit(v42_state_t *s, int new_bit)
 {
     /* DC1 with even parity, 8-16 ones, DC1 with odd parity, 8-16 ones */
-    //uint8_t odp = "0100010001 11111111 0100010011 11111111";
+    /* uint8_t odp = "0100010001 11111111 0100010011 11111111"; */
     /* V.42 OK E , 8-16 ones, C, 8-16 ones */
-    //uint8_t adp_v42 = "0101000101  11111111  0110000101  11111111";
+    /* uint8_t adp_v42 = "0101000101  11111111  0110000101  11111111"; */
     /* V.42 disabled E, 8-16 ones, NULL, 8-16 ones */
-    //uint8_t adp_nov42 = "0101000101  11111111  0000000001  11111111";
+    /* uint8_t adp_nov42 = "0101000101  11111111  0000000001  11111111"; */
 
     /* There may be no negotiation, so we need to process this data through the
        HDLC receiver as well */
@@ -1117,124 +1229,117 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit)
     }
     /*endif*/
     new_bit &= 1;
-    s->rxstream = (s->rxstream << 1) | new_bit;
-    switch (s->rx_negotiation_step)
+    s->neg.rxstream = (s->neg.rxstream << 1) | new_bit;
+    switch (s->neg.rx_negotiation_step)
     {
     case 0:
         /* Look for some ones */
         if (new_bit)
             break;
         /*endif*/
-        s->rx_negotiation_step = 1;
-        s->rxbits = 0;
-        s->rxstream = ~1;
-        s->rxoks = 0;
+        s->neg.rx_negotiation_step = 1;
+        s->neg.rxbits = 0;
+        s->neg.rxstream = ~1;
+        s->neg.rxoks = 0;
         break;
     case 1:
         /* Look for the first character */
-        if (++s->rxbits < 9)
+        if (++s->neg.rxbits < 9)
             break;
         /*endif*/
-        s->rxstream &= 0x3FF;
-        if (s->calling_party  &&  s->rxstream == 0x145)
+        s->neg.rxstream &= 0x3FF;
+        if (s->calling_party  &&  s->neg.rxstream == 0x145)
         {
-            s->rx_negotiation_step++;
+            s->neg.rx_negotiation_step++;
         }
-        else if (!s->calling_party  &&  s->rxstream == 0x111)
+        else if (!s->calling_party  &&  s->neg.rxstream == 0x111)
         {
-            s->rx_negotiation_step++;
+            s->neg.rx_negotiation_step++;
         }
         else
         {
-            s->rx_negotiation_step = 0;
+            s->neg.rx_negotiation_step = 0;
         }
         /*endif*/
-        s->rxbits = 0;
-        s->rxstream = ~0;
+        s->neg.rxbits = 0;
+        s->neg.rxstream = ~0;
         break;
     case 2:
         /* Look for 8 to 16 ones */
-        s->rxbits++;
+        s->neg.rxbits++;
         if (new_bit)
             break;
         /*endif*/
-        if (s->rxbits >= 8  &&  s->rxbits <= 16)
-            s->rx_negotiation_step++;
+        if (s->neg.rxbits >= 8  &&  s->neg.rxbits <= 16)
+            s->neg.rx_negotiation_step++;
         else
-            s->rx_negotiation_step = 0;
+            s->neg.rx_negotiation_step = 0;
         /*endif*/
-        s->rxbits = 0;
-        s->rxstream = ~1;
+        s->neg.rxbits = 0;
+        s->neg.rxstream = ~1;
         break;
     case 3:
         /* Look for the second character */
-        if (++s->rxbits < 9)
+        if (++s->neg.rxbits < 9)
             break;
         /*endif*/
-        s->rxstream &= 0x3FF;
-        if (s->calling_party  &&  s->rxstream == 0x185)
+        s->neg.rxstream &= 0x3FF;
+        if (s->calling_party  &&  s->neg.rxstream == 0x185)
         {
-            s->rx_negotiation_step++;
+            s->neg.rx_negotiation_step++;
         }
-        else if (s->calling_party  &&  s->rxstream == 0x001)
+        else if (s->calling_party  &&  s->neg.rxstream == 0x001)
         {
-            s->rx_negotiation_step++;
+            s->neg.rx_negotiation_step++;
         }
-        else if (!s->calling_party  &&  s->rxstream == 0x113)
+        else if (!s->calling_party  &&  s->neg.rxstream == 0x113)
         {
-            s->rx_negotiation_step++;
+            s->neg.rx_negotiation_step++;
         }
         else
         {
-            s->rx_negotiation_step = 0;
+            s->neg.rx_negotiation_step = 0;
         }
         /*endif*/
-        s->rxbits = 0;
-        s->rxstream = ~0;
+        s->neg.rxbits = 0;
+        s->neg.rxstream = ~0;
         break;
     case 4:
         /* Look for 8 to 16 ones */
-        s->rxbits++;
+        s->neg.rxbits++;
         if (new_bit)
             break;
         /*endif*/
-        if (s->rxbits >= 8  &&  s->rxbits <= 16)
+        if (s->neg.rxbits >= 8  &&  s->neg.rxbits <= 16)
         {
-            if (++s->rxoks >= 2)
+            if (++s->neg.rxoks >= 2)
             {
-                /* HIT */
-                s->rx_negotiation_step++;
+                /* HIT - we have found the "V.42 supported" pattern. */
+                s->neg.rx_negotiation_step++;
                 if (s->calling_party)
                 {
-                    if (s->t400_timer >= 0)
-                    {
-fprintf(stderr, "Deleting T400 h %d\n", s->t400_timer);
-                        span_schedule_del(&s->lapm.sched, s->t400_timer);
-                        s->t400_timer = -1;
-                    }
-                    /*endif*/
-                    s->lapm.state = LAPM_ESTABLISH;
-                    if (s->lapm.status_callback)
-                        s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state);
-                    /*endif*/
+                    t400_stop(s);
+                    s->lapm.state = LAPM_IDLE;
+                    report_rx_status_change(s, s->lapm.state);
+                    restart_lapm(s);
                 }
                 else
                 {
-                    s->odp_seen = TRUE;
+                    s->neg.odp_seen = TRUE;
                 }
                 /*endif*/
                 break;
             }
             /*endif*/
-            s->rx_negotiation_step = 1;
-            s->rxbits = 0;
-            s->rxstream = ~1;
+            s->neg.rx_negotiation_step = 1;
+            s->neg.rxbits = 0;
+            s->neg.rxstream = ~1;
         }
         else
         {
-            s->rx_negotiation_step = 0;
-            s->rxbits = 0;
-            s->rxstream = ~0;
+            s->neg.rx_negotiation_step = 0;
+            s->neg.rxbits = 0;
+            s->neg.rxstream = ~0;
         }
         /*endif*/
         break;
@@ -1252,56 +1357,49 @@ static int v42_support_negotiation_tx_bit(v42_state_t *s)
 
     if (s->calling_party)
     {
-        if (s->txbits <= 0)
+        if (s->neg.txbits <= 0)
         {
-            s->txstream = 0x3FE22;
-            s->txbits = 36;
+            s->neg.txstream = 0x3FE22;
+            s->neg.txbits = 36;
         }
-        else if (s->txbits == 18)
+        else if (s->neg.txbits == 18)
         {
-            s->txstream = 0x3FF22;
+            s->neg.txstream = 0x3FF22;
         }
         /*endif*/
-        bit = s->txstream & 1;
-        s->txstream >>= 1;
-        s->txbits--;
+        bit = s->neg.txstream & 1;
+        s->neg.txstream >>= 1;
+        s->neg.txbits--;
     }
     else
     {
-        if (s->odp_seen  &&  s->txadps < 10)
+        if (s->neg.odp_seen  &&  s->neg.txadps < 10)
         {
-            if (s->txbits <= 0)
+            if (s->neg.txbits <= 0)
             {
-                if (++s->txadps >= 10)
+                if (++s->neg.txadps >= 10)
                 {
-                    if (s->t400_timer >= 0)
-                    {
-fprintf(stderr, "Deleting T400 i %d\n", s->t400_timer);
-                        span_schedule_del(&s->lapm.sched, s->t400_timer);
-                        s->t400_timer = -1;
-                    }
-                    /*endif*/
-                    s->lapm.state = LAPM_ESTABLISH;
-                    if (s->lapm.status_callback)
-                        s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state);
-                    /*endif*/
-                    s->txstream = 1;
+                    t400_stop(s);
+                    s->lapm.state = LAPM_IDLE;
+                    report_rx_status_change(s, s->lapm.state);
+                    s->neg.txstream = 1;
+                    restart_lapm(s);
                 }
                 else
                 {
-                    s->txstream = 0x3FE8A;
-                    s->txbits = 36;
+                    s->neg.txstream = 0x3FE8A;
+                    s->neg.txbits = 36;
                 }
                 /*endif*/
             }
-            else if (s->txbits == 18)
+            else if (s->neg.txbits == 18)
             {
-                s->txstream = 0x3FE86;
+                s->neg.txstream = 0x3FE86;
             }
             /*endif*/
-            bit = s->txstream & 1;
-            s->txstream >>= 1;
-            s->txbits--;
+            bit = s->neg.txstream & 1;
+            s->neg.txstream >>= 1;
+            s->neg.txbits--;
         }
         else
         {
@@ -1333,6 +1431,11 @@ SPAN_DECLARE(int) v42_tx_bit(void *user_data)
     int bit;
 
     s = (v42_state_t *) user_data;
+    if (s->bit_timer  &&  (--s->bit_timer) <= 0)
+    {
+        s->bit_timer = 0;
+        s->bit_timer_func(s);
+    }
     if (s->lapm.state == LAPM_DETECT)
         bit = v42_support_negotiation_tx_bit(s);
     else
@@ -1342,89 +1445,124 @@ SPAN_DECLARE(int) v42_tx_bit(void *user_data)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, v42_status_func_t callback, void *user_data)
+SPAN_DECLARE(int) v42_set_local_busy_status(v42_state_t *s, int busy)
 {
-    s->lapm.status_callback = callback;
-    s->lapm.status_callback_user_data = user_data;
+    int previous_busy;
+
+    previous_busy = s->lapm.local_busy;
+    s->lapm.local_busy = busy;
+    return previous_busy;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(int) v42_get_far_busy_status(v42_state_t *s)
+{
+    return s->lapm.far_busy;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, modem_status_func_t status_handler, void *user_data)
+{
+    s->lapm.status_handler = status_handler;
+    s->lapm.status_user_data = user_data;
 }
 /*- End of function --------------------------------------------------------*/
 
 SPAN_DECLARE(void) v42_restart(v42_state_t *s)
 {
-    span_schedule_init(&s->lapm.sched);
+    hdlc_tx_init(&s->lapm.hdlc_tx, FALSE, 1, TRUE, lapm_hdlc_underflow, s);
+    hdlc_rx_init(&s->lapm.hdlc_rx, FALSE, FALSE, 1, lapm_receive, s);
 
-    s->lapm.we_are_originator = s->calling_party;
-    lapm_restart(&s->lapm);
     if (s->detect)
     {
-        s->txstream = ~0;
-        s->txbits = 0;
-        s->rxstream = ~0;
-        s->rxbits = 0;
-        s->rxoks = 0;
-        s->txadps = 0;
-        s->rx_negotiation_step = 0;
-        s->odp_seen = FALSE;
-fprintf(stderr, "Setting T400 i\n");
-        s->t400_timer = span_schedule_event(&s->lapm.sched, T_400, t400_expired, s);
+        /* We need to do the V.42 support detection sequence */
+        s->neg.txstream = ~0;
+        s->neg.txbits = 0;
+        s->neg.rxstream = ~0;
+        s->neg.rxbits = 0;
+        s->neg.rxoks = 0;
+        s->neg.txadps = 0;
+        s->neg.rx_negotiation_step = 0;
+        s->neg.odp_seen = FALSE;
+        t400_start(s);
         s->lapm.state = LAPM_DETECT;
     }
     else
     {
-        s->lapm.state = LAPM_ESTABLISH;
+        /* Go directly to LAP.M mode */
+        s->lapm.state = LAPM_IDLE;
+        restart_lapm(s);
     }
     /*endif*/
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data)
+SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *ss,
+                                     int calling_party,
+                                     int detect,
+                                     get_msg_func_t iframe_get,
+                                     put_msg_func_t iframe_put,
+                                     void *user_data)
 {
-    int alloced;
-    
-    if (frame_handler == NULL)
-        return NULL;
-    /*endif*/
-    alloced = FALSE;
-    if (s == NULL)
+    lapm_state_t *s;
+
+    if (ss == NULL)
     {
-        if ((s = (v42_state_t *) malloc(sizeof(*s))) == NULL)
+        if ((ss = (v42_state_t *) malloc(sizeof(*ss))) == NULL)
             return NULL;
-        alloced = TRUE;
     }
-    memset(s, 0, sizeof(*s));
-    s->calling_party = calling_party;
-    s->detect = detect;
-    s->lapm.iframe_receive = frame_handler;
-    s->lapm.iframe_receive_user_data = user_data;
-    s->lapm.debug |= (LAPM_DEBUG_LAPM_RAW | LAPM_DEBUG_LAPM_DUMP | LAPM_DEBUG_LAPM_STATE);
-    s->lapm.t401_timer =
-    s->lapm.t402_timer =
-    s->lapm.t403_timer = -1;
+    memset(ss, 0, sizeof(*ss));
 
-    if ((s->lapm.tx_queue = queue_init(NULL, 16384, 0)) == NULL)
-    {
-        if (alloced)
-            free(s);
-        return NULL;
-    }
-    /*endif*/
-    span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
-    span_log_set_protocol(&s->logging, "V.42");
-    v42_restart(s);
-    return s;
+    s = &ss->lapm;
+    ss->calling_party = calling_party;
+    ss->detect = detect;
+    s->iframe_get = iframe_get;
+    s->iframe_get_user_data = user_data;
+    s->iframe_put = iframe_put;
+    s->iframe_put_user_data = user_data;
+
+    s->state = (ss->detect)  ?  LAPM_DETECT  :  LAPM_IDLE;
+    s->local_busy = FALSE;
+    s->far_busy = FALSE;
+
+    /* The address octet is:
+        Data link connection identifier (0)
+        Command/response (0 if answerer, 1 if originator)
+        Extended address (1) */
+    s->cmd_addr = (LAPM_DLCI_DTE_TO_DTE << 2) | ((ss->calling_party)  ?  0x02  :  0x00) | 0x01;
+    s->rsp_addr = (LAPM_DLCI_DTE_TO_DTE << 2) | ((ss->calling_party)  ?  0x00  :  0x02) | 0x01;
+
+    /* Set default values for the LAP.M parameters. These can be modified later. */
+    ss->config.v42_tx_window_size_k = V42_DEFAULT_WINDOW_SIZE_K;
+    ss->config.v42_rx_window_size_k = V42_DEFAULT_WINDOW_SIZE_K;
+    ss->config.v42_tx_n401 = V42_DEFAULT_N_401;
+    ss->config.v42_rx_n401 = V42_DEFAULT_N_401;
+
+    /* TODO: This should be part of the V.42bis startup */
+    ss->config.comp = 1;
+    ss->config.comp_dict_size = 512;
+    ss->config.comp_max_string = 6;
+
+    ss->tx_bit_rate = 28800;
+
+    reset_lapm(ss);
+
+    span_log_init(&ss->logging, SPAN_LOG_NONE, NULL);
+    span_log_set_protocol(&ss->logging, "V.42");
+    return ss;
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(int) v42_release(v42_state_t *s)
+SPAN_DECLARE(void) v42_release(v42_state_t *s)
 {
-    return 0;
+    reset_lapm(s);
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(int) v42_free(v42_state_t *s)
+SPAN_DECLARE(void) v42_free(v42_state_t *s)
 {
+    v42_release(s);
     free(s);
-    return 0;
 }
 /*- End of function --------------------------------------------------------*/
 /*- End of file ------------------------------------------------------------*/
diff --git a/libs/spandsp/src/v42bis.c b/libs/spandsp/src/v42bis.c
index f4aee8ce93..d025ea9f7d 100644
--- a/libs/spandsp/src/v42bis.c
+++ b/libs/spandsp/src/v42bis.c
@@ -5,7 +5,7 @@
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
- * Copyright (C) 2005 Steve Underwood
+ * Copyright (C) 2005, 2011 Steve Underwood
  *
  * All rights reserved.
  *
@@ -45,19 +45,28 @@
 #include "spandsp/telephony.h"
 #include "spandsp/logging.h"
 #include "spandsp/bit_operations.h"
+#include "spandsp/async.h"
 #include "spandsp/v42bis.h"
 
 #include "spandsp/private/logging.h"
 #include "spandsp/private/v42bis.h"
 
 /* Fixed parameters from the spec. */
-#define V42BIS_N3               8   /* Character size (bits) */
-#define V42BIS_N4               256 /* Number of characters in the alphabet */
-#define V42BIS_N5               (V42BIS_N4 + V42BIS_N6)  /* Index number of first dictionary entry used to store a string */
-#define V42BIS_N6               3   /* Number of control codewords */
-
+/* Character size (bits) */
+#define V42BIS_N3                           8
+/* Number of characters in the alphabet */
+#define V42BIS_N4                           256
+/* Index number of first dictionary entry used to store a string */
+#define V42BIS_N5                           (V42BIS_N4 + V42BIS_N6)
+/* Number of control codewords */
+#define V42BIS_N6                           3 
 /* V.42bis/9.2 */
-#define V42BIS_ESC_STEP         51
+#define V42BIS_ESC_STEP                     51
+
+/* Compreeibility monitoring parameters for assessing automated switches between
+   transparent and compressed mode */
+#define COMPRESSIBILITY_MONITOR             (256*V42BIS_N3)
+#define COMPRESSIBILITY_MONITOR_HYSTERESIS  11
 
 /* Control code words in compressed mode */
 enum
@@ -75,558 +84,627 @@ enum
     V42BIS_RESET = 2        /* Force reinitialisation */
 };
 
-static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet)
+static __inline__ void push_octet(v42bis_comp_state_t *s, int octet)
 {
-    ss->output_buf[ss->output_octet_count++] = (uint8_t) octet;
-    if (ss->output_octet_count >= ss->max_len)
+    s->output_buf[s->output_octet_count++] = (uint8_t) octet;
+    if (s->output_octet_count >= s->max_output_len)
     {
-        ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count);
-        ss->output_octet_count = 0;
+        s->handler(s->user_data, s->output_buf, s->output_octet_count);
+        s->output_octet_count = 0;
     }
 }
 /*- End of function --------------------------------------------------------*/
 
-static __inline__ void push_compressed_code(v42bis_compress_state_t *ss, int code)
+static __inline__ void push_octets(v42bis_comp_state_t *s, const uint8_t buf[], int len)
 {
-    ss->output_bit_buffer |= code << (32 - ss->v42bis_parm_c2 - ss->output_bit_count);
-    ss->output_bit_count += ss->v42bis_parm_c2;
-    while (ss->output_bit_count >= 8)
-    {
-        push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24);
-        ss->output_bit_buffer <<= 8;
-        ss->output_bit_count -= 8;
-    }
-}
-/*- End of function --------------------------------------------------------*/
-
-static __inline__ void push_compressed_octet(v42bis_compress_state_t *ss, int code)
-{
-    ss->output_bit_buffer |= code << (32 - 8 - ss->output_bit_count);
-    ss->output_bit_count += 8;
-    while (ss->output_bit_count >= 8)
-    {
-        push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24);
-        ss->output_bit_buffer <<= 8;
-        ss->output_bit_count -= 8;
-    }
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len)
-{
-    int ptr;
     int i;
-    uint32_t octet;
-    uint32_t code;
-    v42bis_compress_state_t *ss;
+    int chunk;
 
-    ss = &s->compress;
-    if ((s->v42bis_parm_p0 & 2) == 0)
+    i = 0;
+    while ((s->output_octet_count + len - i) >= s->max_output_len)
+    {
+        chunk = s->max_output_len - s->output_octet_count;
+        memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk);
+        s->handler(s->user_data, s->output_buf, s->max_output_len);
+        s->output_octet_count = 0;
+        i += chunk;
+    }
+    chunk = len - i;
+    if (chunk > 0)
+    {
+        memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk);
+        s->output_octet_count += chunk;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void push_compressed_code(v42bis_comp_state_t *s, int code)
+{
+    s->bit_buffer |= code << s->bit_count;
+    s->bit_count += s->v42bis_parm_c2;
+    while (s->bit_count >= 8)
+    {
+        push_octet(s, s->bit_buffer & 0xFF);
+        s->bit_buffer >>= 8;
+        s->bit_count -= 8;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void push_octet_alignment(v42bis_comp_state_t *s)
+{
+    if ((s->bit_count & 7))
+    {
+        s->bit_count += (8 - (s->bit_count & 7));
+        while (s->bit_count >= 8)
+        {
+            push_octet(s, s->bit_buffer & 0xFF);
+            s->bit_buffer >>= 8;
+            s->bit_count -= 8;
+        }
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void flush_octets(v42bis_comp_state_t *s)
+{
+    if (s->output_octet_count > 0)
+    {
+        s->handler(s->user_data, s->output_buf, s->output_octet_count);
+        s->output_octet_count = 0;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void dictionary_init(v42bis_comp_state_t *s)
+{
+    int i;
+
+    memset(s->dict, 0, sizeof(s->dict));
+    for (i = 0;  i < V42BIS_N4;  i++)
+        s->dict[i + V42BIS_N6].node_octet = i;
+    s->v42bis_parm_c1 = V42BIS_N5;
+    s->v42bis_parm_c2 = V42BIS_N3 + 1;
+    s->v42bis_parm_c3 = V42BIS_N4 << 1;
+    s->last_matched = 0;
+    s->update_at = 0;
+    s->last_added = 0;
+    s->bit_buffer = 0;
+    s->bit_count = 0;
+    s->flushed_length = 0;
+    s->string_length = 0;
+    s->escape_code = 0;
+    s->transparent = TRUE;
+    s->escaped = FALSE;
+    s->compression_performance = COMPRESSIBILITY_MONITOR;
+}
+/*- End of function --------------------------------------------------------*/
+
+static uint16_t match_octet(v42bis_comp_state_t *s, uint16_t at, uint8_t octet)
+{
+    uint16_t e;
+
+    if (at == 0)
+        return octet + V42BIS_N6;
+    e = s->dict[at].child;
+    while (e)
+    {
+        if (s->dict[e].node_octet == octet)
+            return e;
+        e = s->dict[e].next;
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static uint16_t add_octet_to_dictionary(v42bis_comp_state_t *s, uint16_t at, uint8_t octet)
+{
+    uint16_t newx;
+    uint16_t next;
+    uint16_t e;
+
+    newx = s->v42bis_parm_c1;
+    s->dict[newx].node_octet = octet;
+    s->dict[newx].parent = at;
+    s->dict[newx].child = 0;
+    s->dict[newx].next = s->dict[at].child;
+    s->dict[at].child = newx;
+    next = newx;
+    /* 6.5 Recovering a dictionary entry to use next */
+    do
+    {
+        /* 6.5(a) and (b) */
+        if (++next == s->v42bis_parm_n2)
+            next = V42BIS_N5;
+    }
+    while (s->dict[next].child);
+    /* 6.5(c) We need to reuse a leaf node */
+    if (s->dict[next].parent)
+    {
+        /* 6.5(d) Detach the leaf node from its parent, and re-use it */
+        e = s->dict[next].parent;
+        if (s->dict[e].child == next)
+        {
+            s->dict[e].child = s->dict[next].next;
+        }
+        else
+        {
+            e = s->dict[e].child;
+            while (s->dict[e].next != next)
+                e = s->dict[e].next;
+            s->dict[e].next = s->dict[next].next;
+        }
+    }
+    s->v42bis_parm_c1 = next;
+    return newx;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void send_string(v42bis_comp_state_t *s)
+{
+    push_octets(s, s->string, s->string_length);
+    s->string_length = 0;
+    s->flushed_length = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void expand_codeword_to_string(v42bis_comp_state_t *s, uint16_t code)
+{
+    int i;
+    uint16_t p;
+
+    /* Work out the length */
+    for (i = 0, p = code;  p;  i++)
+        p = s->dict[p].parent;
+    s->string_length += i;
+    /* Now expand the known length of string */
+    i = s->string_length - 1;
+    for (p = code;  p;  )
+    {
+        s->string[i--] = s->dict[p].node_octet;
+        p = s->dict[p].parent;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void send_encoded_data(v42bis_comp_state_t *s, uint16_t code)
+{
+    int i;
+
+    /* Update compressibility metric */
+    /* Integrate at the compressed bit rate, and leak at the pre-compression bit rate */
+    s->compression_performance += (s->v42bis_parm_c2 - s->compression_performance*s->string_length*V42BIS_N3/COMPRESSIBILITY_MONITOR);
+    if (s->transparent)
+    {
+        for (i = 0;  i < s->string_length;  i++)
+        {
+            push_octet(s, s->string[i]);
+            if (s->string[i] == s->escape_code)
+            {
+                push_octet(s, V42BIS_EID);
+                s->escape_code += V42BIS_ESC_STEP;
+            }
+        }
+    }
+    else
+    {
+        /* Allow for any escape octets in the string */
+        for (i = 0;  i < s->string_length;  i++)
+        {
+            if (s->string[i] == s->escape_code)
+                s->escape_code += V42BIS_ESC_STEP;
+        }
+        /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */
+        while (code >= s->v42bis_parm_c3)
+        {
+            /* We need to increase the codeword size */
+            /* 7.4(a) */
+            push_compressed_code(s, V42BIS_STEPUP);
+            /* 7.4(b) */
+            s->v42bis_parm_c2++;
+            /* 7.4(c) */
+            s->v42bis_parm_c3 <<= 1;
+            /* 7.4(d) this might need to be repeated, so we loop */
+        }
+        /* 7.5 Transfer - output the last state of the string */
+        push_compressed_code(s, code);
+    }
+    s->string_length = 0;
+    s->flushed_length = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void go_compressed(v42bis_state_t *ss)
+{
+    v42bis_comp_state_t *s;
+
+    s = &ss->compress;
+    if (!s->transparent)
+        return;
+    span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n");
+    /* Switch out of transparent now, between codes. We need to send the octet which did not
+       match, just before switching. */
+    if (s->last_matched)
+    {
+        s->update_at = s->last_matched;
+        send_encoded_data(s, s->last_matched);
+        s->last_matched = 0;
+    }
+    push_octet(s, s->escape_code);
+    push_octet(s, V42BIS_ECM);
+    s->bit_buffer = 0;
+    s->transparent = FALSE;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void go_transparent(v42bis_state_t *ss)
+{
+    v42bis_comp_state_t *s;
+
+    s = &ss->compress;
+    if (s->transparent)
+        return;
+    span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n");
+    /* Switch into transparent now, between codes, and the unmatched octet should
+       go out in transparent mode, just below */
+    if (s->last_matched)
+    {
+        s->update_at = s->last_matched;
+        send_encoded_data(s, s->last_matched);
+        s->last_matched = 0;
+    }
+    s->last_added = 0;
+    push_compressed_code(s, V42BIS_ETM);
+    push_octet_alignment(s);
+    s->transparent = TRUE;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void monitor_for_mode_change(v42bis_state_t *ss)
+{
+    v42bis_comp_state_t *s;
+
+    s = &ss->compress;
+    switch (s->compression_mode)
+    {
+    case V42BIS_COMPRESSION_MODE_DYNAMIC:
+        /* 7.8 Data compressibility test */
+        if (s->transparent)
+        {
+            if (s->compression_performance < COMPRESSIBILITY_MONITOR - COMPRESSIBILITY_MONITOR_HYSTERESIS)
+            {
+                /* 7.8.1 Transition to compressed mode */
+                go_compressed(ss);
+            }
+        }
+        else
+        {
+            if (s->compression_performance > COMPRESSIBILITY_MONITOR)
+            {
+                /* 7.8.2 Transition to transparent mode */
+                go_transparent(ss);
+            }
+        }
+        /* 7.8.3 Reset function - TODO */
+        break;
+    case V42BIS_COMPRESSION_MODE_ALWAYS:
+        if (s->transparent)
+            go_compressed(ss);
+        break;
+    case V42BIS_COMPRESSION_MODE_NEVER:
+        if (!s->transparent)
+            go_transparent(ss);
+        break;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static int v42bis_comp_init(v42bis_comp_state_t *s,
+                            int p1,
+                            int p2,
+                            put_msg_func_t handler,
+                            void *user_data,
+                            int max_output_len)
+{
+    memset(s, 0, sizeof(*s));
+    s->v42bis_parm_n2 = p1;
+    s->v42bis_parm_n7 = p2;
+    s->handler = handler;
+    s->user_data = user_data;
+    s->max_output_len = (max_output_len < V42BIS_MAX_OUTPUT_LENGTH)  ?  max_output_len  :  V42BIS_MAX_OUTPUT_LENGTH;
+    s->output_octet_count = 0;
+    dictionary_init(s);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int comp_exit(v42bis_comp_state_t *s)
+{
+    s->v42bis_parm_n2 = 0;
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *ss, const uint8_t buf[], int len)
+{
+    v42bis_comp_state_t *s;
+    int i;
+    uint16_t code;
+
+    s = &ss->compress;
+    if (!s->v42bis_parm_p0)
     {
         /* Compression is off - just push the incoming data out */
-        for (i = 0;  i < len - ss->max_len;  i += ss->max_len)
-            ss->handler(ss->user_data, buf + i, ss->max_len);
-        if (i < len)
-            ss->handler(ss->user_data, buf + i, len - i);
+        push_octets(s, buf, len);
         return 0;
     }
-    ptr = 0;
-    if (ss->first  &&  len > 0)
+    for (i = 0;  i < len;  )
     {
-        octet = buf[ptr++];
-        ss->string_code = octet + V42BIS_N6;
-        if (octet == ss->escape_code)
+        /* 6.4 Add the string to the dictionary */
+        if (s->update_at)
         {
-            push_compressed_octet(ss, ss->escape_code);
-            ss->escape_code += V42BIS_ESC_STEP;
-            push_compressed_octet(ss, V42BIS_EID);
+            if (match_octet(s, s->update_at, buf[i]) == 0)
+                s->last_added = add_octet_to_dictionary(s, s->update_at, buf[i]);
+            s->update_at = 0;
         }
-        else
+        /* Match string */
+        while (i < len)
         {
-            push_compressed_octet(ss, octet);
-        }
-        ss->first = FALSE;
-    }
-    while (ptr < len)
-    {
-        octet = buf[ptr++];
-        if ((ss->dict[ss->string_code].children[octet >> 5] & (1 << (octet & 0x1F))))
-        {
-            /* The leaf exists. Now find it in the table. */
-            /* TODO: This is a brute force scan for a match. We need something better. */
-            for (code = 0;  code < ss->v42bis_parm_c3;  code++)
+            code = match_octet(s, s->last_matched, buf[i]);
+            if (code == 0)
             {
-                if (ss->dict[code].parent_code == ss->string_code  &&  ss->dict[code].node_octet == octet)
-                    break;
-            }
-        }
-        else
-        {
-            /* The leaf does not exist. */
-            code = s->v42bis_parm_n2;
-        }
-        /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry
-                  created by the last invocation of the string matching procedure, then the
-                  next character shall be read and appended to the string and this step
-                  repeated. */
-        if (code < ss->v42bis_parm_c3  &&  code != ss->latest_code)
-        {
-            /* The string was found */
-            ss->string_code = code;
-            ss->string_length++;
-        }
-        else
-        {
-            /* The string is not in the table. */
-            if (!ss->transparent)
-            {
-                /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */
-                while (ss->v42bis_parm_c1 >= ss->v42bis_parm_c3  &&  ss->v42bis_parm_c3 <= s->v42bis_parm_n2)
-                {
-                    /* We need to increase the codeword size */
-                    /* 7.4(a) */
-                    push_compressed_code(ss, V42BIS_STEPUP);
-                    /* 7.4(b) */
-                    ss->v42bis_parm_c2++;
-                    /* 7.4(c) */
-                    ss->v42bis_parm_c3 <<= 1;
-                    /* 7.4(d) this might need to be repeated, so we loop */
-                }
-                /* 7.5 Transfer - output the last state of the string */
-                push_compressed_code(ss, ss->string_code);
-            }
-            /* 7.6    Dictionary updating */
-            /* 6.4    Add the string to the dictionary */
-            /* 6.4(b) The string is not in the table. */
-            if (code != ss->latest_code  &&  ss->string_length < s->v42bis_parm_n7)
-            {
-                ss->latest_code = ss->v42bis_parm_c1;
-                /* 6.4(a) The length of the string is in range for adding to the dictionary */
-                /* If the last code was a leaf, it no longer is */
-                ss->dict[ss->string_code].leaves++;
-                ss->dict[ss->string_code].children[octet >> 5] |= (1 << (octet & 0x1F));
-                /* The new one is definitely a leaf */
-                ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->string_code;
-                ss->dict[ss->v42bis_parm_c1].leaves = 0;
-                ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) octet;
-                /* 7.7    Node recovery */
-                /* 6.5    Recovering a dictionary entry to use next */
-                for (;;)
-                {
-                    /* 6.5(a) and (b) */
-                    if ((int) (++ss->v42bis_parm_c1) >= s->v42bis_parm_n2)
-                        ss->v42bis_parm_c1 = V42BIS_N5;
-                    /* 6.5(c) We need to reuse a leaf node */
-                    if (ss->dict[ss->v42bis_parm_c1].leaves)
-                        continue;
-                    if (ss->dict[ss->v42bis_parm_c1].parent_code == 0xFFFF)
-                        break;
-                    /* 6.5(d) Detach the leaf node from its parent, and re-use it */
-                    /* Possibly make the parent a leaf node again */
-                    ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--;
-                    ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].children[ss->dict[ss->v42bis_parm_c1].node_octet >> 5] &= ~(1 << (ss->dict[ss->v42bis_parm_c1].node_octet & 0x1F));
-                    ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF;
-                    break;
-                }
-            }
-            else
-            {
-                ss->latest_code = 0xFFFFFFFF;
-            }
-            /* 7.8 Data compressibility test */
-            /* Filter on the balance of what went into the compressor, and what came out */
-            ss->compressibility_filter += ((((8*ss->string_length - ss->v42bis_parm_c2) << 20) - ss->compressibility_filter) >> 10);
-            if (ss->compression_mode == V42BIS_COMPRESSION_MODE_DYNAMIC)
-            {
-                /* Work out if it is appropriate to change between transparent and
-                   compressed mode. */
-                if (ss->transparent)
-                {
-                    if (ss->compressibility_filter > 0)
-                    {
-                        if (++ss->compressibility_persistence > 1000)
-                        {
-                            /* Schedule a switch to compressed mode */
-                            ss->change_transparency = -1;
-                            ss->compressibility_persistence = 0;
-                        }
-                    }
-                    else
-                    {
-                        ss->compressibility_persistence = 0;
-                    }
-                }
-                else
-                {
-                    if (ss->compressibility_filter < 0)
-                    {
-                        if (++ss->compressibility_persistence > 1000)
-                        {
-                            /* Schedule a switch to transparent mode */
-                            ss->change_transparency = 1;
-                            ss->compressibility_persistence = 0;
-                        }
-                    }
-                    else
-                    {
-                        ss->compressibility_persistence = 0;
-                    }
-                }
-            }
-            if (ss->change_transparency)
-            {
-                if (ss->change_transparency < 0)
-                {
-                    if (ss->transparent)
-                    {
-                        printf("Going compressed\n");
-                        /* 7.8.1 Transition to compressed mode */
-                        /* Switch out of transparent now, between codes. We need to send the octet which did not
-                           match, just before switching. */
-                        if (octet == ss->escape_code)
-                        {
-                            push_compressed_octet(ss, ss->escape_code);
-                            ss->escape_code += V42BIS_ESC_STEP;
-                            push_compressed_octet(ss, V42BIS_EID);
-                        }
-                        else
-                        {
-                            push_compressed_octet(ss, octet);
-                        }
-                        push_compressed_octet(ss, ss->escape_code);
-                        ss->escape_code += V42BIS_ESC_STEP;
-                        push_compressed_octet(ss, V42BIS_ECM);
-                        ss->transparent = FALSE;
-                    }
-                }
-                else
-                {
-                    if (!ss->transparent)
-                    {
-                        printf("Going transparent\n");
-                        /* 7.8.2 Transition to transparent mode */
-                        /* Switch into transparent now, between codes, and the unmatched octet should
-                           go out in transparent mode, just below */
-                        push_compressed_code(ss, V42BIS_ETM);
-                        ss->transparent = TRUE;
-                    }
-                }
-                ss->change_transparency = 0;
-            }
-            /* 7.8.3 Reset function - TODO */
-            ss->string_code = octet + V42BIS_N6;
-            ss->string_length = 1;
-        }
-        if (ss->transparent)
-        {
-            if (octet == ss->escape_code)
-            {
-                push_compressed_octet(ss, ss->escape_code);
-                ss->escape_code += V42BIS_ESC_STEP;
-                push_compressed_octet(ss, V42BIS_EID);
-            }
-            else
-            {
-                push_compressed_octet(ss, octet);
+                s->update_at = s->last_matched;
+                send_encoded_data(s, s->last_matched);
+                s->last_matched = 0;
+                break;
+            }
+            if (code == s->last_added)
+            {
+                s->last_added = 0;
+                send_encoded_data(s, s->last_matched);
+                s->last_matched = 0;
+                break;
+            }
+            s->last_matched = code;
+            /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry
+                      created by the last invocation of the string matching procedure, then the
+                      next character shall be read and appended to the string and this step
+                      repeated. */
+            s->string[s->string_length++] = buf[i++];
+            /* 6.4(a) The string must not exceed N7 in length */
+            if (s->string_length + s->flushed_length == s->v42bis_parm_n7)
+            {
+                send_encoded_data(s, s->last_matched);
+                s->last_matched = 0;
+                break;
             }
         }
+        monitor_for_mode_change(ss);
     }
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s)
+SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *ss)
 {
-    v42bis_compress_state_t *ss;
-
-    ss = &s->compress;
-    if (!ss->transparent)
-    {
-        /* Output the last state of the string */
-        push_compressed_code(ss, ss->string_code);
-        /* TODO: We use a positive FLUSH at all times. It is really needed, if the
-           previous step resulted in no leftover bits. */
-        push_compressed_code(ss, V42BIS_FLUSH);
-    }
-    while (ss->output_bit_count > 0)
-    {
-        push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24);
-        ss->output_bit_buffer <<= 8;
-        ss->output_bit_count -= 8;
-    }
-    /* Now push out anything remaining. */
-    if (ss->output_octet_count > 0)
-    {
-        ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count);
-        ss->output_octet_count = 0;
-    }
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-#if 0
-SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s)
-{
-    int i;
+    v42bis_comp_state_t *s;
+    int len;
     
-    for (i = 0;  i < V42BIS_MAX_CODEWORDS;  i++)
+    s = &ss->compress;
+    if (s->update_at)
+        return 0;
+    if (s->last_matched)
     {
-        if (s->compress.dict[i].parent_code != 0xFFFF)
-        {
-            printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet);
-        }
+        len = s->string_length;
+        send_encoded_data(s, s->last_matched);
+        s->flushed_length += len;
     }
+    if (!s->transparent)
+    {
+        s->update_at = s->last_matched;
+        s->last_matched = 0;
+        s->flushed_length = 0;
+        push_compressed_code(s, V42BIS_FLUSH);
+        push_octet_alignment(s);
+    }
+    flush_octets(s);
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
-#endif
 
-SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len)
+SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int len)
 {
-    int ptr;
+    v42bis_comp_state_t *s;
     int i;
-    int this_length;
-    uint8_t *string;
-    uint32_t code;
-    uint32_t new_code;
-    int code_len;
-    v42bis_decompress_state_t *ss;
-    uint8_t decode_buf[V42BIS_MAX_STRING_SIZE];
+    int j;
+    int yyy;
+    uint16_t code;
+    uint16_t p;
+    uint8_t ch;
+    uint8_t in;
 
-    ss = &s->decompress;
-    if ((s->v42bis_parm_p0 & 1) == 0)
+    s = &ss->decompress;
+    if (!s->v42bis_parm_p0)
     {
         /* Compression is off - just push the incoming data out */
-        for (i = 0;  i < len - ss->max_len;  i += ss->max_len)
-            ss->handler(ss->user_data, buf + i, ss->max_len);
-        if (i < len)
-            ss->handler(ss->user_data, buf + i, len - i);
+        push_octets(s, buf, len);
         return 0;
     }
-    ptr = 0;
-    code_len = (ss->transparent)  ?  8  :  ss->v42bis_parm_c2;
-    for (;;)
+    for (i = 0;  i < len;  )
     {
-        /* Fill up the bit buffer. */
-        while (ss->input_bit_count < (32 - 8)  &&  ptr < len)
+        if (s->transparent)
         {
-            ss->input_bit_count += 8;
-            ss->input_bit_buffer |= (uint32_t) buf[ptr++] << (32 - ss->input_bit_count);
-        }
-        if (ss->input_bit_count < code_len)
-            break;
-        new_code = ss->input_bit_buffer >> (32 - code_len);
-        ss->input_bit_count -= code_len;
-        ss->input_bit_buffer <<= code_len;
-        if (ss->transparent)
-        {
-            code = new_code;
-            if (ss->escaped)
+            in = buf[i];
+            if (s->escaped)
             {
-                ss->escaped = FALSE;
-                switch (code)
+                /* Command */
+                s->escaped = FALSE;
+                switch (in)
                 {
                 case V42BIS_ECM:
-                    printf("Hit V42BIS_ECM\n");
-                    ss->transparent = FALSE;
-                    code_len = ss->v42bis_parm_c2;
-                    break;
+                    /* Enter compressed mode */
+                    span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n");
+                    send_string(s);
+                    s->transparent = FALSE;
+                    s->update_at = s->last_matched;
+                    s->last_matched = 0;
+                    i++;
+                    continue;
                 case V42BIS_EID:
-                    printf("Hit V42BIS_EID\n");
-                    ss->output_buf[ss->output_octet_count++] = ss->escape_code;
-                    ss->escape_code += V42BIS_ESC_STEP;
-                    if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7)
-                    {
-                        ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count);
-                        ss->output_octet_count = 0;
-                    }
+                    /* Escape symbol */
+                    span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n");
+                    in = s->escape_code;
+                    s->escape_code += V42BIS_ESC_STEP;
                     break;
                 case V42BIS_RESET:
-                    printf("Hit V42BIS_RESET\n");
-                    break;
+                    /* Reset dictionary */
+                    span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n");
+                    /* TODO: */
+                    send_string(s);
+                    dictionary_init(s);
+                    i++;
+                    continue;
                 default:
-                    printf("Hit V42BIS_???? - %" PRIu32 "\n", code);
-                    break;
+                    span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in);
+                    return -1;
                 }
             }
-            else if (code == ss->escape_code)
+            else if (in == s->escape_code)
             {
-                ss->escaped = TRUE;
+                s->escaped = TRUE;
+                i++;
+                continue;
             }
-            else
+
+            yyy = TRUE;
+            for (j = 0;  j < 2  &&  yyy;  j++)
             {
-                ss->output_buf[ss->output_octet_count++] = (uint8_t) code;
-                if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7)
+                if (s->update_at)
                 {
-                    ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count);
-                    ss->output_octet_count = 0;
+                    if (match_octet(s, s->update_at, in) == 0)
+                        s->last_added = add_octet_to_dictionary(s, s->update_at, in);
+                    s->update_at = 0;
+                }
+
+                code = match_octet(s, s->last_matched, in);
+                if (code == 0)
+                {
+                    s->update_at = s->last_matched;
+                    send_string(s);
+                    s->last_matched = 0;
+                }
+                else if (code == s->last_added)
+                {
+                    s->last_added = 0;
+                    send_string(s);
+                    s->last_matched = 0;
+                }
+                else
+                {
+                    s->last_matched = code;
+                    s->string[s->string_length++] = in;
+                    if (s->string_length + s->flushed_length == s->v42bis_parm_n7)
+                    {
+                        send_string(s);
+                        s->last_matched = 0;
+                    }
+                    i++;
+                    yyy = FALSE;
                 }
             }
         }
         else
         {
-            if (new_code < V42BIS_N6)
+            /* Get code from input */
+            while (s->bit_count < s->v42bis_parm_c2  &&  i < len)
+            {
+                s->bit_buffer |= buf[i++] << s->bit_count;
+                s->bit_count += 8;
+            }
+            if (s->bit_count < s->v42bis_parm_c2)
+                continue;
+            code = s->bit_buffer & ((1 << s->v42bis_parm_c2) - 1);
+            s->bit_buffer >>= s->v42bis_parm_c2;
+            s->bit_count -= s->v42bis_parm_c2;
+
+            if (code < V42BIS_N6)
             {
                 /* We have a control code. */
-                switch (new_code)
+                switch (code)
                 {
                 case V42BIS_ETM:
-                    printf("Hit V42BIS_ETM\n");
-                    ss->transparent = TRUE;
-                    code_len = 8;
+                    /* Enter transparent mode */
+                    span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n");
+                    s->bit_count = 0;
+                    s->transparent = TRUE;
+                    s->last_matched = 0;
+                    s->last_added = 0;
                     break;
                 case V42BIS_FLUSH:
-                    printf("Hit V42BIS_FLUSH\n");
-                    v42bis_decompress_flush(s);
+                    /* Flush signal */
+                    span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n");
+                    s->bit_count = 0;
                     break;
                 case V42BIS_STEPUP:
-                    /* We need to increase the codeword size */
-                    printf("Hit V42BIS_STEPUP\n");
-                    if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2)
-                    {
-                        /* Invalid condition */
+                    /* Increase code word size */
+                    span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n");
+                    s->v42bis_parm_c2++;
+                    s->v42bis_parm_c3 <<= 1;
+                    if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3))
                         return -1;
-                    }
-                    code_len = ++ss->v42bis_parm_c2;
-                    ss->v42bis_parm_c3 <<= 1;
                     break;
                 }
                 continue;
             }
-            if (ss->first)
-            {
-                ss->first = FALSE;
-                ss->octet = new_code - V42BIS_N6;
-                ss->output_buf[0] = (uint8_t) ss->octet;
-                ss->output_octet_count = 1;
-                if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7)
-                {
-                    ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count);
-                    ss->output_octet_count = 0;
-                }
-                ss->old_code = new_code;
-                continue;
-            }
-            /* Start at the end of the buffer, and decode backwards */
-            string = &decode_buf[V42BIS_MAX_STRING_SIZE - 1];
-            /* Check the received code is valid. It can't be too big, as we pulled only the expected number
-            of bits from the input stream. It could, however, be unknown. */
-            if (ss->dict[new_code].parent_code == 0xFFFF)
+            /* Regular codeword */
+            if (code == s->v42bis_parm_c1)
                 return -1;
-            /* Otherwise we do a straight decode of the new code. */
-            code = new_code;
-            /* Trace back through the octets which form the string, and output them. */
-            while (code >= V42BIS_N5)
+            expand_codeword_to_string(s, code);
+            if (s->update_at)
             {
-if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);}
-                *string-- = ss->dict[code].node_octet;
-                code = ss->dict[code].parent_code;
-            }
-            *string = (uint8_t) (code - V42BIS_N6);
-            ss->octet = code - V42BIS_N6;
-            /* Output the decoded string. */
-            this_length = V42BIS_MAX_STRING_SIZE - (int) (string - decode_buf);
-            for (i = 0;  i < this_length;  i++)
-            {
-                if (string[i] == ss->escape_code)
-                    ss->escape_code += V42BIS_ESC_STEP;
-            }
-            memcpy(ss->output_buf + ss->output_octet_count, string, this_length);
-            ss->output_octet_count += this_length;
-            if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7)
-            {
-                ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count);
-                ss->output_octet_count = 0;
-            }
-            /* 6.4 Add the string to the dictionary */
-            if (ss->last_length < s->v42bis_parm_n7)
-            {
-                /* 6.4(a) The string does not exceed N7 in length */
-                if (ss->last_old_code != ss->old_code
-                    ||
-                    ss->last_extra_octet != *string)
+                ch = s->string[0];
+                if ((p = match_octet(s, s->update_at, ch)) == 0)
                 {
-                    /* 6.4(b) The string is not in the table. */
-                    ss->dict[ss->old_code].leaves++;
-                    /* The new one is definitely a leaf */
-                    ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->old_code;
-                    ss->dict[ss->v42bis_parm_c1].leaves = 0;
-                    ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) ss->octet;
-                    /* 6.5 Recovering a dictionary entry to use next */
-                    for (;;)
-                    {
-                        /* 6.5(a) and (b) */
-                        if (++ss->v42bis_parm_c1 >= s->v42bis_parm_n2)
-                            ss->v42bis_parm_c1 = V42BIS_N5;
-                        /* 6.5(c) We need to reuse a leaf node */
-                        if (ss->dict[ss->v42bis_parm_c1].leaves)
-                            continue;
-                        /* 6.5(d) This is a leaf node, so re-use it */
-                        /* Possibly make the parent a leaf node again */
-                        if (ss->dict[ss->v42bis_parm_c1].parent_code != 0xFFFF)
-                            ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--;
-                        ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF;
-                        break;
-                    }
+                    s->last_added = add_octet_to_dictionary(s, s->update_at, ch);
+                    if (code == s->v42bis_parm_c1)
+                        return -1;
+                }
+                else if (p == s->last_added)
+                {
+                    s->last_added = 0;
                 }
             }
-            /* Record the addition to the dictionary, so we can check for repeat attempts
-               at the next code - see II.4.3 */
-            ss->last_old_code = ss->old_code;
-            ss->last_extra_octet = *string;
-
-            ss->old_code = new_code;
-            ss->last_length = this_length;
+            s->update_at = ((s->string_length + s->flushed_length) == s->v42bis_parm_n7)  ?  0  :  code;
+            /* Allow for any escapes which may be in this string */
+            for (j = 0;  j < s->string_length;  j++)
+            {
+                if (s->string[j] == s->escape_code)
+                    s->escape_code += V42BIS_ESC_STEP;
+            }
+            send_string(s);
         }
     }
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s)
+SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *ss)
 {
-    v42bis_decompress_state_t *ss;
-
-    ss = &s->decompress;
-    /* Push out anything remaining. */
-    if (ss->output_octet_count > 0)
-    {
-        ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count);
-        ss->output_octet_count = 0;
-    }
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-#if 0
-SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s)
-{
-    int i;
+    v42bis_comp_state_t *s;
+    int len;
     
-    for (i = 0;  i < V42BIS_MAX_CODEWORDS;  i++)
-    {
-        if (s->decompress.dict[i].parent_code != 0xFFFF)
-        {
-            printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet);
-        }
-    }
+    s = &ss->decompress;
+    len = s->string_length;
+    send_string(s);
+    s->flushed_length += len;
+    flush_octets(s);
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
-#endif
 
 SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode)
 {
     s->compress.compression_mode = mode;
-    switch (mode)
-    {
-    case V42BIS_COMPRESSION_MODE_ALWAYS:
-        s->compress.change_transparency = -1;
-        break;
-    case V42BIS_COMPRESSION_MODE_NEVER:
-        s->compress.change_transparency = 1;
-        break;
-    }
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -634,14 +712,14 @@ SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s,
                                            int negotiated_p0,
                                            int negotiated_p1,
                                            int negotiated_p2,
-                                           v42bis_frame_handler_t frame_handler,
-                                           void *frame_user_data,
-                                           int max_frame_len,
-                                           v42bis_data_handler_t data_handler,
-                                           void *data_user_data,
-                                           int max_data_len)
+                                           put_msg_func_t encode_handler,
+                                           void *encode_user_data,
+                                           int max_encode_len,
+                                           put_msg_func_t decode_handler,
+                                           void *decode_user_data,
+                                           int max_decode_len)
 {
-    int i;
+    int ret;
 
     if (negotiated_p1 < V42BIS_MIN_DICTIONARY_SIZE  ||  negotiated_p1 > 65535)
         return NULL;
@@ -653,55 +731,18 @@ SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s,
             return NULL;
     }
     memset(s, 0, sizeof(*s));
+    span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
+    span_log_set_protocol(&s->logging, "V.42bis");
 
-    s->compress.handler = frame_handler;
-    s->compress.user_data = frame_user_data;
-    s->compress.max_len = (max_frame_len < 1024)  ?  max_frame_len  :  1024;
-
-    s->decompress.handler = data_handler;
-    s->decompress.user_data = data_user_data;
-    s->decompress.max_len = (max_data_len < 1024)  ?  max_data_len  :  1024;
-
-    s->v42bis_parm_p0 = negotiated_p0;  /* default is both ways off */
-
-    s->v42bis_parm_n1 = top_bit(negotiated_p1 - 1) + 1;
-    s->v42bis_parm_n2 = negotiated_p1;
-    s->v42bis_parm_n7 = negotiated_p2;
-
-    /* 6.5 */
-    s->compress.v42bis_parm_c1 =
-    s->decompress.v42bis_parm_c1 = V42BIS_N5;
-
-    s->compress.v42bis_parm_c2 =
-    s->decompress.v42bis_parm_c2 = V42BIS_N3 + 1;
-
-    s->compress.v42bis_parm_c3 =
-    s->decompress.v42bis_parm_c3 = 2*V42BIS_N4;
-
-    s->compress.first =
-    s->decompress.first = TRUE;
-    for (i = 0;  i < V42BIS_MAX_CODEWORDS;  i++)
+    if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len)))
+        return NULL;
+    if ((ret = v42bis_comp_init(&s->decompress, negotiated_p1, negotiated_p2, decode_handler, decode_user_data, max_decode_len)))
     {
-        s->compress.dict[i].parent_code =
-        s->decompress.dict[i].parent_code = 0xFFFF;
-        s->compress.dict[i].leaves =
-        s->decompress.dict[i].leaves = 0;
+        comp_exit(&s->compress);
+        return NULL;
     }
-    /* Point the root nodes for decompression to themselves. It doesn't matter much what
-       they are set to, as long as they are considered "known" codes. */
-    for (i = 0;  i < V42BIS_N5;  i++)
-        s->decompress.dict[i].parent_code = (uint16_t) i;
-    s->compress.string_code = 0xFFFFFFFF;
-    s->compress.latest_code = 0xFFFFFFFF;
-    s->compress.transparent = TRUE;
-    s->compress.first = TRUE;
-
-    s->decompress.last_old_code = 0xFFFFFFFF;
-    s->decompress.last_extra_octet = -1;
-    s->decompress.transparent = TRUE;
-    s->compress.first = TRUE;
-
-    s->compress.compression_mode = V42BIS_COMPRESSION_MODE_DYNAMIC;
+    s->compress.v42bis_parm_p0 = negotiated_p0 & 2;
+    s->decompress.v42bis_parm_p0 = negotiated_p0 & 1;
 
     return s;
 }
@@ -715,7 +756,8 @@ SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s)
 
 SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s)
 {
-    free(s);
+    comp_exit(&s->compress);
+    comp_exit(&s->decompress);
     return 0;
 }
 /*- End of function --------------------------------------------------------*/
diff --git a/libs/spandsp/tests/Makefile.am b/libs/spandsp/tests/Makefile.am
index 52769e78d8..150977f39c 100644
--- a/libs/spandsp/tests/Makefile.am
+++ b/libs/spandsp/tests/Makefile.am
@@ -23,11 +23,11 @@ LIBS += $(TESTLIBS)
 
 noinst_DATA = sound_c1_8k.wav sound_c3_8k.wav
 
-EXTRA_DIST = regression_tests.sh \
+EXTRA_DIST = fax_tests.sh \
+             regression_tests.sh \
              tsb85_extra_tests.sh \
-             v42bis_tests.sh \
-             fax_tests.sh \
              tsb85_tests.sh \
+             v42bis_tests.sh \
              msvc/adsi_tests.vcproj \
              msvc/complex_tests.vcproj \
              msvc/complex_vector_float_tests.vcproj \
@@ -102,15 +102,15 @@ noinst_PROGRAMS =   adsi_tests \
                     super_tone_rx_tests \
                     super_tone_tx_tests \
                     swept_tone_tests \
-                    t4_tests \
                     t31_tests \
-                    t38_decode \
                     t38_core_tests \
+                    t38_decode \
                     t38_gateway_tests \
                     t38_gateway_to_terminal_tests \
                     t38_non_ecm_buffer_tests \
                     t38_terminal_tests \
                     t38_terminal_to_gateway_tests \
+                    t4_tests \
                     time_scale_tests \
                     timezone_tests \
                     tone_detect_tests \
@@ -126,8 +126,6 @@ noinst_PROGRAMS =   adsi_tests \
                     v8_tests \
                     vector_float_tests \
                     vector_int_tests \
-                    testadsi \
-                    testfax \
                     tsb85_tests
 
 noinst_HEADERS =    echo_monitor.h \
@@ -364,12 +362,6 @@ vector_float_tests_LDADD = $(LIBDIR) -lspandsp
 vector_int_tests_SOURCES = vector_int_tests.c
 vector_int_tests_LDADD = $(LIBDIR) -lspandsp
 
-testadsi_SOURCES = testadsi.c
-testadsi_LDADD = $(LIBDIR) -lspandsp
-
-testfax_SOURCES = testfax.c
-testfax_LDADD = $(LIBDIR) -lspandsp
-
 # We need to create the CSS files for echo cancellation tests.
 
 sound_c1_8k.wav sound_c3_8k.wav: make_g168_css$(EXEEXT)
diff --git a/libs/spandsp/tests/fax_tests.c b/libs/spandsp/tests/fax_tests.c
index 084a2b034f..a01747fb15 100644
--- a/libs/spandsp/tests/fax_tests.c
+++ b/libs/spandsp/tests/fax_tests.c
@@ -80,7 +80,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
 
     i = (int) (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase B:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase B", i);
     printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
     log_rx_parameters(s, tag);
     return T30_ERR_OK;
@@ -93,7 +93,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
 
     i = (int) (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase D:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase D", i);
     printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
     log_transfer_statistics(s, tag);
     log_tx_parameters(s, tag);
@@ -136,7 +136,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
 
     i = (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase E:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase E", i);
     printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result));    
     log_transfer_statistics(s, tag);
     log_tx_parameters(s, tag);
diff --git a/libs/spandsp/tests/oki_adpcm_tests.c b/libs/spandsp/tests/oki_adpcm_tests.c
index 0b761d9607..b36968c59a 100644
--- a/libs/spandsp/tests/oki_adpcm_tests.c
+++ b/libs/spandsp/tests/oki_adpcm_tests.c
@@ -123,6 +123,9 @@ int main(int argc, char *argv[])
         }
     }
 
+    encoded_fd = -1;
+    inhandle = NULL;
+    oki_enc_state = NULL;
     if (encoded_file_name)
     {
         if ((encoded_fd = open(encoded_file_name, O_RDONLY)) < 0)
diff --git a/libs/spandsp/tests/pcap_parse.c b/libs/spandsp/tests/pcap_parse.c
index e5e0014826..900f957068 100644
--- a/libs/spandsp/tests/pcap_parse.c
+++ b/libs/spandsp/tests/pcap_parse.c
@@ -34,14 +34,17 @@
 #include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
+
+#if defined(HAVE_PCAP_H)
 #include <pcap.h>
+#endif
 #include <netinet/in.h>
 #include <netinet/udp.h>
-#if defined(__HPUX)  ||  defined(__CYGWIN)  ||  defined(__FreeBSD__)
+#if defined(__HPUX)  ||  defined(__CYGWIN__)  ||  defined(__FreeBSD__)
 #include <netinet/in_systm.h>
 #endif
 #include <netinet/ip.h>
-#ifndef __CYGWIN
+#if !defined(__CYGWIN__)
 #include <netinet/ip6.h>
 #endif
 #include <string.h>
@@ -55,7 +58,7 @@
 #include "spandsp.h"
 #include "pcap_parse.h"
 
-#if defined(__HPUX) || defined(__DARWIN) || defined(__CYGWIN) || defined(__FreeBSD__)
+#if defined(__HPUX)  ||  defined(__DARWIN)  ||  defined(__CYGWIN__)  ||  defined(__FreeBSD__)
 
 struct iphdr
 {
@@ -90,15 +93,22 @@ typedef struct _ether_hdr
 {
     char ether_dst[6];
     char ether_src[6];
-    u_int16_t ether_type; /* we only need the type, so we can determine, if the next header is IPv4 or IPv6 */
+    u_int16_t ether_type;
 } ether_hdr;
 
+typedef struct _null_hdr
+{
+    uint32_t pf_type;
+} null_hdr;
+
+#if !defined(__CYGWIN__)
 typedef struct _ipv6_hdr
 {
     char dontcare[6];
     u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
     char dontcare2[33];
 } ipv6_hdr;
+#endif
 
 char errbuf[PCAP_ERRBUF_SIZE];
 
@@ -119,9 +129,14 @@ int pcap_scan_pkts(const char *file,
     int total_pkts;
     uint32_t pktlen;
     ether_hdr *ethhdr;
+    null_hdr *nullhdr;
     struct iphdr *iphdr;
+#if !defined(__CYGWIN__)
     ipv6_hdr *ip6hdr;
+#endif
     struct udphdr *udphdr;
+    int datalink;
+    int packet_type;
 
     total_pkts = 0;
     if ((pcap = pcap_open_offline(file, errbuf)) == NULL)
@@ -129,6 +144,15 @@ int pcap_scan_pkts(const char *file,
         fprintf(stderr, "Can't open PCAP file '%s'\n", file);
         return -1;
     }
+    datalink = pcap_datalink(pcap);
+    /* DLT_EN10MB seems to apply to all forms of ethernet, not just the 10MB kind. */
+    if (datalink != DLT_EN10MB  &&  datalink != DLT_NULL)
+    {
+        fprintf(stderr, "Unsupported data link type %d\n", datalink);
+        return -1;
+    }
+
+    printf("Datalink type %d\n", datalink);
     pkthdr = NULL;
     pktdata = NULL;
 #if defined(HAVE_PCAP_NEXT_EX)
@@ -143,14 +167,43 @@ int pcap_scan_pkts(const char *file,
     while ((pktdata = (uint8_t *) pcap_next(pcap, pkthdr)) != NULL)
     {
 #endif
-        ethhdr = (ether_hdr *) pktdata;
-        if (ntohs(ethhdr->ether_type) != 0x0800     /* IPv4 */
-            &&
-            ntohs(ethhdr->ether_type) != 0x86dd)    /* IPv6 */
+        if (datalink == DLT_EN10MB)
+        {
+            ethhdr = (ether_hdr *) pktdata;
+            packet_type = ntohs(ethhdr->ether_type);
+#if !defined(__CYGWIN__)
+            if (packet_type != 0x0800     /* IPv4 */
+                &&
+                packet_type != 0x86DD)    /* IPv6 */
+#else
+            if (packet_type != 0x0800)    /* IPv4 */
+#endif
+            {
+                continue;
+            }
+            iphdr = (struct iphdr *) ((uint8_t *) ethhdr + sizeof(*ethhdr));
+        }
+        else if (datalink == DLT_NULL)
+        {
+            nullhdr = (null_hdr *) pktdata;
+            if (nullhdr->pf_type != PF_INET  &&  nullhdr->pf_type != PF_INET6)
+                continue;
+            iphdr = (struct iphdr *) ((uint8_t *) nullhdr + sizeof(*nullhdr));
+        }
+        else
         {
             continue;
         }
-        iphdr = (struct iphdr *) ((uint8_t *) ethhdr + sizeof(*ethhdr));
+#if 0
+        {
+            int i;
+            printf("--- %d -", pkthdr->caplen);
+            for (i = 0;  i < pkthdr->caplen;  i++)
+                printf(" %02x", pktdata[i]);
+            printf("\n");
+        }
+#endif
+#if !defined(__CYGWIN__)
         if (iphdr  &&  iphdr->version == 6)
         {
             /* ipv6 */
@@ -161,11 +214,12 @@ int pcap_scan_pkts(const char *file,
             udphdr = (struct udphdr *) ((uint8_t *) ip6hdr + sizeof(*ip6hdr));
         }
         else
+#endif
         {
             /* ipv4 */
             if (iphdr->protocol != IPPROTO_UDP)
                 continue;
-#if defined(__DARWIN)  ||  defined(__CYGWIN)  ||  defined(__FreeBSD__)
+#if defined(__DARWIN)  ||  defined(__CYGWIN__)  ||  defined(__FreeBSD__)
             udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2) + 4);
             pktlen = (uint32_t) ntohs(udphdr->uh_ulen);
 #elif defined ( __HPUX)
@@ -176,24 +230,39 @@ int pcap_scan_pkts(const char *file,
             pktlen = (uint32_t) ntohs(udphdr->len);
 #endif
         }
+
         timing_update_handler(user_data, &pkthdr->ts);
+
         if (src_addr  &&  ntohl(iphdr->saddr) != src_addr)
             continue;
+#if defined(__DARWIN)  ||  defined(__CYGWIN__)  ||  defined(__FreeBSD__)
+        if (src_port  &&  ntohs(udphdr->uh_sport) != src_port)
+#else
         if (src_port  &&  ntohs(udphdr->source) != src_port)
+#endif
             continue;
         if (dest_addr  &&  ntohl(iphdr->daddr) != dest_addr)
             continue;
+#if defined(__DARWIN)  ||  defined(__CYGWIN__)  ||  defined(__FreeBSD__)
+        if (dest_port  &&  ntohs(udphdr->uh_dport) != dest_port)
+#else
         if (dest_port  &&  ntohs(udphdr->dest) != dest_port)
+#endif
             continue;
 
+        if (pkthdr->len != pkthdr->caplen)
+        {
+            fprintf(stderr, "Truncated packet - total len = %d, captured len = %d\n", pkthdr->len, pkthdr->caplen);
+            exit(2);
+        }
         body = (const uint8_t *) udphdr;
-        body += sizeof(udphdr);
-        body_len = pktlen - sizeof(udphdr);
+        body += sizeof(struct udphdr);
+        body_len = pktlen - sizeof(struct udphdr);
         packet_handler(user_data, body, body_len);
 
         total_pkts++;
     }
-    fprintf(stderr, "In pcap %s, npkts %d\n", file, total_pkts);
+    fprintf(stderr, "In pcap %s there were %d accepted packets\n", file, total_pkts);
     pcap_close(pcap);
 
     return 0;
diff --git a/libs/spandsp/tests/regression_tests.sh b/libs/spandsp/tests/regression_tests.sh
index 56f628fdd3..2a305531a6 100755
--- a/libs/spandsp/tests/regression_tests.sh
+++ b/libs/spandsp/tests/regression_tests.sh
@@ -846,25 +846,23 @@ echo v29_tests completed OK
 #fi
 #echo v32bis_tests completed OK
 
-#./v42_tests >$STDOUT_DEST 2>$STDERR_DEST
-#RETVAL=$?
-#if [ $RETVAL != 0 ]
-#then
-#    echo v42_tests failed!
-#    exit $RETVAL
-#fi
-#echo v42_tests completed OK
-echo v42_tests not enabled
+./v42_tests >$STDOUT_DEST 2>$STDERR_DEST
+RETVAL=$?
+if [ $RETVAL != 0 ]
+then
+    echo v42_tests failed!
+    exit $RETVAL
+fi
+echo v42_tests completed OK
 
-#./v42bis_tests.sh >/dev/null
-#RETVAL=$?
-#if [ $RETVAL != 0 ]
-#then
-#    echo v42bis_tests failed!
-#    exit $RETVAL
-#fi
-#echo v42bis_tests completed OK
-echo v42bis_tests not enabled
+./v42bis_tests.sh >/dev/null
+RETVAL=$?
+if [ $RETVAL != 0 ]
+then
+    echo v42bis_tests failed!
+    exit $RETVAL
+fi
+echo v42bis_tests completed OK
 
 ./v8_tests >$STDOUT_DEST 2>$STDERR_DEST
 RETVAL=$?
diff --git a/libs/spandsp/tests/t31_tests.c b/libs/spandsp/tests/t31_tests.c
index 49919d052d..c31c1d3aab 100644
--- a/libs/spandsp/tests/t31_tests.c
+++ b/libs/spandsp/tests/t31_tests.c
@@ -280,7 +280,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
 
     i = (int) (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase B:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase B", i);
     printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
     log_rx_parameters(s, tag);
     return T30_ERR_OK;
@@ -293,7 +293,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
 
     i = (int) (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase D:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase D", i);
     printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
     log_transfer_statistics(s, tag);
     log_tx_parameters(s, tag);
@@ -308,7 +308,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
     
     i = (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase E:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase E", i);
     printf("Phase E handler on channel %c\n", i);
     log_transfer_statistics(s, tag);
     log_tx_parameters(s, tag);
diff --git a/libs/spandsp/tests/t38_decode.c b/libs/spandsp/tests/t38_decode.c
index 39c8ec6b4b..bc6d6ce58a 100644
--- a/libs/spandsp/tests/t38_decode.c
+++ b/libs/spandsp/tests/t38_decode.c
@@ -1,7 +1,7 @@
 /*
  * SpanDSP - a series of DSP components for telephony
  *
- * pcap-parse.c
+ * t38_decode.c
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
@@ -53,6 +53,7 @@
 #define OUTPUT_FILE_NAME        "t38pcap.tif"
 
 t38_terminal_state_t *t38_state;
+struct timeval now;
 
 static int phase_b_handler(t30_state_t *s, void *user_data, int result)
 {
@@ -110,29 +111,35 @@ static int timing_update(void *user_data, struct timeval *ts)
     t38_core_state_t *t38_core;
     logging_state_t *logging;
     int samples;
+    int partial;
     static int64_t current = 0;
     int64_t when;
     int64_t diff;
 
+    memcpy(&now, ts, sizeof(now));
+
     when = ts->tv_sec*1000000LL + ts->tv_usec;
     if (current == 0)
         current = when;
 
     diff = when - current;
     samples = diff/125LL;
-    if (samples > 0)
+    while (samples > 0)
     {
+        partial = (samples > 160)  ?  160  :  samples;
+        //fprintf(stderr, "Update time by %d samples\n", partial);
         logging = t38_terminal_get_logging_state(t38_state);
-        span_log_bump_samples(logging, samples);
+        span_log_bump_samples(logging, partial);
         t38_core = t38_terminal_get_t38_core_state(t38_state);
         logging = t38_core_get_logging_state(t38_core);
-        span_log_bump_samples(logging, samples);
+        span_log_bump_samples(logging, partial);
         t30 = t38_terminal_get_t30_state(t38_state);
         logging = t30_get_logging_state(t30);
-        span_log_bump_samples(logging, samples);
+        span_log_bump_samples(logging, partial);
     
-        t38_terminal_send_timeout(t38_state, samples);
+        t38_terminal_send_timeout(t38_state, partial);
         current = when;
+        samples -= partial;
     }
     return 0;
 }
@@ -188,6 +195,7 @@ int main(int argc, char *argv[])
 
     use_ecm = FALSE;
     t38_version = 1;
+    options = 0;
     input_file_name = INPUT_FILE_NAME;
     fill_removal = FALSE;
     use_tep = FALSE;
@@ -196,7 +204,7 @@ int main(int argc, char *argv[])
     src_port = 0;
     dest_addr = 0;
     dest_port = 0;
-    while ((opt = getopt(argc, argv, "D:d:eFi:m:S:s:tv:")) != -1)
+    while ((opt = getopt(argc, argv, "D:d:eFi:m:oS:s:tv:")) != -1)
     {
         switch (opt)
         {
@@ -218,6 +226,9 @@ int main(int argc, char *argv[])
         case 'm':
             supported_modems = atoi(optarg);
             break;
+        case 'o':
+            options = atoi(optarg);
+            break;
         case 'S':
             src_addr = atoi(optarg);
             break;
@@ -272,6 +283,9 @@ int main(int argc, char *argv[])
 
     if (pcap_scan_pkts(input_file_name, src_addr, src_port, dest_addr, dest_port, timing_update, process_packet, NULL))
         exit(2);
+    /* Push the time along, to flush out any remaining activity from the application. */
+    now.tv_sec += 60;
+    timing_update(NULL, &now);
 }
 /*- End of function --------------------------------------------------------*/
 /*- End of file ------------------------------------------------------------*/
diff --git a/libs/spandsp/tests/t38_gateway_to_terminal_tests.c b/libs/spandsp/tests/t38_gateway_to_terminal_tests.c
index 9a27985794..17d4bf93e7 100644
--- a/libs/spandsp/tests/t38_gateway_to_terminal_tests.c
+++ b/libs/spandsp/tests/t38_gateway_to_terminal_tests.c
@@ -595,7 +595,7 @@ int main(int argc, char *argv[])
         logging = t38_core_get_logging_state(t38_core);
         span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
         logging = &t38_state_a->audio.modems.v17_rx.logging;
-        span_log_bump_samples(logging, t30_len_a);
+        span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
 
         logging = t38_terminal_get_logging_state(t38_state_b);
         span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
diff --git a/libs/spandsp/tests/timezone_tests.c b/libs/spandsp/tests/timezone_tests.c
index fb72f98437..f3096e86dd 100644
--- a/libs/spandsp/tests/timezone_tests.c
+++ b/libs/spandsp/tests/timezone_tests.c
@@ -1,86 +1,86 @@
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * timezone_tests.c - Timezone handling for time interpretation
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2010 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.
- */
-
-/*! \page timezone_tests_page Timezone handling tests
-\section timezone_tests_page_sec_1 What does it do?
-*/
-
-#if defined(HAVE_CONFIG_H)
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-//#if defined(WITH_SPANDSP_INTERNALS)
-#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
-//#endif
-
-#include "spandsp.h"
-
-#ifndef FALSE
-#define FALSE    0
-#endif
-
-#ifndef TRUE
-#define TRUE    (!FALSE)
-#endif
-
-int main(int argc, char *argv[])
-{
-    struct tm tms;
-    struct tm *tmp = &tms;
-    time_t ltime;
-    tz_t *tz;
-
-    /* Get the current time */
-    ltime = time(NULL);
-
-    /* Compute the local current time now for several localities, based on Posix tz strings */
-
-    tz = tz_init(NULL, "GMT0GMT0,M10.5.0,M3.5.0");
-    tz_localtime(tz, tmp, ltime);
-    printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-    printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
-
-    tz_init(tz, "CST-8CST-8,M10.5.0,M3.5.0");
-    tz_localtime(tz, tmp, ltime);
-    printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-    printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
-
-    tz_init(tz, "AEST-10AEDT-11,M10.5.0,M3.5.0");
-    tz_localtime(tz, tmp, ltime);
-    printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-    printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
-
-    tz_free(tz);
-
-    return 0;
-}
-/*- End of function --------------------------------------------------------*/
-/*- End of file ------------------------------------------------------------*/
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * timezone_tests.c - Timezone handling for time interpretation
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2010 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.
+ */
+
+/*! \page timezone_tests_page Timezone handling tests
+\section timezone_tests_page_sec_1 What does it do?
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+//#if defined(WITH_SPANDSP_INTERNALS)
+#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
+//#endif
+
+#include "spandsp.h"
+
+#ifndef FALSE
+#define FALSE    0
+#endif
+
+#ifndef TRUE
+#define TRUE    (!FALSE)
+#endif
+
+int main(int argc, char *argv[])
+{
+    struct tm tms;
+    struct tm *tmp = &tms;
+    time_t ltime;
+    tz_t *tz;
+
+    /* Get the current time */
+    ltime = time(NULL);
+
+    /* Compute the local current time now for several localities, based on Posix tz strings */
+
+    tz = tz_init(NULL, "GMT0GMT0,M10.5.0,M3.5.0");
+    tz_localtime(tz, tmp, ltime);
+    printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+    printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
+
+    tz_init(tz, "CST-8CST-8,M10.5.0,M3.5.0");
+    tz_localtime(tz, tmp, ltime);
+    printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+    printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
+
+    tz_init(tz, "AEST-10AEDT-11,M10.5.0,M3.5.0");
+    tz_localtime(tz, tmp, ltime);
+    printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+    printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
+
+    tz_free(tz);
+
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c
index ffab4e7737..e6786add0b 100644
--- a/libs/spandsp/tests/tsb85_tests.c
+++ b/libs/spandsp/tests/tsb85_tests.c
@@ -217,7 +217,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
 
     i = (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase D:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase D", i);
 
     printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
     log_transfer_statistics(s, tag);
@@ -260,7 +260,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
     char tag[20];
     
     i = (intptr_t) user_data;
-    snprintf(tag, sizeof(tag), "%c: Phase E:", i);
+    snprintf(tag, sizeof(tag), "%c: Phase E", i);
     printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result));    
     log_transfer_statistics(s, tag);
     log_tx_parameters(s, tag);
diff --git a/libs/spandsp/tests/v17_tests.c b/libs/spandsp/tests/v17_tests.c
index 22d793c2df..40d4a3de25 100644
--- a/libs/spandsp/tests/v17_tests.c
+++ b/libs/spandsp/tests/v17_tests.c
@@ -63,6 +63,7 @@ display of modem status is maintained.
 #include <sndfile.h>
 #include <signal.h>
 #if defined(HAVE_FENV_H)
+#define __USE_GNU
 #include <fenv.h>
 #endif
 
diff --git a/libs/spandsp/tests/v27ter_tests.c b/libs/spandsp/tests/v27ter_tests.c
index dc2053c692..d33953c318 100644
--- a/libs/spandsp/tests/v27ter_tests.c
+++ b/libs/spandsp/tests/v27ter_tests.c
@@ -62,6 +62,7 @@ display of modem status is maintained.
 #include <sndfile.h>
 #include <signal.h>
 #if defined(HAVE_FENV_H)
+#define __USE_GNU
 #include <fenv.h>
 #endif
 
diff --git a/libs/spandsp/tests/v29_tests.c b/libs/spandsp/tests/v29_tests.c
index 8644ac286d..72689a5288 100644
--- a/libs/spandsp/tests/v29_tests.c
+++ b/libs/spandsp/tests/v29_tests.c
@@ -62,6 +62,7 @@ display of modem status is maintained.
 #include <sndfile.h>
 #include <signal.h>
 #if defined(HAVE_FENV_H)
+#define __USE_GNU
 #include <fenv.h>
 #endif
 
diff --git a/libs/spandsp/tests/v42_tests.c b/libs/spandsp/tests/v42_tests.c
index 7968ff6199..3b6ca16c57 100644
--- a/libs/spandsp/tests/v42_tests.c
+++ b/libs/spandsp/tests/v42_tests.c
@@ -5,7 +5,7 @@
  *
  * Written by Steve Underwood <steveu@coppice.org>
  *
- * Copyright (C) 2004 Steve Underwood
+ * Copyright (C) 2004, 2011 Steve Underwood
  *
  * All rights reserved.
  *
@@ -32,10 +32,11 @@ then exchanged between them.
 */
 
 #if defined(HAVE_CONFIG_H)
-#include <config.h>
+#include "config.h"
 #endif
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
@@ -48,6 +49,7 @@ then exchanged between them.
 
 v42_state_t caller;
 v42_state_t answerer;
+int variable_length;
 
 int rx_next[3] = {0};
 int tx_next[3] = {0};
@@ -55,66 +57,120 @@ int tx_next[3] = {0};
 static void v42_status(void *user_data, int status)
 {
     int x;
-    
-    x = (intptr_t) user_data;
-    printf("%d: Status is '%s' (%d)\n", x, lapm_status_to_str(status), status);
-    //if (status == LAPM_DATA)
-    //    lapm_tx_iframe((x == 1)  ?  &caller.lapm  :  &answerer.lapm, "ABCDEFGHIJ", 10, 1);
-}
 
-static void v42_frames(void *user_data, const uint8_t *msg, int len)
+    x = (intptr_t) user_data;
+    if (status < 0)
+        printf("%d: Status is '%s' (%d)\n", x, signal_status_to_str(status), status);
+    else
+        printf("%d: Status is '%s' (%d)\n", x, lapm_status_to_str(status), status);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int v42_get_frames(void *user_data, uint8_t *msg, int len)
+{
+    int i;
+    int j;
+    int k;
+    int x;
+
+    if (len < 0)
+    {
+        v42_status(user_data, len);
+        return 0;
+    }
+    x = (intptr_t) user_data;
+    if (variable_length)
+    {
+        j = make_mask32(len);
+        do
+            k = j & rand();
+        while (k > len);
+    }
+    else
+    {
+        k = len;
+    }
+    for (i = 0;  i < k;  i++)
+        msg[i] = tx_next[x]++;
+    return k;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void v42_put_frames(void *user_data, const uint8_t *msg, int len)
 {
     int i;
     int x;
-    
+
+    if (len < 0)
+    {
+        v42_status(user_data, len);
+        return;
+    }
     x = (intptr_t) user_data;
     for (i = 0;  i < len;  i++)
     {
         if (msg[i] != (rx_next[x] & 0xFF))
+        {
             printf("%d: Mismatch 0x%02X 0x%02X\n", x, msg[i], rx_next[x] & 0xFF);
+            exit(2);
+        }
         rx_next[x]++;
     }
     printf("%d: Got frame len %d\n", x, len);
 }
+/*- End of function --------------------------------------------------------*/
 
 int main(int argc, char *argv[])
 {
     int i;
     int bit;
-    uint8_t buf[1024];
+    int insert_caller_bit_errors;
+    int insert_answerer_bit_errors;
+    int opt;
 
-    v42_init(&caller, TRUE, TRUE, v42_frames, (void *) 1);
-    v42_init(&answerer, FALSE, TRUE, v42_frames, (void *) 2);
+    insert_caller_bit_errors = FALSE;
+    insert_answerer_bit_errors = FALSE;
+    variable_length = FALSE;
+    while ((opt = getopt(argc, argv, "bv")) != -1)
+    {
+        switch (opt)
+        {
+        case 'b':
+            insert_caller_bit_errors = 11000;
+            insert_answerer_bit_errors = 10000;
+            break;
+        case 'v':
+            variable_length = TRUE;
+            break;
+        default:
+            //usage();
+            exit(2);
+            break;
+        }
+    }
+
+    v42_init(&caller, TRUE, TRUE, v42_get_frames, v42_put_frames, (void *) 1);
+    v42_init(&answerer, FALSE, TRUE, v42_get_frames, v42_put_frames, (void *) 2);
     v42_set_status_callback(&caller, v42_status, (void *) 1);
     v42_set_status_callback(&answerer, v42_status, (void *) 2);
-    span_log_set_level(&caller.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG);
+    v42_restart(&caller);
+    v42_restart(&answerer);
+
+    span_log_set_level(&caller.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_DEBUG);
     span_log_set_tag(&caller.logging, "caller");
-    span_log_set_level(&caller.lapm.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG);
-    span_log_set_tag(&caller.lapm.logging, "caller");
-    span_log_set_level(&caller.lapm.sched.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG);
-    span_log_set_tag(&caller.lapm.sched.logging, "caller");
-    span_log_set_level(&answerer.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG);
+    span_log_set_level(&answerer.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_DEBUG);
     span_log_set_tag(&answerer.logging, "answerer");
-    span_log_set_level(&answerer.lapm.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG);
-    span_log_set_tag(&answerer.lapm.logging, "answerer");
-    span_log_set_level(&answerer.lapm.sched.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG);
-    span_log_set_tag(&answerer.lapm.sched.logging, "answerer");
-    for (i = 0;  i < 100000;  i++)
+
+    for (i = 0;  i < 1000000;  i++)
     {
         bit = v42_tx_bit(&caller);
+        if (insert_caller_bit_errors  &&  i%insert_caller_bit_errors == 0)
+            bit ^= 1;
         v42_rx_bit(&answerer, bit);
         bit = v42_tx_bit(&answerer);
-        //if (i%10000 == 0)
-        //    bit ^= 1;
+        if (insert_answerer_bit_errors  &&  i%insert_answerer_bit_errors == 0)
+            bit ^= 1;
         v42_rx_bit(&caller, bit);
-        span_schedule_update(&caller.lapm.sched, 4);
-        span_schedule_update(&answerer.lapm.sched, 4);
-        buf[0] = tx_next[1];
-        if (lapm_tx(&caller.lapm, buf, 1) == 1)
-            tx_next[1]++;
-        buf[0] = tx_next[2];
-        if (lapm_tx(&answerer.lapm, buf, 1) == 1)
-            tx_next[2]++;
     }
     return  0;
 }
diff --git a/libs/spandsp/tests/v42bis_tests.c b/libs/spandsp/tests/v42bis_tests.c
index 2218d1a94b..e59d80711b 100644
--- a/libs/spandsp/tests/v42bis_tests.c
+++ b/libs/spandsp/tests/v42bis_tests.c
@@ -34,7 +34,7 @@ of this file should exactly match the original file.
 */
 
 #if defined(HAVE_CONFIG_H)
-#include <config.h>
+#include "config.h"
 #endif
 
 #include <stdlib.h>
@@ -46,12 +46,14 @@ of this file should exactly match the original file.
 #include <ctype.h>
 #include <assert.h>
 
+//#if defined(WITH_SPANDSP_INTERNALS)
+#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
+//#endif
+
 #include "spandsp.h"
 
-#include "spandsp/private/v42bis.h"
-
 #define COMPRESSED_FILE_NAME        "v42bis_tests.v42bis"
-#define OUTPUT_FILE_NAME            "v42bis_tests.out"
+#define DECOMPRESSED_FILE_NAME      "v42bis_tests.out"
 
 int in_octets_to_date = 0;
 int out_octets_to_date = 0;
@@ -85,36 +87,96 @@ int main(int argc, char *argv[])
     int out_fd;
     int do_compression;
     int do_decompression;
+    int stutter_compression;
+    int stutter_time;
+    int seg;
+    int opt;
     time_t now;
+    const char *argv0;
+    const char *original_file;
+    const char *compressed_file;
+    const char *decompressed_file;
 
-    do_compression = TRUE;
-    do_decompression = TRUE;
-    if (argc < 2)
+    argv0 = argv[0];
+    do_compression = FALSE;
+    do_decompression = FALSE;
+    stutter_compression = FALSE;
+    while ((opt = getopt(argc, argv, "cds")) != -1)
     {
-        fprintf(stderr, "Usage: %s <file>\n", argv[0]);
+        switch (opt)
+        {
+        case 'c':
+            do_compression = TRUE;
+            break;
+        case 'd':
+            do_decompression = TRUE;
+            break;
+        case 's':
+            stutter_compression = TRUE;
+            break;
+        default:
+            //usage();
+            exit(2);
+            break;
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc < 1)
+    {
+        fprintf(stderr, "Usage: %s [-c] [-d] [-s] <in-file> [<out-file>]\n", argv0);
         exit(2);
     }
     if (do_compression)
     {
-        if ((in_fd = open(argv[1], O_RDONLY)) < 0)
+        original_file = argv[0];
+        compressed_file = COMPRESSED_FILE_NAME;
+    }
+    else
+    {
+        original_file = NULL;
+        compressed_file = argv[0];
+    }
+    decompressed_file = (argc > 1)  ?  argv[1]  :  DECOMPRESSED_FILE_NAME;
+    if (do_compression)
+    {
+        stutter_time = rand() & 0x3FF;
+        if ((in_fd = open(argv[0], O_RDONLY)) < 0)
         {
-            fprintf(stderr, "Error opening file '%s'.\n", argv[1]);
+            fprintf(stderr, "Error opening file '%s'.\n", original_file);
             exit(2);
         }
-        if ((v42bis_fd = open(COMPRESSED_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
+        if ((v42bis_fd = open(compressed_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
         {
-            fprintf(stderr, "Error opening file '%s'.\n", COMPRESSED_FILE_NAME);
+            fprintf(stderr, "Error opening file '%s'.\n", compressed_file);
             exit(2);
         }
 
         time(&now);
         v42bis_init(&state_a, 3, 512, 6, frame_handler, (void *) (intptr_t) v42bis_fd, 512, data_handler, NULL, 512);
-        v42bis_compression_control(&state_a, V42BIS_COMPRESSION_MODE_ALWAYS);
+        span_log_set_level(&state_a.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+        span_log_set_tag(&state_a.logging, "XXX");
+        //v42bis_compression_control(&state_a, V42BIS_COMPRESSION_MODE_ALWAYS);
         in_octets_to_date = 0;
         out_octets_to_date = 0;
         while ((len = read(in_fd, buf, 1024)) > 0)
         {
-            if (v42bis_compress(&state_a, buf, len))
+            seg = 0;
+            if (stutter_compression)
+            {
+                while ((len - seg) >= stutter_time)
+                {
+                    if (v42bis_compress(&state_a, buf + seg, stutter_time))
+                    {
+                        fprintf(stderr, "Bad return code from compression\n");
+                        exit(2);
+                    }
+                    v42bis_compress_flush(&state_a);
+                    seg += stutter_time;
+                    stutter_time = rand() & 0x3FF;
+                }
+            }
+            if (v42bis_compress(&state_a, buf + seg, len - seg))
             {
                 fprintf(stderr, "Bad return code from compression\n");
                 exit(2);
@@ -130,19 +192,21 @@ int main(int argc, char *argv[])
     if (do_decompression)
     {
         /* Now open the files for the decompression. */
-        if ((v42bis_fd = open(COMPRESSED_FILE_NAME, O_RDONLY)) < 0)
+        if ((v42bis_fd = open(compressed_file, O_RDONLY)) < 0)
         {
-            fprintf(stderr, "Error opening file '%s'.\n", COMPRESSED_FILE_NAME);
+            fprintf(stderr, "Error opening file '%s'.\n", compressed_file);
             exit(2);
         }
-        if ((out_fd = open(OUTPUT_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
+        if ((out_fd = open(decompressed_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
         {
-            fprintf(stderr, "Error opening file '%s'.\n", OUTPUT_FILE_NAME);
+            fprintf(stderr, "Error opening file '%s'.\n", decompressed_file);
             exit(2);
         }
     
         time(&now);
         v42bis_init(&state_b, 3, 512, 6, frame_handler, (void *) (intptr_t) v42bis_fd, 512, data_handler, (void *) (intptr_t) out_fd, 512);
+        span_log_set_level(&state_b.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+        span_log_set_tag(&state_b.logging, "XXX");
         in_octets_to_date = 0;
         out_octets_to_date = 0;
         while ((len = read(v42bis_fd, buf, 1024)) > 0)
diff --git a/libs/spandsp/tests/v42bis_tests.sh b/libs/spandsp/tests/v42bis_tests.sh
index 39ae75e0df..fa86645785 100755
--- a/libs/spandsp/tests/v42bis_tests.sh
+++ b/libs/spandsp/tests/v42bis_tests.sh
@@ -17,7 +17,7 @@
 
 BASE=../test-data/itu/v56ter
 
-./v42bis_tests ${BASE}/1.TST
+./v42bis_tests -c -d ${BASE}/1.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -29,7 +29,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/1X04.TST
+./v42bis_tests -c -d ${BASE}/1X04.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -41,7 +41,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/1X30.TST
+./v42bis_tests -c -d ${BASE}/1X30.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -53,7 +53,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/2.TST
+./v42bis_tests -c -d ${BASE}/2.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -65,8 +65,9 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/2X10.TST
+./v42bis_tests -c -d ${BASE}/2X10.TST
 RETVAL=$?
+
 if [ $RETVAL != 0 ]
 then
     exit $RETVAL
@@ -77,7 +78,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/3.TST
+./v42bis_tests -c -d ${BASE}/3.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -89,7 +90,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/3X06.TST
+./v42bis_tests -c -d ${BASE}/3X06.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -101,7 +102,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/4.TST
+./v42bis_tests -c -d ${BASE}/4.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -113,7 +114,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/4X04.TST
+./v42bis_tests -c -d ${BASE}/4X04.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -125,7 +126,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/5.TST
+./v42bis_tests -c -d ${BASE}/5.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
@@ -137,7 +138,7 @@ if [ $RETVAL != 0 ]
 then
     exit $RETVAL
 fi
-./v42bis_tests ${BASE}/5X16.TST
+./v42bis_tests -c -d ${BASE}/5X16.TST
 RETVAL=$?
 if [ $RETVAL != 0 ]
 then
diff --git a/libs/spandsp/unpack_gsm0610_data.sh b/libs/spandsp/unpack_gsm0610_data.sh
index 482334c79e..d1f8b92a23 100755
--- a/libs/spandsp/unpack_gsm0610_data.sh
+++ b/libs/spandsp/unpack_gsm0610_data.sh
@@ -53,7 +53,7 @@ else
     cd gsm0610
 fi
 
-if [ $1x =  --no-exe-runx ]
+if [ $1x ==  --no-exe-runx ]
 then
     # Run the .exe files, which should be here
     ./FR_A.EXE
@@ -77,7 +77,7 @@ rm -rf READ_FRA.TXT
 rm -rf ACTION
 rm -rf unpacked
 
-if [ $1x =  --no-exex ]
+if [ $1x ==  --no-exex ]
 then
     # We need to prepare the .exe files to be run separately
     rm -rf *.INP
diff --git a/libs/spandsp/wrapper.xsl b/libs/spandsp/wrapper.xsl
index 89e314d781..2f432262b3 100644
--- a/libs/spandsp/wrapper.xsl
+++ b/libs/spandsp/wrapper.xsl
@@ -2,4 +2,4 @@
                 version='1.0'>
   <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
   <xsl:param name="html.stylesheet">css.css</xsl:param>
-</xsl:stylesheet>
\ No newline at end of file
+</xsl:stylesheet>