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
This commit is contained in:
parent
d8b45778de
commit
73f83d533b
|
@ -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 \
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/* GPRS SNDCP data compression handler */
|
||||
|
||||
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <openbsc/gprs_sndcp_comp.h>
|
||||
|
||||
/* 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);
|
|
@ -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 {
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <openbsc/gprs_llc_xid.h>
|
||||
#include <openbsc/gprs_sndcp_xid.h>
|
||||
#include <openbsc/gprs_sndcp_pcomp.h>
|
||||
#include <openbsc/gprs_sndcp_dcomp.h>
|
||||
#include <openbsc/gprs_sndcp_comp.h>
|
||||
|
||||
#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,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <openbsc/gprs_sndcp_xid.h>
|
||||
#include <openbsc/gprs_sndcp_comp.h>
|
||||
#include <openbsc/gprs_sndcp_pcomp.h>
|
||||
#include <openbsc/gprs_sndcp_dcomp.h>
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/gsm/tlv.h>
|
||||
|
||||
#include <openbsc/gprs_llc.h>
|
||||
#include <openbsc/sgsn.h>
|
||||
#include <openbsc/gprs_sndcp_xid.h>
|
||||
#include <openbsc/v42bis.h>
|
||||
#include <openbsc/v42bis_private.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gprs_sndcp_comp.h>
|
||||
#include <openbsc/gprs_sndcp_dcomp.h>
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
Loading…
Reference in New Issue