diff options
-rw-r--r-- | TODO-RELEASE | 1 | ||||
-rw-r--r-- | include/osmocom/gsm/gsm0808_utils.h | 2 | ||||
-rw-r--r-- | include/osmocom/gsm/gsm23003.h | 7 | ||||
-rw-r--r-- | include/osmocom/gsm/protocol/gsm_08_08.h | 5 | ||||
-rw-r--r-- | src/gsm/gsm0808_utils.c | 66 | ||||
-rw-r--r-- | src/gsm/gsm23003.c | 45 | ||||
-rw-r--r-- | tests/gsm0808/gsm0808_test.c | 5 |
7 files changed, 127 insertions, 4 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE index 8ccfa491..38551459 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -7,3 +7,4 @@ # If any interfaces have been added since the last public release: c:r:a + 1. # If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line +libosmogsm ABI BREAKAGE CELL_IDENT_WHOLE_GLOBAL_PS changed enum number diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h index 60e665bb..6abfeecc 100644 --- a/include/osmocom/gsm/gsm0808_utils.h +++ b/include/osmocom/gsm/gsm0808_utils.h @@ -44,6 +44,8 @@ union gsm0808_cell_id_u { uint16_t ci; struct osmo_location_area_id lai_and_lac; uint16_t lac; + struct osmo_service_area_id sai; + /* osmocom specific: */ struct osmo_cell_global_id_ps global_ps; }; diff --git a/include/osmocom/gsm/gsm23003.h b/include/osmocom/gsm/gsm23003.h index 487379a4..4070581f 100644 --- a/include/osmocom/gsm/gsm23003.h +++ b/include/osmocom/gsm/gsm23003.h @@ -30,6 +30,9 @@ struct osmo_cell_global_id { uint16_t cell_identity; }; +/* 3GPP TS 48.018: + * 8c.1.4.1.1 GERAN BSS identification (RIM) + * sec 11.3.9 Cell Identifier */ struct osmo_cell_global_id_ps { struct osmo_routing_area_id rai; uint16_t cell_identity; @@ -134,6 +137,10 @@ const char *osmo_cgi_ps_name(const struct osmo_cell_global_id_ps *cgi_ps); const char *osmo_cgi_ps_name2(const struct osmo_cell_global_id_ps *cgi_ps); char *osmo_cgi_ps_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id_ps *cgi_ps); char *osmo_cgi_ps_name_c(const void *ctx, const struct osmo_cell_global_id_ps *cgi_ps); +const char *osmo_sai_name(const struct osmo_service_area_id *sai); +const char *osmo_sai_name2(const struct osmo_service_area_id *sai); +char *osmo_sai_name_buf(char *buf, size_t buf_len, const struct osmo_service_area_id *sai); +char *osmo_sai_name_c(const void *ctx, const struct osmo_service_area_id *sai); const char *osmo_gummei_name(const struct osmo_gummei *gummei); char *osmo_gummei_name_buf(char *buf, size_t buf_len, const struct osmo_gummei *gummei); char *osmo_gummei_name_c(const void *ctx, const struct osmo_gummei *gummei); diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h index 983783ee..2162c2a0 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -25,9 +25,10 @@ enum CELL_IDENT { CELL_IDENT_UTRAN_PLMN_LAC_RNC = 8, CELL_IDENT_UTRAN_RNC = 9, CELL_IDENT_UTRAN_LAC_RNC = 10, + CELL_IDENT_SAI = 11, - /* Not in 03.03 nor 08.08 */ - CELL_IDENT_WHOLE_GLOBAL_PS = 11, /* CGI with + RAC */ + /* Not in 03.03 nor 08.08. Place them > 0x0f (discr_id is 4 bits) */ + CELL_IDENT_WHOLE_GLOBAL_PS = 128, /* CGI + RAC, TS 48.018 8c.1.4.1.1 */ }; /* Keep this misnamed CELL_IDENT for API backwards compatibility (see OS#3124). */ #define CELL_IDENT_LAI_AND_LAC CELL_IDENT_LAI diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c index 78cbe92e..040872b8 100644 --- a/src/gsm/gsm0808_utils.c +++ b/src/gsm/gsm0808_utils.c @@ -831,6 +831,10 @@ static void cell_id_to_cgi(struct osmo_cell_global_id *dst, dst->lai.lac = u->lac; return; + case CELL_IDENT_SAI: + dst->lai = u->sai.lai; + return; + case CELL_IDENT_NO_CELL: case CELL_IDENT_BSS: case CELL_IDENT_UTRAN_PLMN_LAC_RNC: @@ -858,6 +862,8 @@ int gsm0808_cell_id_size(enum CELL_IDENT discr) case CELL_IDENT_BSS: case CELL_IDENT_NO_CELL: return 0; + case CELL_IDENT_SAI: + return 7; case CELL_IDENT_WHOLE_GLOBAL_PS: return 8; default: @@ -904,6 +910,12 @@ int gsm0808_decode_cell_id_u(union gsm0808_cell_id_u *out, enum CELL_IDENT discr case CELL_IDENT_NO_CELL: /* Does not have any list items */ break; + case CELL_IDENT_SAI: + if (len < 7) + return -EINVAL; + decode_lai(buf, &out->sai.lai); + out->sai.sac = osmo_load16be(buf + sizeof(struct gsm48_loc_area_id)); + break; case CELL_IDENT_WHOLE_GLOBAL_PS: /* 3GPP TS 48.018 sec 11.3.9 "Cell Identifier" */ if (len < 8) @@ -953,6 +965,16 @@ void gsm0808_msgb_put_cell_id_u(struct msgb *msg, enum CELL_IDENT id_discr, cons case CELL_IDENT_NO_CELL: /* Does not have any list items */ break; + + case CELL_IDENT_SAI: { + const struct osmo_service_area_id *id = &u->sai; + struct gsm48_loc_area_id lai; + gsm48_generate_lai2(&lai, &id->lai); + memcpy(msgb_put(msg, sizeof(lai)), &lai, sizeof(lai)); + msgb_put_u16(msg, id->sac); + break; + } + case CELL_IDENT_WHOLE_GLOBAL_PS: { /* 3GPP TS 48.018 sec 11.3.9 "Cell Identifier" */ const struct osmo_cell_global_id_ps *id = &u->global_ps; @@ -1166,6 +1188,31 @@ static int parse_cell_id_lac_list(struct gsm0808_cell_id_list2 *cil, const uint8 return i; } +static int parse_cell_id_sai_list(struct gsm0808_cell_id_list2 *cil, const uint8_t *data, size_t remain, size_t *consumed) +{ + struct osmo_service_area_id *id; + uint16_t *sac_be; + size_t lai_offset; + int i = 0; + const size_t elemlen = sizeof(struct gsm48_loc_area_id) + sizeof(*sac_be); + + *consumed = 0; + while (remain >= elemlen) { + if (i >= GSM0808_CELL_ID_LIST2_MAXLEN) + return -ENOSPC; + id = &cil->id_list[i].sai; + lai_offset = i * elemlen; + decode_lai(&data[lai_offset], &id->lai); + sac_be = (uint16_t *)(&data[lai_offset + sizeof(struct gsm48_loc_area_id)]); + id->sac = osmo_load16be(sac_be); + *consumed += elemlen; + remain -= elemlen; + i++; + } + + return i; +} + /*! Decode Cell Identifier List IE * \param[out] cil Caller-provided memory to store Cell ID list * \param[in] elem IE value to be decoded @@ -1210,6 +1257,12 @@ int gsm0808_dec_cell_id_list2(struct gsm0808_cell_id_list2 *cil, case CELL_IDENT_NO_CELL: /* Does not have any list items */ break; + case CELL_IDENT_SAI: + list_len = parse_cell_id_sai_list(cil, elem, len, &bytes_elem); + break; + case CELL_IDENT_UTRAN_PLMN_LAC_RNC: + case CELL_IDENT_UTRAN_RNC: + case CELL_IDENT_UTRAN_LAC_RNC: default: /* Remaining cell identification types are not implemented. */ return -EINVAL; @@ -1703,6 +1756,8 @@ int gsm0808_cell_id_u_name(char *buf, size_t buflen, return snprintf(buf, buflen, "%s", osmo_cgi_name(&u->global)); case CELL_IDENT_WHOLE_GLOBAL_PS: return snprintf(buf, buflen, "%s", osmo_cgi_ps_name(&u->global_ps)); + case CELL_IDENT_SAI: + return snprintf(buf, buflen, "%s", osmo_sai_name(&u->sai)); default: /* For CELL_IDENT_BSS and CELL_IDENT_NO_CELL, just print the discriminator. * Same for kinds we have no string representation of yet. */ @@ -1859,6 +1914,12 @@ void gsm0808_cell_id_from_cgi(struct gsm0808_cell_id *cid, enum CELL_IDENT id_di cid->id.lac = cgi->lai.lac; return; + case CELL_IDENT_SAI: + cid->id.sai = (struct osmo_service_area_id){ + .lai = cgi->lai, + }; + return; + case CELL_IDENT_NO_CELL: case CELL_IDENT_BSS: case CELL_IDENT_UTRAN_PLMN_LAC_RNC: @@ -1905,6 +1966,10 @@ int gsm0808_cell_id_to_cgi(struct osmo_cell_global_id *cgi, const struct gsm0808 cgi->lai.lac = cid->id.lac; return OSMO_CGI_PART_LAC; + case CELL_IDENT_SAI: + cgi->lai = cid->id.sai.lai; + return OSMO_CGI_PART_PLMN | OSMO_CGI_PART_LAC; + case CELL_IDENT_NO_CELL: case CELL_IDENT_BSS: case CELL_IDENT_UTRAN_PLMN_LAC_RNC: @@ -1927,6 +1992,7 @@ const struct value_string gsm0808_cell_id_discr_names[] = { { CELL_IDENT_UTRAN_PLMN_LAC_RNC, "UTRAN-PLMN-LAC-RNC" }, { CELL_IDENT_UTRAN_RNC, "UTRAN-RNC" }, { CELL_IDENT_UTRAN_LAC_RNC, "UTRAN-LAC-RNC" }, + { CELL_IDENT_SAI, "SAI" }, { CELL_IDENT_WHOLE_GLOBAL_PS, "CGI-PS"}, { 0, NULL } }; diff --git a/src/gsm/gsm23003.c b/src/gsm/gsm23003.c index b893873b..1eed41fe 100644 --- a/src/gsm/gsm23003.c +++ b/src/gsm/gsm23003.c @@ -368,6 +368,51 @@ char *osmo_cgi_ps_name_c(const void *ctx, const struct osmo_cell_global_id_ps *c return osmo_cgi_ps_name_buf(buf, 32, cgi_ps); } +/*! Return MCC-MNC-LAC-SAC as string, in caller-provided output buffer. + * \param[out] buf caller-allocated output buffer + * \param[in] buf_len size of buf in bytes + * \param[in] sai SAI to encode. + * \returns buf + */ +char *osmo_sai_name_buf(char *buf, size_t buf_len, const struct osmo_service_area_id *sai) +{ + snprintf(buf, buf_len, "%s-%u", osmo_lai_name(&sai->lai), sai->sac); + return buf; +} + +/*! Return MCC-MNC-LAC-SAC as string, in a static buffer. + * \param[in] sai SAI to encode. + * \returns Static string buffer. + */ +const char *osmo_sai_name(const struct osmo_service_area_id *sai) +{ + static __thread char buf[32]; + return osmo_sai_name_buf(buf, sizeof(buf), sai); +} + +/*! Same as osmo_cgi_name(), but uses a different static buffer. + * Useful for printing two distinct CGIs in the same printf format. + * \param[in] sai SAI to encode. + * \returns Static string buffer. + */ +const char *osmo_sai_name2(const struct osmo_service_area_id *sai) +{ + static __thread char buf[32]; + return osmo_sai_name_buf(buf, sizeof(buf), sai); +} + +/*! Return MCC-MNC-LAC-SAC as string, in a talloc-allocated output buffer. + * \param[in] ctx talloc context from which to allocate output buffer + * \param[in] sai SAI to encode. + * \returns string representation of CGI in dynamically-allocated buffer. + */ +char *osmo_sai_name_c(const void *ctx, const struct osmo_service_area_id *sai) +{ + char *buf = talloc_size(ctx, 32); + return osmo_sai_name_buf(buf, 32, sai); +} + + static void to_bcd(uint8_t *bcd, uint16_t val) { bcd[2] = val % 10; diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c index d0560d5f..b823a151 100644 --- a/tests/gsm0808/gsm0808_test.c +++ b/tests/gsm0808/gsm0808_test.c @@ -1080,8 +1080,9 @@ static void test_gsm0808_dec_cell_id_list_srvcc() int rc; rc = gsm0808_dec_cell_id_list2(&dec_cil, enc_cil, sizeof(enc_cil)); - /* Not yet supported: */ - OSMO_ASSERT(rc == -EINVAL); + OSMO_ASSERT(rc == sizeof(enc_cil)); + OSMO_ASSERT(dec_cil.id_discr = CELL_IDENT_SAI); + OSMO_ASSERT(dec_cil.id_list_len = 1); } static void test_gsm0808_enc_dec_cell_id_list_lac() |