diff options
Diffstat (limited to 'openbsc/src/gprs/v42bis.c')
-rw-r--r-- | openbsc/src/gprs/v42bis.c | 767 |
1 files changed, 0 insertions, 767 deletions
diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c deleted file mode 100644 index a04b0af5c..000000000 --- a/openbsc/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 ------------------------------------------------------------*/ |