gsm: [ABI BREAK] Support CellId SAI, change CellId CGI-PS id number

Those are available in 3GPP TS 48.008 version 16.0.0 Release 16, section
3.2.2.17 Cell Identifier. It can be seen that we have a collision
between the osmocom non-standard format and the SAI standard one.

This is because CGI-PS is not really a TS 48.008 Cell Identifier, but only
specified in TS 48.018 and has no ID number assigned. The CGI-PS was
added there because the whole osmo-bsc neighbour configuration works
with CellIds to manage neighbours, so it felt natural to extend the APIs
to also provide means to use CGI-PS format (TS 48.018 even refers 48.008
existance and mentions there's no explicit ID).

At the time this Cell Identifier was added, the firstly available number
(11) was taken, which was of course a really bad idea since newer
versions of the spec can at some point use it, which is the case if one
checks for instance TS 48.008 Release 16 SAI Cell Id.

There no perfect way to fix this bad decision at the time, but the
CGI-PS is only used in osmo-bsc and only for RIM related purposes, so by
changing the ID of CELL_IDENT_WHOLE_GLOBAL_PS, we only break RIM under
some specific CIs being used, and when an osmo-bsc is built against
older libosmocore and then used at runtime against a newer libosmocore
(which should be rare).
Hence, the downside is acceptable, and by moving the new ID number to be
ouside of the spec proto TS 48.008 range (4 bits), we make sure we don't
have the same problem again in the future.

Related: SYS#5838
Fixes: ca33a71ca8
Change-Id: Id25e563febdb7640174540136225f399515a0089
This commit is contained in:
Pau Espin 2022-02-16 13:09:32 +01:00
parent a87526d53e
commit b5551eec33
7 changed files with 127 additions and 4 deletions

View File

@ -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

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -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 }
};

View File

@ -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;

View File

@ -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()