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

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ifd27bab0380f7ad0c44c719aa6c8bd62cf7b034c </div>
<div style="display:none"> Gerrit-Change-Number: 12659 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>