This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
dexter gerrit-no-reply at lists.osmocom.orgHello Harald Welte, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/638 to look at the new patch set (#4). Added LLC-XID encoder / decoder The lle-xid encoder/decoder is needed to encode and decode llc xid parameter messages. We need this to exchange sndcp-parameters (SNDCP-XID) and also simple parameters such as encryption IOVs Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 --- M openbsc/include/openbsc/Makefile.am A openbsc/include/openbsc/gprs_llc_xid.h M openbsc/src/gprs/Makefile.am A openbsc/src/gprs/gprs_llc_xid.c A openbsc/src/gprs/gprs_sndcp_comp_entity.c 5 files changed, 678 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/38/638/4 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 9ef8a15..9e8c554 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -18,7 +18,7 @@ gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ - gtphub.h gprs_sndcp.h slhc.h + gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h new file mode 100644 index 0000000..a4104ec --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc_xid.h @@ -0,0 +1,63 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (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/>. + * + */ + +#ifndef _GPRS_LLC_XID_H +#define _GPRS_LLC_XID_H + +#include <stdint.h> +#include <osmocom/core/linuxlist.h> + +/* TS 101 351 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (octets) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int bytes_maxlen); + +/* Transform a XID message (dst) into a list of XID fields */ +int gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int bytes_len); + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field); + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + +#endif diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index a118a19..b3a5137 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -23,7 +23,8 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ slhc.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ - gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ + gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \ + gprs_llc_xid.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ gprs_utils.c gprs_gsup_client.c \ sgsn_cdr.c sgsn_ares.c \ diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c new file mode 100644 index 0000000..e2ec163 --- /dev/null +++ b/openbsc/src/gprs/gprs_llc_xid.c @@ -0,0 +1,281 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 04.64 */ + +/* (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 <errno.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/talloc.h> + +#include <openbsc/debug.h> +#include <openbsc/gprs_llc.h> +#include <openbsc/sgsn.h> +#include <openbsc/gprs_llc_xid.h> + + +/* Parse XID parameter field */ +static int +decode_xid_field(const uint8_t *src, uint8_t src_len, + struct gprs_llc_xid_field *xid_field) +{ + uint8_t xl; + uint8_t type; + uint8_t len; + int src_counter = 0; + + /* Exit immediately if it is clear that no + parseable data is present */ + if ((src_len < 1) || !src) + return -EINVAL; + + /* Exit immediately if no result can be stored */ + if (!xid_field) + return -EINVAL; + + /* Extract header info */ + xl = (*src >> 7) & 1; + type = (*src >> 2) & 0x1F; + + /* Extract length field */ + len = (*src) & 0x3; + src++; + src_counter++; + if (xl) { + if (src_len < 2) + return -EINVAL; + len = (len << 6) & 0xC0; + len |= ((*src) >> 2) & 0x3F; + src++; + src_counter++; + } + + /* Fill out struct */ + xid_field->type = type; + xid_field->data_len = len; + if (len > 0) { + if (src_len < src_counter + len) + return -EINVAL; + xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(xid_field->data, src, xid_field->data_len); + } else + xid_field->data = NULL; + + /* Return consumed length */ + return src_counter + len; +} + + +/* Encode XID parameter field */ +static int +encode_xid_field(uint8_t *dst, int dst_maxlen, + const struct gprs_llc_xid_field *xid_field) +{ + int xl = 0; + + /* Exit immediately if no source struct is available */ + if (!xid_field) + return -EINVAL; + + /* When the length does not fit into 2 bits, + we need extended length fields */ + if (xid_field->data_len > 3) + xl = 1; + + /* Exit immediately if it is clear that no + encoding result can be stored */ + if (dst_maxlen < xid_field->data_len + 1 + xl) + return -EINVAL; + + /* There are only 5 bits reserved for the type, exit on exceed */ + if (xid_field->type > 31) + return -EINVAL; + + /* Encode header */ + memset(dst, 0, dst_maxlen); + if (xl) + dst[0] |= 0x80; + dst[0] |= (((xid_field->type) & 0x1F) << 2); + + if (xl) { + dst[0] |= (((xid_field->data_len) >> 6) & 0x03); + dst[1] = ((xid_field->data_len) << 2) & 0xFC; + } else + dst[0] |= ((xid_field->data_len) & 0x03); + + /* Append payload data */ + if ((xid_field->data) && (xid_field->data_len)) + memcpy(dst + 1 + xl, xid_field->data, + xid_field->data_len); + + /* Return generated length */ + return xid_field->data_len + 1 + xl; +} + + +/* Transform a list with XID fields into a XID message (dst) */ +int +gprs_llc_compile_xid(const struct llist_head *xid_fields, uint8_t *dst, + int dst_maxlen) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int byte_counter = 0; + + llist_for_each_entry(xid_field, xid_fields, list) { + /* Encode XID-Field */ + rc = encode_xid_field(dst, dst_maxlen, xid_field); + if (rc < 0) + return -EINVAL; + + /* Advance pointer and lower maxlen for the + next encoding round */ + dst += rc; + byte_counter += rc; + dst_maxlen -= rc; + } + + /* Return generated length */ + return byte_counter; +} + + +/* Transform a XID message (dst) into a list of XID fields */ +int +gprs_llc_parse_xid(struct llist_head *xid_fields, const uint8_t *src, + int src_len) +{ + struct gprs_llc_xid_field *xid_field; + int rc; + int max_loops = src_len; + + while (1) { + /* Bail in case decode_xid_field() constantly returns zero */ + if (max_loops <= 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Decode XID field */ + xid_field = talloc_zero(NULL, struct gprs_llc_xid_field); + rc = decode_xid_field(src, src_len, xid_field); + + /* Immediately stop on error */ + if (rc < 0) { + gprs_llc_free_xid(xid_fields); + return -EINVAL; + } + + /* Add parsed XID field to list */ + llist_add(&xid_field->list, xid_fields); + + /* Advance pointer and lower dst_len for the next + decoding round */ + src += rc; + src_len -= rc; + + /* We are (scuccessfully) done when no further byes are left */ + if (src_len == 0) + return 0; + + max_loops--; + } +} + + +/* Free llist with xid fields */ +void gprs_llc_free_xid(struct llist_head *xid_fields) +{ + struct gprs_llc_xid_field *xid_field; + struct llist_head *lh, *lh2; + + if (xid_fields) { + llist_for_each_entry(xid_field, xid_fields, list) { + if ((xid_field->data) && (xid_field->data_len)) + talloc_free(xid_field->data); + } + + llist_for_each_safe(lh, lh2, xid_fields) { + llist_del(lh); + talloc_free(lh); + } + } +} + + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_duplicate_xid_field(const struct + gprs_llc_xid_field + *xid_field) +{ + struct gprs_llc_xid_field *duplicate_of_xid_field; + + /* Create a copy of the XID field in memory */ + duplicate_of_xid_field = + talloc_zero(NULL, struct gprs_llc_xid_field); + memcpy(duplicate_of_xid_field, xid_field, + sizeof(struct gprs_llc_xid_field)); + duplicate_of_xid_field->data = + talloc_zero_size(NULL, xid_field->data_len); + memcpy(duplicate_of_xid_field->data, xid_field->data, + xid_field->data_len); + + /* Wipeout all llist information in the duplicate (just to be sure) */ + memset(&duplicate_of_xid_field->list, 0, + sizeof(struct llist_head)); + + return duplicate_of_xid_field; +} + +/* Copy an llist with xid fields */ +void gprs_llc_copy_xid(struct llist_head *xid_fields_copy, + const struct llist_head *xid_fields_orig) +{ + struct gprs_llc_xid_field *xid_field; + + /* Make sure that the target list is empty */ + gprs_llc_free_xid(xid_fields_copy); + + /* Create duplicates and add them to the target list */ + llist_for_each_entry(xid_field, xid_fields_orig, list) { + llist_add(&gprs_llc_duplicate_xid_field(xid_field)->list, xid_fields_copy); + } +} + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, unsigned int logl) +{ + struct gprs_llc_xid_field *xid_field; + + llist_for_each_entry(xid_field, xid_fields, list) { + LOGP(DSNDCP, logl, + "XID: type=%i, data_len=%i, data=%s\n", + xid_field->type, xid_field->data_len, + osmo_hexdump_nospc(xid_field->data, + xid_field->data_len)); + } +} diff --git a/openbsc/src/gprs/gprs_sndcp_comp_entity.c b/openbsc/src/gprs/gprs_sndcp_comp_entity.c new file mode 100644 index 0000000..095a32a --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp_comp_entity.c @@ -0,0 +1,331 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (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 <osmocom/core/linuxlist.h> +#include <osmocom/core/talloc.h> + +#include <openbsc/debug.h> +#include <openbsc/gprs_sndcp_xid.h> +#include <openbsc/gprs_sndcp_comp_entity.h> +#include <openbsc/gprs_sndcp_hdrcomp.h> + +/* Create a new compression entity from a XID-Field */ +static struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_create (struct gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + comp_entity = talloc_zero (NULL, struct gprs_sndcp_comp_entity); + + /* Copy relevant information from the SNDCP-XID field */ + comp_entity->entity = comp_field->entity; + comp_entity->comp_len = comp_field->comp_len; + memcpy (comp_entity->comp, comp_field->comp, + comp_field->comp_len * sizeof (int)); + + if (comp_field->rfc1144_params) { + comp_entity->nsapi_len = + comp_field->rfc1144_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc1144_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rfc2507_params) { + comp_entity->nsapi_len = + comp_field->rfc2507_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->rfc2507_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->rohc_params) { + comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len; + memcpy (comp_entity->nsapi, comp_field->rohc_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v42bis_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else if (comp_field->v44_params) { + comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len; + memcpy (comp_entity->nsapi, + comp_field->v42bis_params->nsapi, + comp_entity->nsapi_len * sizeof (int)); + } + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Comp field contained invalid parameters, compression entity not created!\n"); + return NULL; + } + + comp_entity->algo = comp_field->algo; + comp_entity->state = NULL; + + /* Determine of which class our compression entity will be + (Protocol or Data compresson ?) */ + comp_entity->compclass = + gprs_sndcp_get_compression_class (comp_field); + + if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { + if (gprs_sndcp_hdrcomp_init (comp_entity, comp_field) == 0) + LOGP (DSNDCP, LOGL_INFO, + "New header compression entity (%i) created.\n", + comp_entity->entity); + else { + talloc_free (comp_entity); + LOGP (DSNDCP, LOGL_ERROR, + "Header compression entity (%i) creation failed!\n", + comp_entity->entity); + return NULL; + } + } + else + LOGP (DSNDCP, LOGL_INFO, + "New data compression entity (%i) created.\n", + comp_entity->entity); + + return comp_entity; +} + +/* Free a list with compression entities */ +void +gprs_sndcp_comp_entities_free (struct llist_head *comp_entities) +{ + if (comp_entities) { + struct gprs_sndcp_comp_entity *comp_entity; + + llist_for_each_entry (comp_entity, comp_entities, list) { + /* Free compression entity */ + if (comp_entity->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) header compression entity %i ...\n", + comp_entity->entity); + gprs_sndcp_hdrcomp_term (comp_entity); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting (free) data compression entity %i ...\n", + comp_entity->entity); + + talloc_free (comp_entity); + } + + } +} + +/* Delete a compression entity */ +void +gprs_sndcp_comp_entities_delete (struct llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + struct gprs_sndcp_comp_entity *comp_entity_to_delete = NULL; + + if (comp_entities) { + + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + comp_entity_to_delete = comp_entity; + } + + if (comp_entity_to_delete) { + if (comp_entity_to_delete->compclass == + SNDCP_XID_PROTOCOL_COMPRESSION) { + LOGP (DSNDCP, LOGL_INFO, + "Deleting header compression entity %i ...\n", + comp_entity_to_delete->entity); + gprs_sndcp_hdrcomp_term + (comp_entity_to_delete); + } + else + LOGP (DSNDCP, LOGL_INFO, + "Deleting data compression entity %i ...\n", + comp_entity_to_delete->entity); + + /* Delete compression entity */ + llist_del (&comp_entity_to_delete->list); + talloc_free (comp_entity_to_delete); + } + } +} + +/* Create and Add a new compression entity +(returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entities_add (struct + llist_head + *comp_entities, struct + gprs_sndcp_comp_field *comp_field) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + /* Just to be sure, if the entity is already in + the list it will be deleted now */ + gprs_sndcp_comp_entities_delete (comp_entities, comp_field->entity); + + /* Create and add a new entity to the list */ + comp_entity = gprs_sndcp_comp_entity_create (comp_field); + + if (comp_entity) { + llist_add (&comp_entity->list, comp_entities); + return comp_entity; + } + + return NULL; +} + +/* Find compression entity by its entity number */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_entity (struct + llist_head *comp_entities, int entity) +{ + struct gprs_sndcp_comp_entity *comp_entity; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + if (comp_entity->entity == entity) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given entity number %i.\n", + entity); + return NULL; +} + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_comp (struct + llist_head *comp_entities, int comp) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return comp_entity; + } + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given pcomp/dcomp value %i.\n", + comp); + return NULL; +} + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp_entity * +gprs_sndcp_comp_entity_find_by_nsapi (struct + llist_head *comp_entities, int nsapi) +{ + struct gprs_sndcp_comp_entity *comp_entity; + int i; + + if (comp_entities) { + llist_for_each_entry (comp_entity, comp_entities, list) { + for (i = 0; i < comp_entity->nsapi_len; i++) { + if (comp_entity->nsapi[i] == nsapi) + return comp_entity; + } + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching compression entity for given nsapi value %i\n", + nsapi); + return NULL; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity list contained null-pointer!\n"); + return NULL; +} + +/* Find a comp_index for a given pcomp/dcomp value */ +int +gprs_sndcp_comp_entity_find_comp_index_by_comp (struct + gprs_sndcp_comp_entity + *comp_entity, int comp) +{ + int i; + + if (comp_entity) { + /* A pcomp/dcomp field set to zero always disables + all sort of compression and is assigned fix. So we + just return zero in this case */ + if (comp == 0) + return 0; + + /* Look in the pcomp/dcomp list for the index */ + for (i = 0; i < comp_entity->comp_len; i++) { + if (comp_entity->comp[i] == comp) + return i + 1; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching comp_index for given pcomp/dcomp value %i\n", + comp); + return 0; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} + +/* Find a pcomp/dcomp value for a given comp_index */ +int +gprs_sndcp_comp_entity_find_comp_by_comp_index (struct + gprs_sndcp_comp_entity + *comp_entity, int comp_index) +{ + if (comp_entity) { + /* A comp_index of zero translates to zero right away. */ + if (comp_index == 0) + return 0; + + if (comp_index > comp_entity->comp_len) { + LOGP (DSNDCP, LOGL_ERROR, + "Could not find a matching pcomp/dcomp value for given comp_index value %i.\n", + comp_index); + return 0; + } + + /* Look in the pcomp/dcomp list for the comp_index */ + return comp_entity->comp[comp_index - 1]; + } + + LOGP (DSNDCP, LOGL_ERROR, + "Compression entity contained null-pointer!\n"); + return 0; +} -- To view, visit https://gerrit.osmocom.org/638 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ia06e4cb08bf9b48c2a4682606d1b1a91d19a9d37 Gerrit-PatchSet: 4 Gerrit-Project: openbsc Gerrit-Branch: master Gerrit-Owner: dexter <pmaier at sysmocom.de> Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org> Gerrit-Reviewer: Jenkins Builder