From 73f83d533ba8d929a840ab76efb099da4d5b6174 Mon Sep 17 00:00:00 2001 From: Philipp Date: Fri, 2 Sep 2016 13:38:01 +0200 Subject: [PATCH] SNDCP: add V.42bis data compression functionality - Add compression control for V.42bis Add code to handle compression (gprs_sndcp_dcomp.c/h) - Add Adjustments in SNDCP - Add VTY commands Change-Id: I6d36cbdf2f5c5f83ca9ba57c70452f02b8582e7e --- openbsc/include/openbsc/Makefile.am | 1 + openbsc/include/openbsc/gprs_sndcp_dcomp.h | 53 +++ openbsc/include/openbsc/sgsn.h | 9 + openbsc/src/gprs/Makefile.am | 1 + openbsc/src/gprs/gprs_sndcp.c | 87 ++++- openbsc/src/gprs/gprs_sndcp_comp.c | 12 +- openbsc/src/gprs/gprs_sndcp_dcomp.c | 357 +++++++++++++++++++++ openbsc/src/gprs/sgsn_main.c | 5 + openbsc/src/gprs/sgsn_vty.c | 77 ++++- openbsc/tests/sgsn/Makefile.am | 1 + 10 files changed, 585 insertions(+), 18 deletions(-) create mode 100644 openbsc/include/openbsc/gprs_sndcp_dcomp.h create mode 100644 openbsc/src/gprs/gprs_sndcp_dcomp.c diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 3014d5fa1..c6a01499f 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -26,6 +26,7 @@ noinst_HEADERS = \ gprs_sgsn.h \ gprs_sndcp.h \ gprs_sndcp_comp.h \ + gprs_sndcp_dcomp.h \ gprs_sndcp_pcomp.h \ gprs_sndcp_xid.h \ gprs_utils.h \ diff --git a/openbsc/include/openbsc/gprs_sndcp_dcomp.h b/openbsc/include/openbsc/gprs_sndcp_dcomp.h new file mode 100644 index 000000000..a76b4a4b3 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sndcp_dcomp.h @@ -0,0 +1,53 @@ +/* GPRS SNDCP data compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +/* Note: The decompressed packet may have a maximum size of: + * Return value * MAX_DATADECOMPR_FAC */ +#define MAX_DATADECOMPR_FAC 10 + +/* Note: In unacknowledged mode (SN_UNITDATA), the comression state is reset + * for every NPDU. The compressor needs a reasonably large payload to operate + * effectively (yield positive compression gain). For packets shorter than 100 + * byte, no positive compression gain can be expected so we will skip the + * compression for short packets. */ +#define MIN_COMPR_PAYLOAD 100 + +/* Initalize data compression */ +int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate data compression */ +void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet */ +int gprs_sndcp_dcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet */ +int gprs_sndcp_dcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 9537c0afc..786e2b240 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -100,6 +100,15 @@ struct sgsn_config { int passive; int s01; } pcomp_rfc1144; + + /* V.42vis data compression */ + struct { + int active; + int passive; + int p0; + int p1; + int p2; + } dcomp_v42bis; }; struct sgsn_instance { diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 3970ba6dd..d228b397a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -72,6 +72,7 @@ osmo_sgsn_SOURCES = \ gprs_sgsn.c \ gprs_sndcp.c \ gprs_sndcp_comp.c \ + gprs_sndcp_dcomp.c \ gprs_sndcp_pcomp.c \ gprs_sndcp_vty.c \ gprs_sndcp_xid.c \ diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c index c006d9bcf..0b18f816e 100644 --- a/openbsc/src/gprs/gprs_sndcp.c +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */ @@ -204,7 +205,8 @@ LLIST_HEAD(gprs_sndcp_entities); /* Check if any compression parameters are set in the sgsn configuration */ static inline int any_pcomp_or_dcomp_active(struct sgsn_instance *sgsn) { - if (sgsn->cfg.pcomp_rfc1144.active || sgsn->cfg.pcomp_rfc1144.passive) + if (sgsn->cfg.pcomp_rfc1144.active || sgsn->cfg.pcomp_rfc1144.passive || + sgsn->cfg.dcomp_v42bis.active || sgsn->cfg.dcomp_v42bis.passive) return true; else return false; @@ -324,11 +326,22 @@ static int defrag_segments(struct gprs_sndcp_entity *sne) #endif if (any_pcomp_or_dcomp_active(sgsn)) { - expnd = talloc_zero_size(msg, npdu_len + MAX_HDRDECOMPR_INCR); + expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC + + MAX_HDRDECOMPR_INCR); memcpy(expnd, npdu, npdu_len); + /* Apply data decompression */ + rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp, + sne->defrag.data); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "Data decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } + /* Apply header decompression */ - rc = gprs_sndcp_pcomp_expand(expnd, npdu_len, sne->defrag.pcomp, + rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, sne->defrag.proto); if (rc < 0) { LOGP(DSNDCP, LOGL_ERROR, @@ -653,6 +666,19 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi * the new, compressed buffer size */ msgb_get(msg, msg->len); msgb_put(msg, rc); + + /* Apply data compression */ + rc = gprs_sndcp_dcomp_compress(msg->data, msg->len, &dcomp, + lle->llme->comp.data, nsapi); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, "Data compression failed!\n"); + return -EIO; + } + + /* Fixup pointer locations and sizes in message buffer to match + * the new, compressed buffer size */ + msgb_get(msg, msg->len); + msgb_put(msg, rc); } #if DEBUG_IP_PACKETS == 1 DEBUGP(DSNDCP, "===================================================\n"); @@ -784,11 +810,22 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, #endif if (any_pcomp_or_dcomp_active(sgsn)) { - expnd = talloc_zero_size(msg, npdu_len + MAX_HDRDECOMPR_INCR); + expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC + + MAX_HDRDECOMPR_INCR); memcpy(expnd, npdu, npdu_len); + /* Apply data decompression */ + rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp, + sne->defrag.data); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "Data decompression failed!\n"); + talloc_free(expnd); + return -EIO; + } + /* Apply header decompression */ - rc = gprs_sndcp_pcomp_expand(expnd, npdu_len, sne->defrag.pcomp, + rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, sne->defrag.proto); if (rc < 0) { LOGP(DSNDCP, LOGL_ERROR, @@ -884,8 +921,11 @@ static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi) LLIST_HEAD(comp_fields); struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; struct gprs_sndcp_comp_field rfc1144_comp_field; + struct gprs_sndcp_dcomp_v42bis_params v42bis_params; + struct gprs_sndcp_comp_field v42bis_comp_field; memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); + memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); /* Setup rfc1144 */ if (sgsn->cfg.pcomp_rfc1144.active) { @@ -903,6 +943,23 @@ static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi) llist_add(&rfc1144_comp_field.list, &comp_fields); } + /* Setup V.42bis */ + if (sgsn->cfg.dcomp_v42bis.active) { + v42bis_params.nsapi[0] = nsapi; + v42bis_params.nsapi_len = 1; + v42bis_params.p0 = sgsn->cfg.dcomp_v42bis.p0; + v42bis_params.p1 = sgsn->cfg.dcomp_v42bis.p1; + v42bis_params.p2 = sgsn->cfg.dcomp_v42bis.p2; + v42bis_comp_field.p = 1; + v42bis_comp_field.entity = entity; + v42bis_comp_field.algo = V42BIS; + v42bis_comp_field.comp[V42BIS_DCOMP1] = 1; + v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; + v42bis_comp_field.v42bis_params = &v42bis_params; + entity++; + llist_add(&v42bis_comp_field.list, &comp_fields); + } + /* Compile bytestream */ return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields); } @@ -1008,13 +1065,19 @@ static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, /* Process proposed parameters */ switch (comp_field->algo) { case V42BIS: - /* V42BIS is not yet supported, - * so we set applicable nsapis to zero */ - LOGP(DSNDCP, LOGL_DEBUG, - "Rejecting V.42bis data compression...\n"); - comp_field->v42bis_params->nsapi_len = 0; - gprs_sndcp_comp_delete(lle->llme->comp.data, - comp_field->entity); + if (sgsn->cfg.dcomp_v42bis.passive && + comp_field->v42bis_params->nsapi_len > 0) { + DEBUGP(DSNDCP, + "Accepting V.42bis data compression...\n"); + gprs_sndcp_comp_add(lle->llme, lle->llme->comp.data, + comp_field); + } else { + LOGP(DSNDCP, LOGL_DEBUG, + "Rejecting V.42bis data compression...\n"); + gprs_sndcp_comp_delete(lle->llme->comp.data, + comp_field->entity); + comp_field->v42bis_params->nsapi_len = 0; + } break; case V44: /* V44 is not yet supported, diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c index 1a9d030bc..b13cb8b23 100644 --- a/openbsc/src/gprs/gprs_sndcp_comp.c +++ b/openbsc/src/gprs/gprs_sndcp_comp.c @@ -34,6 +34,7 @@ #include #include #include +#include /* Create a new compression entity from a XID-Field */ static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, @@ -100,16 +101,16 @@ static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx, comp_entity = NULL; } } else { - LOGP(DSNDCP, LOGL_ERROR, - "We don't support data compression yet!\n"); - talloc_free(comp_entity); - return NULL; + if (gprs_sndcp_dcomp_init(ctx, comp_entity, comp_field) != 0) { + talloc_free(comp_entity); + comp_entity = NULL; + } } /* Display info message */ if (comp_entity == NULL) { LOGP(DSNDCP, LOGL_ERROR, - "Header compression entity (%d) creation failed!\n", + "Compression entity (%d) creation failed!\n", comp_entity->entity); return NULL; } @@ -159,6 +160,7 @@ void gprs_sndcp_comp_free(struct llist_head *comp_entities) LOGP(DSNDCP, LOGL_INFO, "Deleting data compression entity %d ...\n", comp_entity->entity); + gprs_sndcp_dcomp_term(comp_entity); } } diff --git a/openbsc/src/gprs/gprs_sndcp_dcomp.c b/openbsc/src/gprs/gprs_sndcp_dcomp.c new file mode 100644 index 000000000..489106b47 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_dcomp.c @@ -0,0 +1,357 @@ +/* GPRS SNDCP data compression handler */ + +/* (C) 2016 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* A struct to capture the output data of compressor and decompressor */ +struct v42bis_output_buffer { + uint8_t *buf; + uint8_t *buf_pointer; + int len; +}; + +/* Handler to capture the output data from the compressor */ +void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, pkt, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Handler to capture the output data from the decompressor */ +void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) +{ + struct v42bis_output_buffer *output_buffer = + (struct v42bis_output_buffer *)user_data; + memcpy(output_buffer->buf_pointer, buf, len); + output_buffer->buf_pointer += len; + output_buffer->len += len; + return; +} + +/* Initalize data compression */ +int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a new data compression + * entity is created by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + OSMO_ASSERT(comp_field); + + if (comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION + && comp_entity->algo == V42BIS) { + comp_entity->state = + v42bis_init(ctx, NULL, comp_field->v42bis_params->p0, + comp_field->v42bis_params->p1, + comp_field->v42bis_params->p2, + &tx_v42bis_frame_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH, + &rx_v42bis_data_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH); + LOGP(DSNDCP, LOGL_INFO, + "V.42bis data compression initalized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * data compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate data compression */ +void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a data compression + * entity is deleted by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + + if (comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION + && comp_entity->algo == V42BIS) { + if (comp_entity->state) { + v42bis_free((v42bis_state_t *) comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "V.42bis data compression terminated.\n"); + return; + } + + /* Just in case someone tries to terminate an unknown or unsupported + * data compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Perform a full reset of the V.42bis compression state */ +static void v42bis_reset(v42bis_state_t *comp) +{ + /* This function performs a complete reset of the V.42bis compression + * state by reinitalizing the state withe the previously negotiated + * parameters. */ + + int p0, p1, p2; + p0 = comp->decompress.v42bis_parm_p0 | comp->compress.v42bis_parm_p0; + p1 = comp->decompress.v42bis_parm_n2; + p2 = comp->decompress.v42bis_parm_n7; + + DEBUGP(DSNDCP, "Resetting compression state: %p, p0=%d, p1=%d, p2=%d\n", + comp, p0, p1, p2); + + v42bis_init(NULL, comp, p0, p1, p2, &tx_v42bis_frame_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH, &rx_v42bis_data_handler, NULL, + V42BIS_MAX_OUTPUT_LENGTH); +} + +/* Compress a packet using V.42bis data compression */ +static int v42bis_compress_unitdata(uint8_t *pcomp_index, uint8_t *data, + unsigned int len, v42bis_state_t *comp) +{ + /* Note: This implementation may only be used to compress SN_UNITDATA + * packets, since it resets the compression state for each NPDU. */ + + uint8_t *data_o; + int rc; + int skip = 0; + struct v42bis_output_buffer compressed_data; + + /* Don't bother with short packets */ + if (len < MIN_COMPR_PAYLOAD) + skip = 1; + + /* Skip if compression is not enabled for TX direction */ + if (!comp->compress.v42bis_parm_p0) + skip = 1; + + /* Skip compression */ + if (skip) { + *pcomp_index = 0; + return len; + } + + /* Reset V.42bis compression state */ + v42bis_reset(comp); + + /* Run compressor */ + data_o = talloc_zero_size(comp, len * MAX_DATADECOMPR_FAC); + compressed_data.buf = data_o; + compressed_data.buf_pointer = data_o; + compressed_data.len = 0; + comp->compress.user_data = (&compressed_data); + rc = v42bis_compress(comp, data, len); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "Data compression failed, skipping...\n"); + skip = 1; + } + rc = v42bis_compress_flush(comp); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "Data compression failed, skipping...\n"); + skip = 1; + } + + /* The compressor might yield negative compression gain, in + * this case, we just decide to send the packat as normal, + * uncompressed payload => skip compresssion */ + if (compressed_data.len >= len) { + LOGP(DSNDCP, LOGL_ERROR, + "Data compression ineffective, skipping...\n"); + skip = 1; + } + + /* Skip compression */ + if (skip) { + *pcomp_index = 0; + talloc_free(data_o); + return len; + } + + *pcomp_index = 1; + memcpy(data, data_o, compressed_data.len); + talloc_free(data_o); + + return compressed_data.len; +} + +/* Expand a packet using V.42bis data compression */ +static int v42bis_expand_unitdata(uint8_t *data, unsigned int len, + uint8_t pcomp_index, v42bis_state_t *comp) +{ + /* Note: This implementation may only be used to compress SN_UNITDATA + * packets, since it resets the compression state for each NPDU. */ + + int rc; + struct v42bis_output_buffer uncompressed_data; + uint8_t *data_i; + + /* Skip when the packet is marked as uncompressed */ + if (pcomp_index == 0) { + return len; + } + + /* Reset V.42bis compression state */ + v42bis_reset(comp); + + /* Decompress packet */ + data_i = talloc_zero_size(comp, len); + memcpy(data_i, data, len); + uncompressed_data.buf = data; + uncompressed_data.buf_pointer = data; + uncompressed_data.len = 0; + comp->decompress.user_data = (&uncompressed_data); + rc = v42bis_decompress(comp, data_i, len); + talloc_free(data_i); + if (rc < 0) + return -EINVAL; + rc = v42bis_decompress_flush(comp); + if (rc < 0) + return -EINVAL; + + return uncompressed_data.len; +} + +/* Expand packet */ +int gprs_sndcp_dcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data compression entity list: comp_entities=%p\n", comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Data compression mode: dcomp=%d\n", pcomp); + + /* Skip on pcomp=0 */ + if (pcomp == 0) { + return len; + } + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + return len; + } + + /* Note: Only data compression entities may appear in + * data compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION); + + /* Note: Currently V42BIS is the only compression method we + * support, so the only allowed algorithm is V42BIS */ + OSMO_ASSERT(comp_entity->algo == V42BIS); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = v42bis_expand_unitdata(data, len, pcomp_index, comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} + +/* Compress packet */ +int gprs_sndcp_dcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi) +{ + int rc; + uint8_t pcomp_index = 0; + struct gprs_sndcp_comp *comp_entity; + + OSMO_ASSERT(data); + OSMO_ASSERT(pcomp); + OSMO_ASSERT(comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data compression entity list: comp_entities=%p\n", comp_entities); + + /* Find out which compression entity handles the data */ + comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi); + + /* Skip compression if no suitable compression entity can be found */ + if (!comp_entity) { + *pcomp = 0; + return len; + } + + /* Note: Only data compression entities may appear in + * data compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION); + + /* Note: Currently V42BIS is the only compression method we + * support, so the only allowed algorithm is V42BIS */ + OSMO_ASSERT(comp_entity->algo == V42BIS); + + /* Run compression algo */ + rc = v42bis_compress_unitdata(&pcomp_index, data, len, + comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, "Data compression mode: dcomp=%d\n", *pcomp); + + LOGP(DSNDCP, LOGL_DEBUG, + "Data compression done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 9f3260d55..fb5b6d585 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -299,6 +299,11 @@ static struct log_info_cat gprs_categories[] = { .description = "RFC1144 TCP/IP Header compression (SLHC)", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DV42BIS] = { + .name = "DV42BIS", + .description = "V.42bis data compression (SNDCP)", + .enabled = 1, .loglevel = LOGL_DEBUG, + } }; static const struct log_info gprs_log_info = { diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index 0eea35029..1b477e524 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -277,6 +277,26 @@ static int config_write_sgsn(struct vty *vty) } else vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); + if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) { + vty_out(vty, + " compression v42bis active direction sgsn codewords %d strlen %d%s", + g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, + VTY_NEWLINE); + } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) { + vty_out(vty, + " compression v42bis active direction ms codewords %d strlen %d%s", + g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, + VTY_NEWLINE); + } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) { + vty_out(vty, + " compression v42bis active direction both codewords %d strlen %d%s", + g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, + VTY_NEWLINE); + } else if (g_cfg->dcomp_v42bis.passive) { + vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE); + } else + vty_out(vty, " no compression v42bis%s", VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1117,6 +1137,59 @@ DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd, return CMD_SUCCESS; } +DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd, + "no compression v42bis", + NO_STR COMPRESSION_STR "disable V.42bis data compression\n") +{ + g_cfg->dcomp_v42bis.active = 0; + g_cfg->dcomp_v42bis.passive = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd, + "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>", + COMPRESSION_STR + "V.42bis data compresion scheme\n" + "Compression is actively proposed\n" + "Direction in which the compression shall be active (p0)\n" + "Compress ms->sgsn direction only\n" + "Compress sgsn->ms direction only\n" + "Both directions\n" + "Number of codewords (p1)\n" + "Number of codewords\n" + "Maximum string length (p2)\n" "Maximum string length\n") +{ + g_cfg->dcomp_v42bis.active = 1; + g_cfg->dcomp_v42bis.passive = 1; + + switch (argv[0][0]) { + case 'm': + g_cfg->dcomp_v42bis.p0 = 1; + break; + case 's': + g_cfg->dcomp_v42bis.p0 = 2; + break; + case 'b': + g_cfg->dcomp_v42bis.p0 = 3; + break; + } + + g_cfg->dcomp_v42bis.p1 = atoi(argv[1]); + g_cfg->dcomp_v42bis.p2 = atoi(argv[2]); + return CMD_SUCCESS; +} + +DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd, + "compression v42bis passive", + COMPRESSION_STR + "V.42bis data compresion scheme\n" + "Compression is available on request\n") +{ + g_cfg->dcomp_v42bis.active = 0; + g_cfg->dcomp_v42bis.passive = 1; + return CMD_SUCCESS; +} + int sgsn_vty_init(void) { install_element_ve(&show_sgsn_cmd); @@ -1174,7 +1247,9 @@ int sgsn_vty_init(void) install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd); - + install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd); + install_element(SGSN_NODE, &cfg_comp_v42bis_cmd); + install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd); return 0; } diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 92506323c..9ee5455e7 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -62,6 +62,7 @@ sgsn_test_LDADD = \ $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ $(top_builddir)/src/gprs/v42bis.o \ + $(top_builddir)/src/gprs/gprs_sndcp_dcomp.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \