From 762c39ccc65e0307a32b89e8bf7daaad2b6b66b4 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 30 Aug 2019 20:47:02 +0200 Subject: Move out sgsn to its own subdir Change-Id: I16fccc0eadf588599b9e5578d0f4dbaf9df81737 --- src/sgsn/gprs_sndcp_pcomp.c | 282 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 src/sgsn/gprs_sndcp_pcomp.c (limited to 'src/sgsn/gprs_sndcp_pcomp.c') diff --git a/src/sgsn/gprs_sndcp_pcomp.c b/src/sgsn/gprs_sndcp_pcomp.c new file mode 100644 index 000000000..8c2fc974d --- /dev/null +++ b/src/sgsn/gprs_sndcp_pcomp.c @@ -0,0 +1,282 @@ +/* GPRS SNDCP header 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 + +/* Initalize header compression */ +int gprs_sndcp_pcomp_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 header compression + * entity is created by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + OSMO_ASSERT(comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo.pcomp == RFC_1144) { + OSMO_ASSERT(comp_field->rfc1144_params); + comp_entity->state = + slhc_init(ctx, comp_field->rfc1144_params->s01 + 1, + comp_field->rfc1144_params->s01 + 1); + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header compression initialized.\n"); + return 0; + } + + /* Just in case someone tries to initalize an unknown or unsupported + * header compresson. Since everything is checked during the SNDCP + * negotiation process, this should never happen! */ + OSMO_ASSERT(false); +} + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity) +{ + /* Note: This function is automatically called from + * gprs_sndcp_comp.c when a header compression + * entity is deleted by gprs_sndcp.c */ + + OSMO_ASSERT(comp_entity); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION + && comp_entity->algo.pcomp == RFC_1144) { + if (comp_entity->state) { + slhc_free((struct slcompress *)comp_entity->state); + comp_entity->state = NULL; + } + LOGP(DSNDCP, LOGL_INFO, + "RFC1144 header 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); +} + +/* Compress a packet using Van Jacobson RFC1144 header compression */ +static int rfc1144_compress(uint8_t *pcomp_index, uint8_t *data, + unsigned int len, struct slcompress *comp) +{ + uint8_t *comp_ptr; + int compr_len; + uint8_t *data_o; + + /* Create a working copy of the incoming data */ + data_o = talloc_zero_size(comp, len); + memcpy(data_o, data, len); + + /* Run compressor */ + compr_len = slhc_compress(comp, data, len, data_o, &comp_ptr, 0); + + /* Generate pcomp_index */ + if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { + *pcomp_index = 2; + data_o[0] &= ~SL_TYPE_COMPRESSED_TCP; + memcpy(data, data_o, compr_len); + } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) == + SL_TYPE_UNCOMPRESSED_TCP) { + *pcomp_index = 1; + data_o[0] &= 0x4F; + memcpy(data, data_o, compr_len); + } else + *pcomp_index = 0; + + talloc_free(data_o); + return compr_len; +} + +/* Expand a packet using Van Jacobson RFC1144 header compression */ +static int rfc1144_expand(uint8_t *data, unsigned int len, uint8_t pcomp_index, + struct slcompress *comp) +{ + int data_decompressed_len; + int type; + + /* Note: this function should never be called with pcomp_index=0, + * since this condition is already filtered + * out by gprs_sndcp_pcomp_expand() */ + + /* Determine the data type by the PCOMP index */ + switch (pcomp_index) { + case 0: + type = SL_TYPE_IP; + break; + case 1: + type = SL_TYPE_UNCOMPRESSED_TCP; + break; + case 2: + type = SL_TYPE_COMPRESSED_TCP; + break; + default: + LOGP(DSNDCP, LOGL_ERROR, + "rfc1144_expand() Invalid pcomp_index value (%d) detected, assuming no compression!\n", + pcomp_index); + type = SL_TYPE_IP; + break; + } + + /* Restore the original version nibble on + * marked uncompressed packets */ + if (type == SL_TYPE_UNCOMPRESSED_TCP) { + /* Just in case the phone tags uncompressed tcp-data + * (normally this is handled by pcomp so there is + * no need for tagging the data) */ + data[0] &= 0x4F; + data_decompressed_len = slhc_remember(comp, data, len); + return data_decompressed_len; + } + + /* Uncompress compressed packets */ + else if (type == SL_TYPE_COMPRESSED_TCP) { + data_decompressed_len = slhc_uncompress(comp, data, len); + return data_decompressed_len; + } + + /* Regular or unknown packets will not be touched */ + return len; +} + +/* Expand packet header */ +int gprs_sndcp_pcomp_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, + "Header compression entity list: comp_entities=%p\n", + comp_entities); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%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 protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo.pcomp == RFC_1144); + + /* Find pcomp_index */ + pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp); + + /* Run decompression algo */ + rc = rfc1144_expand(data, len, pcomp_index, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header expansion done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + + return rc; +} + +/* Compress packet header */ +int gprs_sndcp_pcomp_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, + "Header 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 protocol compression entities may appear in + * protocol compression context */ + OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION); + + /* Note: Currently RFC1144 is the only compression method we + * support, so the only allowed algorithm is RFC1144 */ + OSMO_ASSERT(comp_entity->algo.pcomp == RFC_1144); + + /* Run compression algo */ + rc = rfc1144_compress(&pcomp_index, data, len, comp_entity->state); + slhc_i_status(comp_entity->state); + slhc_o_status(comp_entity->state); + + /* Find pcomp value */ + *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index); + + LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", *pcomp); + + LOGP(DSNDCP, LOGL_DEBUG, + "Header compression done, old length=%d, new length=%d, entity=%p\n", + len, rc, comp_entity); + return rc; +} -- cgit v1.2.3