mirror of https://gerrit.osmocom.org/libosmocore
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
This commit is contained in:
parent
0423b61aa8
commit
7740d26d7e
|
@ -56,6 +56,22 @@ struct gsm48_classmark2 {
|
|||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct osmo_gsm48_classmark {
|
||||
bool classmark1_set;
|
||||
struct gsm48_classmark1 classmark1;
|
||||
uint8_t classmark2_len;
|
||||
struct gsm48_classmark2 classmark2;
|
||||
uint8_t classmark3_len;
|
||||
uint8_t classmark3[14]; /* if cm3 gets extended by spec, it will be truncated */
|
||||
};
|
||||
|
||||
bool osmo_gsm48_classmark_is_r99(const struct osmo_gsm48_classmark *cm);
|
||||
bool osmo_gsm48_classmark1_is_r99(const struct gsm48_classmark1 *cm1);
|
||||
bool osmo_gsm48_classmark2_is_r99(const struct gsm48_classmark2 *cm2, uint8_t cm2_len);
|
||||
int osmo_gsm48_classmark_supports_a5(const struct osmo_gsm48_classmark *cm, uint8_t a5);
|
||||
const char *osmo_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm);
|
||||
void osmo_gsm48_classmark_update(struct osmo_gsm48_classmark *dst, const struct osmo_gsm48_classmark *src);
|
||||
|
||||
/* Chapter 10.5.2.1b.3 */
|
||||
#if OSMO_IS_LITTLE_ENDIAN == 1
|
||||
struct gsm48_range_1024 {
|
||||
|
|
126
src/gsm/gsm48.c
126
src/gsm/gsm48.c
|
@ -1160,4 +1160,130 @@ const struct value_string osmo_cm_service_type_names[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
bool osmo_gsm48_classmark1_is_r99(const struct gsm48_classmark1 *cm1)
|
||||
{
|
||||
return cm1->rev_lev >= 2;
|
||||
}
|
||||
|
||||
bool osmo_gsm48_classmark2_is_r99(const struct gsm48_classmark2 *cm2, uint8_t cm2_len)
|
||||
{
|
||||
if (!cm2_len)
|
||||
return false;
|
||||
return cm2->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_gsm48_classmark_is_r99(const struct osmo_gsm48_classmark *cm)
|
||||
{
|
||||
if (cm->classmark1_set)
|
||||
return osmo_gsm48_classmark1_is_r99(&cm->classmark1);
|
||||
return osmo_gsm48_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_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm)
|
||||
{
|
||||
static char buf[128];
|
||||
char cm1[42] = "no-cm1";
|
||||
char cm2[42] = " no-cm2";
|
||||
char cm3[42] = " no-cm2";
|
||||
|
||||
if (cm->classmark1_set)
|
||||
snprintf(cm1, sizeof(cm1), "cm1{a5/1=%s}",
|
||||
cm->classmark1.a5_1 ? "not-supported":"supported" /* inverted logic */);
|
||||
|
||||
if (cm->classmark2_len >= 3)
|
||||
snprintf(cm2, sizeof(cm2), " cm2{0x%x=%s%s}",
|
||||
cm->classmark2.a5_2 + (cm->classmark2.a5_3 << 1),
|
||||
cm->classmark2.a5_2 ? " A5/2" : "",
|
||||
cm->classmark2.a5_3 ? " A5/3" : "");
|
||||
|
||||
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" : "");
|
||||
|
||||
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[out] dst The target Classmark storage to be updated.
|
||||
* \param[in] src The new Classmark information to read from.
|
||||
*/
|
||||
void osmo_gsm48_classmark_update(struct osmo_gsm48_classmark *dst, const struct osmo_gsm48_classmark *src)
|
||||
{
|
||||
if (src->classmark1_set) {
|
||||
dst->classmark1 = src->classmark1;
|
||||
dst->classmark1_set = true;
|
||||
}
|
||||
if (src->classmark2_len) {
|
||||
dst->classmark2_len = src->classmark2_len;
|
||||
dst->classmark2 = src->classmark2;
|
||||
}
|
||||
if (src->classmark3_len) {
|
||||
dst->classmark3_len = src->classmark3_len;
|
||||
memcpy(dst->classmark3, src->classmark3, OSMO_MIN(sizeof(dst->classmark3), src->classmark3_len));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! 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_gsm48_classmark_supports_a5(const struct osmo_gsm48_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;
|
||||
/* Inverted logic for this bit! */
|
||||
return cm->classmark1.a5_1 ? 0 : 1;
|
||||
case 2:
|
||||
/* See 3GPP TS 24.008 10.5.1.6 */
|
||||
if (cm->classmark2_len < 3)
|
||||
return -2;
|
||||
return cm->classmark2.a5_2 ? 1 : 0;
|
||||
case 3:
|
||||
if (cm->classmark2_len < 3)
|
||||
return -2;
|
||||
return cm->classmark2.a5_3 ? 1 : 0;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
/* See 3GPP TS 24.008 10.5.1.7 */
|
||||
if (!cm->classmark3_len)
|
||||
return -3;
|
||||
return (cm->classmark3[0] & (1 << (a5-4))) ? 1 : 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @} */
|
||||
|
|
|
@ -580,5 +580,12 @@ osmo_rat_type_names;
|
|||
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: *;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue