aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO-RELEASE1
-rw-r--r--include/osmocom/gsm/gsm0808_utils.h2
-rw-r--r--include/osmocom/gsm/gsm23003.h7
-rw-r--r--include/osmocom/gsm/protocol/gsm_08_08.h5
-rw-r--r--src/gsm/gsm0808_utils.c66
-rw-r--r--src/gsm/gsm23003.c45
-rw-r--r--tests/gsm0808/gsm0808_test.c5
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()