aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs/v42bis.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gprs/v42bis.c')
-rw-r--r--src/gprs/v42bis.c767
1 files changed, 0 insertions, 767 deletions
diff --git a/src/gprs/v42bis.c b/src/gprs/v42bis.c
deleted file mode 100644
index a04b0af5c..000000000
--- a/src/gprs/v42bis.c
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * v42bis.c
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2005, 2011 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.
- */
-
-/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED.
- Currently it performs the core compression and decompression functions OK.
- However, a number of the bells and whistles in V.42bis are incomplete. */
-
-/*! \file */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include <openbsc/v42bis.h>
-#include <openbsc/v42bis_private.h>
-#include <openbsc/debug.h>
-#include <osmocom/core/talloc.h>
-
-
-#define span_log(x,y,msg, ...) DEBUGP(DV42BIS,msg, ##__VA_ARGS__)
-#define span_log_init(x,y,z)
-#define span_log_set_protocol(x,y)
-
-
-#define FALSE 0
-#define TRUE 1
-
-/* Fixed parameters from the spec. */
-/* 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
-
-/* 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
-{
- V42BIS_ETM = 0, /* Enter transparent mode */
- V42BIS_FLUSH = 1, /* Flush data */
- V42BIS_STEPUP = 2 /* Step up codeword size */
-};
-
-/* Command codes in transparent mode */
-enum
-{
- V42BIS_ECM = 0, /* Enter compression mode */
- V42BIS_EID = 1, /* Escape character in data */
- V42BIS_RESET = 2 /* Force reinitialisation */
-};
-
-static __inline__ void push_octet(v42bis_comp_state_t *s, int octet)
-{
- s->output_buf[s->output_octet_count++] = (uint8_t) octet;
- if (s->output_octet_count >= s->max_output_len)
- {
- s->handler(s->user_data, s->output_buf, s->output_octet_count);
- s->output_octet_count = 0;
- }
-}
-/*- End of function --------------------------------------------------------*/
-
-static __inline__ void push_octets(v42bis_comp_state_t *s, const uint8_t buf[], int len)
-{
- int i;
- int chunk;
-
- 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 */
- push_octets(s, buf, len);
- return 0;
- }
- for (i = 0; i < len; )
- {
- /* 6.4 Add the string to the dictionary */
- if (s->update_at)
- {
- 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;
- }
- /* Match string */
- while (i < len)
- {
- code = match_octet(s, s->last_matched, buf[i]);
- if (code == 0)
- {
- 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 *ss)
-{
- v42bis_comp_state_t *s;
- int len;
-
- s = &ss->compress;
- if (s->update_at)
- return 0;
- if (s->last_matched)
- {
- 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 --------------------------------------------------------*/
-
-SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int len)
-{
- v42bis_comp_state_t *s;
- int i;
- int j;
- int yyy;
- uint16_t code;
- uint16_t p;
- uint8_t ch;
- uint8_t in;
-
- s = &ss->decompress;
- if (!s->v42bis_parm_p0)
- {
- /* Compression is off - just push the incoming data out */
- push_octets(s, buf, len);
- return 0;
- }
- for (i = 0; i < len; )
- {
- if (s->transparent)
- {
- in = buf[i];
- if (s->escaped)
- {
- /* Command */
- s->escaped = FALSE;
- switch (in)
- {
- case V42BIS_ECM:
- /* 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:
- /* 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:
- /* Reset dictionary */
- span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n");
- /* TODO: */
- send_string(s);
- dictionary_init(s);
- i++;
- continue;
- default:
- span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in);
- return -1;
- }
- }
- else if (in == s->escape_code)
- {
- s->escaped = TRUE;
- i++;
- continue;
- }
-
- yyy = TRUE;
- for (j = 0; j < 2 && yyy; j++)
- {
- if (s->update_at)
- {
- 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
- {
- /* 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 (code)
- {
- case V42BIS_ETM:
- /* 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:
- /* Flush signal */
- span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n");
- s->bit_count = 0;
- break;
- case V42BIS_STEPUP:
- /* 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;
- break;
- }
- continue;
- }
- /* Regular codeword */
- if (code == s->v42bis_parm_c1)
- return -1;
- expand_codeword_to_string(s, code);
- if (s->update_at)
- {
- ch = s->string[0];
- if ((p = match_octet(s, s->update_at, ch)) == 0)
- {
- 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;
- }
- }
- 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 *ss)
-{
- v42bis_comp_state_t *s;
- int len;
-
- s = &ss->decompress;
- len = s->string_length;
- send_string(s);
- s->flushed_length += len;
- flush_octets(s);
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode)
-{
- s->compress.compression_mode = mode;
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx,
- v42bis_state_t *s,
- int negotiated_p0,
- int negotiated_p1,
- int negotiated_p2,
- 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 ret;
-
- if (negotiated_p1 < V42BIS_MIN_DICTIONARY_SIZE || negotiated_p1 > 65535)
- return NULL;
- if (negotiated_p2 < V42BIS_MIN_STRING_SIZE || negotiated_p2 > V42BIS_MAX_STRING_SIZE)
- return NULL;
- if (s == NULL)
- {
- if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL)
- return NULL;
- }
- memset(s, 0, sizeof(*s));
- span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
- span_log_set_protocol(&s->logging, "V.42bis");
-
- 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)))
- {
- comp_exit(&s->compress);
- return NULL;
- }
- s->compress.v42bis_parm_p0 = negotiated_p0 & 2;
- s->decompress.v42bis_parm_p0 = negotiated_p0 & 1;
-
- return s;
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s)
-{
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
-SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s)
-{
- comp_exit(&s->compress);
- comp_exit(&s->decompress);
- talloc_free(s);
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
-/*- End of file ------------------------------------------------------------*/