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/.
Neels Hofmeyr gerrit-no-reply at lists.osmocom.orgNeels Hofmeyr has uploaded this change for review. ( https://gerrit.osmocom.org/12659 Change subject: add osmo_classmark_* API ...................................................................... add osmo_classmark_* API osmo-bsc and osmo-msc implement identical Classmark structures. It makes sense to define once near the gsm48 protocol definitions. Also move along some generic Classmark API from osmo-msc. Change-Id: Ifd27bab0380f7ad0c44c719aa6c8bd62cf7b034c --- M include/osmocom/gsm/protocol/gsm_04_08.h M src/gsm/gsm48.c M src/gsm/libosmogsm.map 3 files changed, 171 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/59/12659/1 diff --git a/include/osmocom/gsm/protocol/gsm_04_08.h b/include/osmocom/gsm/protocol/gsm_04_08.h index 234fa79..1e782d5 100644 --- a/include/osmocom/gsm/protocol/gsm_04_08.h +++ b/include/osmocom/gsm/protocol/gsm_04_08.h @@ -56,6 +56,22 @@ #endif } __attribute__ ((packed)); +struct osmo_classmark { + bool classmark1_set; + struct gsm48_classmark1 classmark1; + uint8_t classmark2_len; + uint8_t classmark2[3]; + uint8_t classmark3_len; + uint8_t classmark3[14]; /* if cm3 gets extended by spec, it will be truncated */ +}; + +bool osmo_classmark_is_r99(const struct osmo_classmark *cm); +bool osmo_classmark1_is_r99(const struct gsm48_classmark1 *cm1); +bool osmo_classmark2_is_r99(const uint8_t *cm2, uint8_t cm2_len); +int osmo_classmark_supports_a5(const struct osmo_classmark *cm, uint8_t a5); +const char *osmo_classmark_a5_name(const struct osmo_classmark *cm); +void osmo_classmark_update(const struct osmo_classmark *src, struct osmo_classmark *dst); + /* Chapter 10.5.2.1b.3 */ #if OSMO_IS_LITTLE_ENDIAN == 1 struct gsm48_range_1024 { diff --git a/src/gsm/gsm48.c b/src/gsm/gsm48.c index 795e98b..dd193a3 100644 --- a/src/gsm/gsm48.c +++ b/src/gsm/gsm48.c @@ -1156,4 +1156,152 @@ {} }; +bool osmo_classmark1_is_r99(const struct gsm48_classmark1 *cm1) +{ + return cm1->rev_lev >= 2; +} + +bool osmo_classmark2_is_r99(const uint8_t *cm2, uint8_t cm2_len) +{ + uint8_t rev_lev; + if (!cm2_len) + return false; + rev_lev = (cm2[0] >> 5) & 0x3; + return rev_lev >= 2; +} + +/*! Return true if any of Classmark 1 or Classmark 2 are present and indicate R99 capability. + * \param[in] cm Classmarks. + * \returns True if R99 or later, false if pre-R99 or no Classmarks are present. + */ +bool osmo_classmark_is_r99(const struct osmo_classmark *cm) +{ + if (cm->classmark1_set) + return osmo_classmark1_is_r99(&cm->classmark1); + return osmo_classmark2_is_r99(cm->classmark2, cm->classmark2_len); +} + +/*! Return a string representation of A5 cipher algorithms indicated by Classmark 1, 2 and 3. + * \param[in] cm Classmarks. + * \returns A statically allocated string like "cm1{a5/1=supported} cm2{0x23= A5/2 A5/3} no-cm3" + */ +const char *osmo_classmark_a5_name(const struct osmo_classmark *cm) +{ + static char buf[128]; + char cm1[42]; + char cm2[42]; + char cm3[42]; + + if (cm->classmark1_set) + snprintf(cm1, sizeof(cm1), "cm1{a5/1=%s}", + cm->classmark1.a5_1 ? "not-supported":"supported" /* inverted logic */); + else + snprintf(cm1, sizeof(cm1), "no-cm1"); + + if (cm->classmark2_len >= 3) + snprintf(cm2, sizeof(cm2), " cm2{0x%x=%s%s}", + cm->classmark2[2], + cm->classmark2[2] & 0x1 ? " A5/2" : "", + cm->classmark2[2] & 0x2 ? " A5/3" : ""); + else + snprintf(cm2, sizeof(cm2), " no-cm2"); + + if (cm->classmark3_len >= 1) + snprintf(cm3, sizeof(cm3), " cm3{0x%x=%s%s%s%s}", + cm->classmark3[0], + cm->classmark3[0] & (1 << 0) ? " A5/4" : "", + cm->classmark3[0] & (1 << 1) ? " A5/5" : "", + cm->classmark3[0] & (1 << 2) ? " A5/6" : "", + cm->classmark3[0] & (1 << 3) ? " A5/7" : ""); + else + snprintf(cm3, sizeof(cm3), " no-cm3"); + + snprintf(buf, sizeof(buf), "%s%s%s", cm1, cm2, cm3); + return buf; +} + +/*! Overwrite dst with the Classmark information present in src. + * Add an new Classmark and overwrite in dst what src has to offer, but where src has no Classmark information, leave + * dst unchanged. (For Classmark 2 and 3, dst will exactly match any non-zero Classmark length from src, hence may end + * up with a shorter Classmark after this call.) + * \param[in] src The new Classmark information to read from. + * \param[out] dst The target Classmark storage to be updated. + */ +void osmo_classmark_update(const struct osmo_classmark *src, struct osmo_classmark *dst) +{ + if (src->classmark1_set) { + dst->classmark1 = src->classmark1; + dst->classmark1_set = true; + } + if (src->classmark2_len) { + dst->classmark2_len = src->classmark2_len; + memcpy(dst->classmark2, src->classmark2, sizeof(dst->classmark2)); + } + if (src->classmark3_len) { + dst->classmark3_len = src->classmark3_len; + memcpy(dst->classmark3, src->classmark3, sizeof(dst->classmark3)); + } +} + + +/*! Determine if the given Classmark (1/2/3) value permits a given A5/n cipher. + * \param[in] cm Classmarks. + * \param[in] a5 The N in A5/N for which to query whether support is indicated. + * \return 1 when the given A5/n is permitted, 0 when not (or a5 > 7), and negative if the respective MS Classmark is + * not known, where the negative number indicates the classmark type: -2 means Classmark 2 is not available. The + * idea is that when e.g. A5/3 is requested and the corresponding Classmark 3 is not available, that the caller + * can react by obtaining Classmark 3 and calling again once it is available. + */ +int osmo_classmark_supports_a5(const struct osmo_classmark *cm, uint8_t a5) +{ + switch (a5) { + case 0: + /* all phones must implement A5/0, see 3GPP TS 43.020 4.9 */ + return 1; + case 1: + /* 3GPP TS 43.020 4.9 requires A5/1 to be suppored by all phones and actually states: + * "The network shall not provide service to an MS which indicates that it does not + * support the ciphering algorithm A5/1.". However, let's be more tolerant based + * on policy here */ + /* See 3GPP TS 24.008 10.5.1.7 */ + if (!cm->classmark1_set) { + return -1; + } else { + if (cm->classmark1.a5_1) + return 0; /* Inverted logic for this bit! */ + else + return 1; + } + break; + case 2: + case 3: + /* See 3GPP TS 24.008 10.5.1.6 */ + if (cm->classmark2_len < 3) { + return -2; + } else { + if (cm->classmark2[2] & (1 << (a5-2))) + return 1; + else + return 0; + } + break; + case 4: + case 5: + case 6: + case 7: + /* See 3GPP TS 24.008 10.5.1.7 */ + if (cm->classmark3_len < 1) { + return -3; + } else { + if (cm->classmark3[0] & (1 << (a5-4))) + return 1; + else + return 0; + } + break; + default: + return 0; + } +} + /*! @} */ diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index da6fba1..54e32da 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -581,5 +581,12 @@ osmo_lu_type_names; osmo_cm_service_type_names; +osmo_classmark_is_r99; +osmo_classmark1_is_r99; +osmo_classmark2_is_r99; +osmo_classmark_supports_a5; +osmo_classmark_a5_name; +osmo_classmark_update; + local: *; }; -- To view, visit https://gerrit.osmocom.org/12659 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-MessageType: newchange Gerrit-Change-Id: Ifd27bab0380f7ad0c44c719aa6c8bd62cf7b034c Gerrit-Change-Number: 12659 Gerrit-PatchSet: 1 Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de> -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190120/049b762c/attachment.htm>