From e25786ab6a40fe1fed479d3dd477131718a92e9b Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Wed, 3 May 2023 02:13:16 +0200 Subject: [PATCH] gsm: add osmo_mobile_identity_decode_from_l3_buf() We have osmo_mobile_identity_decode_from_l3(), which takes a msgb as argument, and decodes msg->l3h. Not all callers have their data in this form. Offer a more flexible API for the same decoding. For example, before the new function, osmo-hnbgw, which extracts a NAS PDU from asn.1 packed data for CN pooling, would allocate a new msgb and copy the NAS data just to pass a data pointer as argument. Related: SYS#6412 Change-Id: I9bd99ccd01f0eedc091fe51687ff92ae1fdff60b --- include/osmocom/gsm/gsm48.h | 2 ++ src/gsm/gsm48.c | 41 ++++++++++++++++++++++++++----------- src/gsm/libosmogsm.map | 1 + 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h index 93a9e21dd..8323c724d 100644 --- a/include/osmocom/gsm/gsm48.h +++ b/include/osmocom/gsm/gsm48.h @@ -96,6 +96,8 @@ char *osmo_mobile_identity_to_str_c(void *ctx, const struct osmo_mobile_identity int osmo_mobile_identity_cmp(const struct osmo_mobile_identity *a, const struct osmo_mobile_identity *b); int osmo_mobile_identity_decode(struct osmo_mobile_identity *mi, const uint8_t *mi_data, uint8_t mi_len, bool allow_hex); +int osmo_mobile_identity_decode_from_l3_buf(struct osmo_mobile_identity *mi, const uint8_t *l3_data, size_t l3_len, + bool allow_hex); int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct msgb *msg, bool allow_hex); int osmo_mobile_identity_encoded_len(const struct osmo_mobile_identity *mi, int *mi_digits); int osmo_mobile_identity_encode_buf(uint8_t *buf, size_t buflen, const struct osmo_mobile_identity *mi, bool allow_hex); diff --git a/src/gsm/gsm48.c b/src/gsm/gsm48.c index dee6813fb..df455acb3 100644 --- a/src/gsm/gsm48.c +++ b/src/gsm/gsm48.c @@ -863,11 +863,13 @@ int osmo_mobile_identity_encode_msgb(struct msgb *msg, const struct osmo_mobile_ * osmo_mobile_identity. * * \param[out] mi Return buffer for decoded Mobile Identity. - * \param[in] msg The Complete Layer 3 message to extract from (LU, CM Service Req or Paging Resp). + * \param[in] l3_data The Complete Layer 3 message to extract from (LU, CM Service Req or Paging Resp). + * \param[in] l3_len Length of l3_data in bytes. * \returns 0 on success, negative on error: return codes as defined in osmo_mobile_identity_decode(), or * -ENOTSUP = not a Complete Layer 3 message, */ -int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct msgb *msg, bool allow_hex) +int osmo_mobile_identity_decode_from_l3_buf(struct osmo_mobile_identity *mi, const uint8_t *l3_data, size_t l3_len, + bool allow_hex) { const struct gsm48_hdr *gh; int8_t pdisc = 0; @@ -886,10 +888,10 @@ int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct .tmsi = GSM_RESERVED_TMSI, }; - if (msgb_l3len(msg) < sizeof(*gh)) + if (l3_len < sizeof(*gh)) return -EBADMSG; - gh = msgb_l3(msg); + gh = (void *)l3_data; pdisc = gsm48_hdr_pdisc(gh); mtype = gsm48_hdr_msg_type(gh); @@ -899,12 +901,12 @@ int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct switch (mtype) { case GSM48_MT_MM_LOC_UPD_REQUEST: /* First make sure that lu-> can be dereferenced */ - if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) + if (l3_len < sizeof(*gh) + sizeof(*lu)) return -EBADMSG; /* Now we know there is enough msgb data to read a lu->mi_len, so also check that */ lu = (struct gsm48_loc_upd_req*)gh->data; - if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu) + lu->mi_len) + if (l3_len < sizeof(*gh) + sizeof(*lu) + lu->mi_len) return -EBADMSG; mi_data = lu->mi; mi_len = lu->mi_len; @@ -914,7 +916,7 @@ int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct case GSM48_MT_MM_CM_REEST_REQ: /* Unfortunately in Phase1 the Classmark2 length is variable, so we cannot * just use gsm48_service_request struct, and need to parse it manually. */ - if (msgb_l3len(msg) < sizeof(*gh) + 2) + if (l3_len < sizeof(*gh) + 2) return -EBADMSG; cm2_len = gh->data[1]; @@ -922,7 +924,7 @@ int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct goto got_cm2; case GSM48_MT_MM_IMSI_DETACH_IND: - if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*idi)) + if (l3_len < sizeof(*gh) + sizeof(*idi)) return -EBADMSG; idi = (struct gsm48_imsi_detach_ind*) gh->data; mi_data = idi->mi; @@ -930,7 +932,7 @@ int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct goto got_mi; case GSM48_MT_MM_ID_RESP: - if (msgb_l3len(msg) < sizeof(*gh) + 2) + if (l3_len < sizeof(*gh) + 2) return -EBADMSG; mi_data = gh->data+1; mi_len = gh->data[0]; @@ -945,7 +947,7 @@ int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct switch (mtype) { case GSM48_MT_RR_PAG_RESP: - if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*paging_response)) + if (l3_len < sizeof(*gh) + sizeof(*paging_response)) return -EBADMSG; paging_response = (struct gsm48_pag_resp*)gh->data; cm2_len = paging_response->cm2_len; @@ -964,7 +966,7 @@ got_cm2: /* MI (Mobile Identity) LV follows the Classmark2 */ /* There must be at least a mi_len byte after the CM2 */ - if (cm2_buf + cm2_len + 1 > msg->tail) + if (cm2_buf + cm2_len + 1 > l3_data + l3_len) return -EBADMSG; mi_start = cm2_buf + cm2_len; @@ -973,12 +975,27 @@ got_cm2: got_mi: /* mi_data points at the start of the Mobile Identity coding of mi_len bytes */ - if (mi_data + mi_len > msg->tail) + if (mi_data + mi_len > l3_data + l3_len) return -EBADMSG; return osmo_mobile_identity_decode(mi, mi_data, mi_len, allow_hex); } +/*! Extract Mobile Identity from a Complete Layer 3 message. + * + * Determine the Mobile Identity data and call osmo_mobile_identity_decode() to return a decoded struct + * osmo_mobile_identity. + * + * \param[out] mi Return buffer for decoded Mobile Identity. + * \param[in] msg The Complete Layer 3 message to extract from (LU, CM Service Req or Paging Resp). + * \returns 0 on success, negative on error: return codes as defined in osmo_mobile_identity_decode(), or + * -ENOTSUP = not a Complete Layer 3 message, + */ +int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct msgb *msg, bool allow_hex) +{ + return osmo_mobile_identity_decode_from_l3_buf(mi, msgb_l3(msg), msgb_l3len(msg), allow_hex); +} + /*! Return a human readable representation of a struct osmo_mobile_identity. * Write a string like "IMSI-1234567", "TMSI-0x1234ABCD" or "NONE", "NULL". * \param[out] buf String buffer to write to. diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 6795c5781..0018e1c40 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -391,6 +391,7 @@ osmo_mobile_identity_to_str_buf; osmo_mobile_identity_to_str_c; osmo_mobile_identity_cmp; osmo_mobile_identity_decode; +osmo_mobile_identity_decode_from_l3_buf; osmo_mobile_identity_decode_from_l3; osmo_mobile_identity_encoded_len; osmo_mobile_identity_encode_buf;