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/.
Stefan Sperling gerrit-no-reply at lists.osmocom.orgHello Jenkins Builder, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/6509 to look at the new patch set (#4). Support for more cell ID list types in libosmocore. Extend gsm0808_dec_cell_id_list() with support for additional types of cell identifier lists. The new parsing routines are based on similar routines used by the paging code in osmo-bsc's osmo_bsc_bssap.c. Likewise, extend gsm0808_enc_cell_id_list() with support for the same additional types of cell identifier lists. There is an API change in struct gsm0808_cell_id_list. The previous definition was insufficient because it assumed that all decoded cell ID types could be represented with a single uint16_t. The only user I am aware of is in osmo-msc, where this struct is used for one local variable. This API user is fixed by https://gerrit.osmocom.org/#/c/6518/ Change-Id: Ib7e754f538df0c83298a3c958b4e15a32fcb8abb Related: OS#2847 --- M include/osmocom/gsm/protocol/gsm_08_08.h M src/gsm/gsm0808_utils.c M tests/gsm0808/gsm0808_test.c 3 files changed, 257 insertions(+), 23 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/09/6509/4 diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h index ba347ef..75c3c61 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -502,9 +502,67 @@ }; /* 3GPP TS 48.008 3.2.2.27 Cell Identifier List */ -#define CELL_ID_LIST_LAC_MAXLEN 127 + +/* + * The structs below are parsed representations of data in the corresponding IE. + * All fields are in host byte-order. + * + * The functions gsm0808_dec_cell_id_list() and gsm0808_enc_cell_id_list() + * convert these structs from/to a network byte-order data stream. + * + * XXX TODO: These declarations belong in gsm_0808_utils.h, not here. + * However, moving them there currently breaks the build. + */ + +/* Parsed Cell Global Identification (CELL_IDENT_WHOLE_GLOBAL) */ +struct gsm0808_cell_id_global { + uint16_t mcc; + uint16_t mnc; + uint16_t lac; + uint16_t ci; +}a; + +/* Parsed Location Area Code and Cell Identity (CELL_IDENT_LAC_AND_CI) */ +struct gsm0808_cell_id_lac_and_ci { + uint16_t lac; + uint16_t ci; +}; + +/* Parsed Cell Identity (CELL_IDENT_CI) */ +struct gsm0808_cell_id_ci { + uint16_t ci; +}; + +/* Parsed Location Area Identification and Location Area Code (CELL_IDENT_LAI_AND_LAC) */ +struct gsm0808_cell_id_lai_and_lac { + uint16_t mcc; + uint16_t mnc; + uint16_t lac; +}; + +/* Parsed Location Area Code (CELL_IDENT_LAC) */ +struct gsm0808_cell_id_lac { + uint16_t lac; +}; + +#define CELL_ID_LIST_MAXLEN 254 /* implementation-defined limit, in bytes */ +#define CELL_ID_LIST_GLOBAL_MAXLEN (CELL_ID_LIST_MAXLEN / sizeof(struct gsm0808_cell_id_global)) +#define CELL_ID_LIST_LAC_AND_CI_MAXLEN (CELL_ID_LIST_MAXLEN / sizeof(struct gsm0808_cell_id_lac_and_ci)) +#define CELL_ID_LIST_CI_MAXLEN (CELL_ID_LIST_MAXLEN / sizeof(struct gsm0808_cell_id_ci)) +#define CELL_ID_LIST_LAI_AND_LAC_MAXLEN (CELL_ID_LIST_MAXLEN / sizeof(struct gsm0808_cell_id_lai_and_lac)) +#define CELL_ID_LIST_LAC_MAXLEN (CELL_ID_LIST_MAXLEN / sizeof(struct gsm0808_cell_id_lac)) struct gsm0808_cell_id_list { uint8_t id_discr; - uint16_t id_list_lac[CELL_ID_LIST_LAC_MAXLEN]; + union { + /* + * All struct fields in elements of these arrays are in host-byte order, + * ie. contain parsed representations of the data in the corresponding IE. + */ + struct gsm0808_cell_id_global id_list_global[CELL_ID_LIST_GLOBAL_MAXLEN]; + struct gsm0808_cell_id_lac_and_ci id_list_lac_and_ci[CELL_ID_LIST_LAC_AND_CI_MAXLEN]; + struct gsm0808_cell_id_ci id_list_ci[CELL_ID_LIST_CI_MAXLEN]; + struct gsm0808_cell_id_lai_and_lac id_list_lai_and_lac[CELL_ID_LIST_LAI_AND_LAC_MAXLEN]; + struct gsm0808_cell_id_lac id_list_lac[CELL_ID_LIST_LAC_MAXLEN]; + } id_list; unsigned int id_list_len; }; diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c index 93e6074..80b203d 100644 --- a/src/gsm/gsm0808_utils.c +++ b/src/gsm/gsm0808_utils.c @@ -27,6 +27,7 @@ #include <string.h> #include <errno.h> #include <osmocom/gsm/protocol/gsm_08_08.h> +#include <osmocom/gsm/gsm48.h> #define IP_V4_ADDR_LEN 4 #define IP_V6_ADDR_LEN 16 @@ -588,22 +589,180 @@ msgb_put_u8(msg, cil->id_discr & 0x0f); switch (cil->id_discr) { + case CELL_IDENT_WHOLE_GLOBAL: + OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_GLOBAL_MAXLEN) + for (i = 0; i < cil->id_list_len; i++) { + const struct gsm0808_cell_id_global *id = &cil->id_list.id_list_global[i]; + struct gsm48_loc_area_id lai; + gsm48_generate_lai(&lai, id->mcc, id->mnc, id->lac); + memcpy(msgb_put(msg, sizeof(lai)), &lai, sizeof(lai)); + msgb_put_u16(msg, id->ci); + } + break; + case CELL_IDENT_LAC_AND_CI: + OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_AND_CI_MAXLEN) + for (i = 0; i < cil->id_list_len; i++) { + const struct gsm0808_cell_id_lac_and_ci *id = &cil->id_list.id_list_lac_and_ci[i]; + msgb_put_u16(msg, id->lac); + msgb_put_u16(msg, id->ci); + } + break; + case CELL_IDENT_CI: + OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_CI_MAXLEN) + for (i = 0; i < cil->id_list_len; i++) { + const struct gsm0808_cell_id_ci *id = &cil->id_list.id_list_ci[i]; + msgb_put_u16(msg, id->ci); + } + break; + case CELL_IDENT_LAI_AND_LAC: + OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAI_AND_LAC_MAXLEN) + for (i = 0; i < cil->id_list_len; i++) { + const struct gsm0808_cell_id_lai_and_lac *id = &cil->id_list.id_list_lai_and_lac[i]; + struct gsm48_loc_area_id lai; + gsm48_generate_lai(&lai, id->mcc, id->mnc, id->lac); + memcpy(msgb_put(msg, sizeof(lai)), &lai, sizeof(lai)); + } + break; case CELL_IDENT_LAC: OSMO_ASSERT(cil->id_list_len <= CELL_ID_LIST_LAC_MAXLEN) - for (i=0;i<cil->id_list_len;i++) { - msgb_put_u16(msg, cil->id_list_lac[i]); + for (i = 0; i < cil->id_list_len; i++) { + const struct gsm0808_cell_id_lac *id = &cil->id_list.id_list_lac[i]; + msgb_put_u16(msg, id->lac); } break; case CELL_IDENT_BSS: + case CELL_IDENT_NO_CELL: /* Does not have any list items */ break; default: - /* FIXME: Implement support for all identifier list elements */ + /* Support for other identifier list types is not implemented. */ OSMO_ASSERT(false); } *tlv_len = (uint8_t) (msg->tail - old_tail); return *tlv_len + 2; +} + +/* Decode 5-byte LAI list element data (see TS 08.08 3.2.2.27) into MCC/MNC/LAC. + * Return 0 if successful, negative on error. */ +static int decode_lai(const uint8_t *data, uint16_t *mcc, uint16_t *mnc, uint16_t *lac) +{ + struct gsm48_loc_area_id lai; + + /* Copy data to stack to prevent unaligned access in gsm48_decode_lai(). */ + memcpy(&lai, data, sizeof(lai)); /* don't byte swap yet */ + + return gsm48_decode_lai(&lai, mcc, mnc, lac) != 0 ? -1 : 0; +} + +static int parse_cell_id_global_list(struct gsm0808_cell_id_global *id_list, unsigned int maxlen, const uint8_t *data, + size_t remain, size_t *consumed) +{ + struct gsm0808_cell_id_global *id; + uint16_t *ci_be; + size_t lai_offset; + int i = 0; + + *consumed = 0; + while (remain >= sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be)) { + if (i >= maxlen) + return -ENOSPC; + id = &id_list[i]; + if (decode_lai(&data[lai_offset], &id->mcc, &id->mnc, &id->lac) != 0) + return -EINVAL; + lai_offset = 1 + i * (sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be)); + ci_be = (uint16_t *)(&data[lai_offset + sizeof(struct gsm48_loc_area_id)]); + id->ci = osmo_load16be(ci_be); + *consumed += sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be); + remain -= sizeof(struct gsm48_loc_area_id) + sizeof(*ci_be); + i++; + } + + return i; +} + +static int parse_cell_id_lac_and_ci_list(struct gsm0808_cell_id_lac_and_ci *id_list, unsigned int maxlen, + const uint8_t *data, size_t remain, size_t *consumed) +{ + uint16_t *lacp_be, *ci_be; + struct gsm0808_cell_id_lac_and_ci *id; + int i = 0; + + *consumed = 0; + + if (remain < sizeof(*lacp_be) + sizeof(*ci_be)) + return -EINVAL; + + lacp_be = (uint16_t *)(&data[0]); + ci_be = (uint16_t *)(&data[2]); + while (remain >= sizeof(*lacp_be) + sizeof(*ci_be)) { + if (i >= maxlen) + return -ENOSPC; + id = &id_list[i]; + id->lac = osmo_load16be(lacp_be); + id->ci = osmo_load16be(ci_be); + *consumed += sizeof(*lacp_be) + sizeof(*ci_be); + remain -= sizeof(*lacp_be) + sizeof(*ci_be); + lacp_be++; + ci_be++; + } + + return i; +} + +static int parse_cell_id_ci_list(struct gsm0808_cell_id_ci *id_list, unsigned int maxlen, const uint8_t *data, + size_t remain, size_t *consumed) +{ + const uint16_t *ci_be = (const uint16_t *)data; + int i = 0; + + *consumed = 0; + while (remain >= sizeof(*ci_be)) { + if (i >= maxlen) + return -ENOSPC; + id_list[i++].ci = osmo_load16be(ci_be++); + consumed += sizeof(*ci_be); + remain -= sizeof(*ci_be); + } + return i; +} + +static int parse_cell_id_lai_and_lac(struct gsm0808_cell_id_lai_and_lac *id_list, unsigned int maxlen, + const uint8_t *data, size_t remain, size_t *consumed) +{ + struct gsm0808_cell_id_lai_and_lac *id; + int i = 0; + + *consumed = 0; + while (remain >= sizeof(struct gsm48_loc_area_id)) { + if (i >= maxlen) + return -ENOSPC; + id = &id_list[i]; + if (decode_lai(&data[1 + i * sizeof(struct gsm48_loc_area_id)], &id->mcc, &id->mnc, &id->lac) != 0) + return -EINVAL; + *consumed += sizeof(struct gsm48_loc_area_id); + remain -= sizeof(struct gsm48_loc_area_id); + i++; + } + + return i; +} + +static int parse_cell_id_lac_list(struct gsm0808_cell_id_lac *id_list, unsigned int maxlen, const uint8_t *data, + size_t remain, size_t *consumed) +{ + const uint16_t *lac_be = (const uint16_t *)data; + int i = 0; + + *consumed = 0; + while (remain >= sizeof(*lac_be)) { + if (i >= maxlen) + return -ENOSPC; + id_list[i++].lac = osmo_load16be(lac_be++); + *consumed += sizeof(*lac_be); + remain -= sizeof(*lac_be); + } + return i; } /*! Decode Cell Identifier List IE @@ -615,8 +774,8 @@ const uint8_t *elem, uint8_t len) { uint8_t id_discr; - const uint8_t *old_elem = elem; - unsigned int item_count = 0; + size_t bytes_elem = 0; + int list_len = 0; OSMO_ASSERT(cil); if (!elem) @@ -630,26 +789,43 @@ elem++; len--; - cil->id_discr = id_discr; - switch (id_discr) { + case CELL_IDENT_WHOLE_GLOBAL: + list_len = parse_cell_id_global_list(cil->id_list.id_list_global, CELL_ID_LIST_GLOBAL_MAXLEN, elem, len, + &bytes_elem); + break; + case CELL_IDENT_LAC_AND_CI: + list_len = parse_cell_id_lac_and_ci_list(cil->id_list.id_list_lac_and_ci, CELL_ID_LIST_LAC_AND_CI_MAXLEN, + elem, len, &bytes_elem); + break; + case CELL_IDENT_CI: + list_len = parse_cell_id_ci_list(cil->id_list.id_list_ci, CELL_ID_LIST_CI_MAXLEN, elem, len, + &bytes_elem); + break; + case CELL_IDENT_LAI_AND_LAC: + list_len = parse_cell_id_lai_and_lac(cil->id_list.id_list_lai_and_lac, CELL_ID_LIST_LAI_AND_LAC_MAXLEN, + elem, len, &bytes_elem); + break; case CELL_IDENT_LAC: - while (len >= 2) { - cil->id_list_lac[item_count] = osmo_load16be(elem); - elem += 2; - item_count++; - len -= 2; - } + list_len = parse_cell_id_lac_list(cil->id_list.id_list_lac, CELL_ID_LIST_LAC_MAXLEN, elem, len, + &bytes_elem); + break; case CELL_IDENT_BSS: + case CELL_IDENT_NO_CELL: /* Does not have any list items */ break; default: - /* FIXME: Implement support for all identifier list elements */ + /* Remaining cell identification types are not implemented. */ return -EINVAL; } - cil->id_list_len = item_count; - return (int)(elem - old_elem); + if (list_len < 0) /* parsing error */ + return list_len; + + cil->id_discr = id_discr; + cil->id_list_len = list_len; + + return 1 + (int)bytes_elem; } /*! Convert the representation of the permitted speech codec identifier diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c index 189d548..cf39498 100644 --- a/tests/gsm0808/gsm0808_test.c +++ b/tests/gsm0808/gsm0808_test.c @@ -458,7 +458,7 @@ char imsi[] = "001010000001234"; cil.id_discr = CELL_IDENT_LAC; - cil.id_list_lac[0] = 0x2342; + cil.id_list.id_list_lac[0].lac = 0x2342; cil.id_list_len = 1; printf("Testing creating Paging Request\n"); @@ -759,9 +759,9 @@ memset(&enc_cil, 0, sizeof(enc_cil)); enc_cil.id_discr = CELL_IDENT_LAC; - enc_cil.id_list_lac[0] = 0x0124; - enc_cil.id_list_lac[1] = 0xABCD; - enc_cil.id_list_lac[2] = 0x5678; + enc_cil.id_list.id_list_lac[0].lac = 0x0124; + enc_cil.id_list.id_list_lac[1].lac = 0xABCD; + enc_cil.id_list.id_list_lac[2].lac = 0x5678; enc_cil.id_list_len = 3; msg = msgb_alloc(1024, "output buffer"); @@ -790,7 +790,7 @@ memset(&enc_cil, 0, sizeof(enc_cil)); enc_cil.id_discr = CELL_IDENT_LAC; - enc_cil.id_list_lac[0] = 0x2342; + enc_cil.id_list.id_list_lac[0].lac = 0x2342; enc_cil.id_list_len = 1; msg = msgb_alloc(1024, "output buffer"); -- To view, visit https://gerrit.osmocom.org/6509 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newpatchset Gerrit-Change-Id: Ib7e754f538df0c83298a3c958b4e15a32fcb8abb Gerrit-PatchSet: 4 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: Stefan Sperling <ssperling at sysmocom.de> Gerrit-Reviewer: Jenkins Builder