<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/18716">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">use new osmo_mobile_identity API everywhere<br><br>Depends: Ic3f969e739654c1e8c387aedeeba5cce07fe2307 (libosmocore)<br>Change-Id: I4cacb10bac419633ca0c14f244f9903f7f517b49<br>---<br>M src/gbproxy/gb_proxy_patch.c<br>M src/gbproxy/gb_proxy_tlli.c<br>M src/gbproxy/gb_proxy_vty.c<br>M src/gprs/gprs_gb_parse.c<br>M src/sgsn/gprs_gmm.c<br>M tests/gbproxy/gbproxy_test.c<br>6 files changed, 135 insertions(+), 120 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-sgsn refs/changes/16/18716/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/gbproxy/gb_proxy_patch.c b/src/gbproxy/gb_proxy_patch.c</span><br><span>index 6235b04..2bc3b4b 100644</span><br><span>--- a/src/gbproxy/gb_proxy_patch.c</span><br><span>+++ b/src/gbproxy/gb_proxy_patch.c</span><br><span>@@ -436,28 +436,26 @@</span><br><span> int gbproxy_check_imsi(struct gbproxy_match *match,</span><br><span>                     const uint8_t *imsi, size_t imsi_len)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       char mi_buf[200];</span><br><span>    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_mobile_identity mi;</span><br><span> </span><br><span>  if (!match->enable)</span><br><span>               return 1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   rc = gprs_is_mi_imsi(imsi, imsi_len);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (rc > 0)</span><br><span style="color: hsl(0, 100%, 40%);">-          rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = osmo_mobile_identity_decode(&mi, imsi, imsi_len, false);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc || mi.type != GSM_MI_TYPE_IMSI) {</span><br><span>             LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",</span><br><span>                   osmo_hexdump(imsi, imsi_len));</span><br><span>          return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi.imsi, rc);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        rc = regexec(&match->re_comp, mi_buf, 0, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = regexec(&match->re_comp, mi.imsi, 0, NULL, 0);</span><br><span>   if (rc == REG_NOMATCH) {</span><br><span>             LOGP(DGPRS, LOGL_INFO,</span><br><span>                      "IMSI '%s' doesn't match pattern '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                 mi_buf, match->re_str);</span><br><span style="color: hsl(120, 100%, 40%);">+                    mi.imsi, match->re_str);</span><br><span>           return 0;</span><br><span>    }</span><br><span> </span><br><span>diff --git a/src/gbproxy/gb_proxy_tlli.c b/src/gbproxy/gb_proxy_tlli.c</span><br><span>index 4e21ede..e9271c2 100644</span><br><span>--- a/src/gbproxy/gb_proxy_tlli.c</span><br><span>+++ b/src/gbproxy/gb_proxy_tlli.c</span><br><span>@@ -401,14 +401,16 @@</span><br><span>               peer, parse_ctx->imsi, parse_ctx->imsi_len);</span><br><span> </span><br><span>       if (other_link_info && other_link_info != link_info) {</span><br><span style="color: hsl(0, 100%, 40%);">-          char mi_buf[200];</span><br><span style="color: hsl(0, 100%, 40%);">-               mi_buf[0] = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-               gsm48_mi_to_string(mi_buf, sizeof(mi_buf),</span><br><span style="color: hsl(0, 100%, 40%);">-                                 parse_ctx->imsi, parse_ctx->imsi_len);</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGP(DGPRS, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-               "Removing TLLI %08x from list (IMSI %s re-used)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   other_link_info->tlli.current, mi_buf);</span><br><span style="color: hsl(0, 100%, 40%);">-         gbproxy_delete_link_info(peer, other_link_info);</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+               || mi.type != GSM_MI_TYPE_IMSI) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOGP(DGPRS, LOGL_ERROR, "Failed to decode Mobile Identity\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DGPRS, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "Removing TLLI %08x from list (IMSI %s re-used)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         other_link_info->tlli.current, mi.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+                      gbproxy_delete_link_info(peer, other_link_info);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span>    }</span><br><span> </span><br><span>        /* Update the IMSI field */</span><br><span>diff --git a/src/gbproxy/gb_proxy_vty.c b/src/gbproxy/gb_proxy_vty.c</span><br><span>index 5c4f454..355b23f 100644</span><br><span>--- a/src/gbproxy/gb_proxy_vty.c</span><br><span>+++ b/src/gbproxy/gb_proxy_vty.c</span><br><span>@@ -554,7 +554,6 @@</span><br><span>        SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")</span><br><span> {</span><br><span>        struct gbproxy_peer *peer;</span><br><span style="color: hsl(0, 100%, 40%);">-      char mi_buf[200];</span><br><span>    time_t now;</span><br><span>  struct timespec ts = {0,};</span><br><span> </span><br><span>@@ -569,17 +568,20 @@</span><br><span> </span><br><span>           llist_for_each_entry(link_info, &state->logical_links, list) {</span><br><span>                        time_t age = now - link_info->timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+                       const char *imsi_str;</span><br><span> </span><br><span>                    if (link_info->imsi > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                snprintf(mi_buf, sizeof(mi_buf), "(invalid)");</span><br><span style="color: hsl(0, 100%, 40%);">-                                gsm48_mi_to_string(mi_buf, sizeof(mi_buf),</span><br><span style="color: hsl(0, 100%, 40%);">-                                                 link_info->imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                             link_info->imsi_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+                               || mi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+                                   imsi_str = "(invalid)";</span><br><span style="color: hsl(120, 100%, 40%);">+                             else</span><br><span style="color: hsl(120, 100%, 40%);">+                                  imsi_str = mi.imsi;</span><br><span>                  } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                snprintf(mi_buf, sizeof(mi_buf), "(none)");</span><br><span style="color: hsl(120, 100%, 40%);">+                         imsi_str = "(none)";</span><br><span>                       }</span><br><span>                    vty_out(vty, "  TLLI %08x, IMSI %s, AGE %d",</span><br><span style="color: hsl(0, 100%, 40%);">-                          link_info->tlli.current, mi_buf, (int)age);</span><br><span style="color: hsl(120, 100%, 40%);">+                                link_info->tlli.current, imsi_str, (int)age);</span><br><span> </span><br><span>                         if (link_info->stored_msgs_len)</span><br><span>                           vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,</span><br><span>@@ -708,7 +710,6 @@</span><br><span>         struct gbproxy_peer *peer = 0;</span><br><span>       struct gbproxy_link_info *link_info, *nxt;</span><br><span>   struct gbproxy_patch_state *state;</span><br><span style="color: hsl(0, 100%, 40%);">-      char mi_buf[200];</span><br><span>    int found = 0;</span><br><span> </span><br><span>   match = argv[1][0];</span><br><span>@@ -729,6 +730,8 @@</span><br><span>    state = &peer->patch_state;</span><br><span> </span><br><span>       llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>            switch (match) {</span><br><span>             case MATCH_TLLI:</span><br><span>                     if (link_info->tlli.current != ident)</span><br><span>@@ -741,12 +744,10 @@</span><br><span>             case MATCH_IMSI:</span><br><span>                     if (!link_info->imsi)</span><br><span>                             continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       mi_buf[0] = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-                       gsm48_mi_to_string(mi_buf, sizeof(mi_buf),</span><br><span style="color: hsl(0, 100%, 40%);">-                                         link_info->imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     link_info->imsi_len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (strcmp(mi_buf, imsi) != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+                       || mi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (strcmp(mi.imsi, imsi) != 0)</span><br><span>                              continue;</span><br><span>                    break;</span><br><span>               }</span><br><span>diff --git a/src/gprs/gprs_gb_parse.c b/src/gprs/gprs_gb_parse.c</span><br><span>index 379674a..e5de4d4 100644</span><br><span>--- a/src/gprs/gprs_gb_parse.c</span><br><span>+++ b/src/gprs/gprs_gb_parse.c</span><br><span>@@ -604,13 +604,12 @@</span><br><span>       }</span><br><span> </span><br><span>        if (parse_ctx->imsi) {</span><br><span style="color: hsl(0, 100%, 40%);">-               char mi_buf[200];</span><br><span style="color: hsl(0, 100%, 40%);">-               mi_buf[0] = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-               gsm48_mi_to_string(mi_buf, sizeof(mi_buf),</span><br><span style="color: hsl(0, 100%, 40%);">-                                 parse_ctx->imsi, parse_ctx->imsi_len);</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGPC(DGPRS, log_level, "%s IMSI %s",</span><br><span style="color: hsl(0, 100%, 40%);">-              sep, mi_buf);</span><br><span style="color: hsl(0, 100%, 40%);">-              sep = ",";</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false) == 0</span><br><span style="color: hsl(120, 100%, 40%);">+                  && mi.type == GSM_MI_TYPE_IMSI) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOGPC(DGPRS, log_level, "%s IMSI %s", sep, mi.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+                        sep = ",";</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>    }</span><br><span>    if (parse_ctx->invalidate_tlli) {</span><br><span>                 LOGPC(DGPRS, log_level, "%s invalidate", sep);</span><br><span>diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c</span><br><span>index 0391229..38dc1bf 100644</span><br><span>--- a/src/sgsn/gprs_gmm.c</span><br><span>+++ b/src/sgsn/gprs_gmm.c</span><br><span>@@ -280,8 +280,10 @@</span><br><span>     struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT ACK");</span><br><span>     struct gsm48_hdr *gh;</span><br><span>        struct gsm48_attach_ack *aa;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t *mid;</span><br><span>        unsigned long t;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t *l;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span> #if 0</span><br><span>     uint8_t *ptsig;</span><br><span> #endif</span><br><span>@@ -321,9 +323,18 @@</span><br><span> </span><br><span> #ifdef PTMSI_ALLOC</span><br><span>   /* Optional: Allocated P-TMSI */</span><br><span style="color: hsl(0, 100%, 40%);">-        mid = msgb_put(msg, GSM48_MID_TMSI_LEN);</span><br><span style="color: hsl(0, 100%, 40%);">-        gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);</span><br><span style="color: hsl(0, 100%, 40%);">-       mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+    mi = (struct osmo_mobile_identity){</span><br><span style="color: hsl(120, 100%, 40%);">+           .type = GSM_MI_TYPE_TMSI,</span><br><span style="color: hsl(120, 100%, 40%);">+             .tmsi = mm->p_tmsi,</span><br><span style="color: hsl(120, 100%, 40%);">+        };</span><br><span style="color: hsl(120, 100%, 40%);">+    l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGMMCTXP(LOGL_ERROR, mm, "Cannot encode Mobile Identity\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     *l = rc;</span><br><span> #endif</span><br><span> </span><br><span>       /* Optional: MS-identity (combined attach) */</span><br><span>@@ -1026,31 +1037,35 @@</span><br><span> static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)</span><br><span> {</span><br><span>   struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;</span><br><span style="color: hsl(0, 100%, 40%);">-        long mi_typel = mi_type;</span><br><span style="color: hsl(0, 100%, 40%);">-        char mi_string[GSM48_MI_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+        long mi_typel;</span><br><span style="color: hsl(120, 100%, 40%);">+        char mi_log_string[32];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_mobile_identity mi;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);</span><br><span>       if (!ctx) {</span><br><span>          DEBUGP(DMM, "from unknown TLLI 0x%08x?!? This should not happen\n", msgb_tlli(msg));</span><br><span>               return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI(%s)=%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                gsm48_mi_type_name(mi_type), mi_string);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (osmo_mobile_identity_decode(&mi, &gh->data[1], gh->data[0], false)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGMMCTXP(LOGL_ERROR, ctx, "-> GMM IDENTITY RESPONSE: cannot decode Mobile Identity\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_mobile_identity_name_buf(mi_log_string, sizeof(mi_log_string), &mi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI=%s\n", mi_log_string);</span><br><span> </span><br><span>     if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) {</span><br><span>             LOGMMCTXP(LOGL_NOTICE, ctx,</span><br><span style="color: hsl(0, 100%, 40%);">-                       "Got unexpected IDENTITY RESPONSE: MI(%s)=%s, "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "Got unexpected IDENTITY RESPONSE: MI=%s, "</span><br><span>                        "ignoring message\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                         gsm48_mi_type_name(mi_type), mi_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                      mi_log_string);</span><br><span>            return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (mi_type == ctx->t3370_id_type)</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mi.type == ctx->t3370_id_type)</span><br><span>                mmctx_timer_stop(ctx, 3370);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        switch (mi_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (mi.type) {</span><br><span>   case GSM_MI_TYPE_IMSI:</span><br><span>               /* we already have a mm context with current TLLI, but no</span><br><span>             * P-TMSI / IMSI yet.  What we now need to do is to fill</span><br><span>@@ -1058,7 +1073,7 @@</span><br><span>             if (strlen(ctx->imsi) == 0) {</span><br><span>                     /* Check if we already have a MM context for this IMSI */</span><br><span>                    struct sgsn_mm_ctx *ictx;</span><br><span style="color: hsl(0, 100%, 40%);">-                       ictx = sgsn_mm_ctx_by_imsi(mi_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ictx = sgsn_mm_ctx_by_imsi(mi.imsi);</span><br><span>                         if (ictx) {</span><br><span>                          /* Handle it like in gsm48_rx_gmm_det_req,</span><br><span>                            * except that no messages are sent to the BSS */</span><br><span>@@ -1070,16 +1085,17 @@</span><br><span>                          mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");</span><br><span>                     }</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-               osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);</span><br><span>           break;</span><br><span>       case GSM_MI_TYPE_IMEI:</span><br><span style="color: hsl(0, 100%, 40%);">-          osmo_strlcpy(ctx->imei, mi_string, sizeof(ctx->imei));</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_STRLCPY_ARRAY(ctx->imei, mi.imei);</span><br><span>           break;</span><br><span>       case GSM_MI_TYPE_IMEISV:</span><br><span>             break;</span><br><span>       }</span><br><span> </span><br><span>        /* Check if we can let the mobile station enter */</span><br><span style="color: hsl(120, 100%, 40%);">+    mi_typel = mi.type;</span><br><span>  return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_IDEN_RESP_RECV, (void *)mi_typel);</span><br><span> }</span><br><span> </span><br><span>@@ -1131,14 +1147,14 @@</span><br><span>                               struct gprs_llc_llme *llme)</span><br><span> {</span><br><span>     struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t *cur = gh->data, *msnc, *mi, *ms_ra_acc_cap;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t msnc_len, att_type, mi_len, mi_type, ms_ra_acc_cap_len;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t *cur = gh->data, *msnc, *mi_data, *ms_ra_acc_cap;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t msnc_len, att_type, mi_len, ms_ra_acc_cap_len;</span><br><span>       uint16_t drx_par;</span><br><span style="color: hsl(0, 100%, 40%);">-       uint32_t tmsi;</span><br><span style="color: hsl(0, 100%, 40%);">-  char mi_string[GSM48_MI_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+        char mi_log_string[32];</span><br><span>      struct gprs_ra_id ra_id;</span><br><span>     uint16_t cid = 0;</span><br><span>    enum gsm48_gmm_cause reject_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_mobile_identity mi;</span><br><span>      int rc;</span><br><span> </span><br><span>  LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");</span><br><span>@@ -1182,15 +1198,15 @@</span><br><span> </span><br><span>      /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */</span><br><span>      mi_len = *cur++;</span><br><span style="color: hsl(0, 100%, 40%);">-        mi = cur;</span><br><span style="color: hsl(0, 100%, 40%);">-       if (mi_len > 8)</span><br><span style="color: hsl(0, 100%, 40%);">-              goto err_inval;</span><br><span style="color: hsl(0, 100%, 40%);">- mi_type = *mi & GSM_MI_TYPE_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+ mi_data = cur;</span><br><span>       cur += mi_len;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               goto err_inval;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_mobile_identity_name_buf(mi_log_string, sizeof(mi_log_string), &mi);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,</span><br><span style="color: hsl(120, 100%, 40%);">+    DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,</span><br><span>               get_value_string(gprs_att_t_strs, att_type));</span><br><span> </span><br><span>    /* Old routing area identification 10.5.5.15. Skip it */</span><br><span>@@ -1207,11 +1223,11 @@</span><br><span> </span><br><span>       /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    switch (mi_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (mi.type) {</span><br><span>   case GSM_MI_TYPE_IMSI:</span><br><span>               /* Try to find MM context based on IMSI */</span><br><span>           if (!ctx)</span><br><span style="color: hsl(0, 100%, 40%);">-                       ctx = sgsn_mm_ctx_by_imsi(mi_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                 ctx = sgsn_mm_ctx_by_imsi(mi.imsi);</span><br><span>          if (!ctx) {</span><br><span>                  if (MSG_IU_UE_CTX(msg))</span><br><span>                              ctx = sgsn_mm_ctx_alloc_iu(MSG_IU_UE_CTX(msg));</span><br><span>@@ -1221,15 +1237,13 @@</span><br><span>                            reject_cause = GMM_CAUSE_NET_FAIL;</span><br><span>                           goto rejected;</span><br><span>                       }</span><br><span style="color: hsl(0, 100%, 40%);">-                       osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));</span><br><span style="color: hsl(120, 100%, 40%);">+                  OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);</span><br><span>           }</span><br><span>            break;</span><br><span>       case GSM_MI_TYPE_TMSI:</span><br><span style="color: hsl(0, 100%, 40%);">-          memcpy(&tmsi, mi+1, 4);</span><br><span style="color: hsl(0, 100%, 40%);">-             tmsi = ntohl(tmsi);</span><br><span>          /* Try to find MM context based on P-TMSI */</span><br><span>                 if (!ctx)</span><br><span style="color: hsl(0, 100%, 40%);">-                       ctx = sgsn_mm_ctx_by_ptmsi(tmsi);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);</span><br><span>                 if (!ctx) {</span><br><span>                  /* Allocate a context as most of our code expects one.</span><br><span>                        * Context will not have an IMSI ultil ID RESP is received */</span><br><span>@@ -1241,12 +1255,12 @@</span><br><span>                              reject_cause = GMM_CAUSE_NET_FAIL;</span><br><span>                           goto rejected;</span><br><span>                       }</span><br><span style="color: hsl(0, 100%, 40%);">-                       ctx->p_tmsi = tmsi;</span><br><span style="color: hsl(120, 100%, 40%);">+                        ctx->p_tmsi = mi.tmsi;</span><br><span>            }</span><br><span>            break;</span><br><span>       default:</span><br><span>             LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with "</span><br><span style="color: hsl(0, 100%, 40%);">-                  "MI type %s\n", gsm48_mi_type_name(mi_type));</span><br><span style="color: hsl(120, 100%, 40%);">+                       "MI %s\n", mi_log_string);</span><br><span>                 reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;</span><br><span>          goto rejected;</span><br><span>       }</span><br><span>@@ -1275,8 +1289,8 @@</span><br><span>                                       ctx->ciph_algo)) {</span><br><span>             reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;</span><br><span>           LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "</span><br><span style="color: hsl(0, 100%, 40%);">-                         "type %s because MS do not support required %s "</span><br><span style="color: hsl(0, 100%, 40%);">-                      "encryption\n", gsm48_mi_type_name(mi_type),</span><br><span style="color: hsl(120, 100%, 40%);">+                        "%s because MS do not support required %s "</span><br><span style="color: hsl(120, 100%, 40%);">+                         "encryption\n", mi_log_string,</span><br><span>                     get_value_string(gprs_cipher_names,ctx->ciph_algo));</span><br><span>            goto rejected;</span><br><span>       }</span><br><span>@@ -1423,8 +1437,10 @@</span><br><span>   struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 UPD ACK");</span><br><span>     struct gsm48_hdr *gh;</span><br><span>        struct gsm48_ra_upd_ack *rua;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t *mid;</span><br><span>        unsigned long t;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t *l;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_mobile_identity mi;</span><br><span> </span><br><span>  rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);</span><br><span>  LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");</span><br><span>@@ -1454,9 +1470,17 @@</span><br><span> </span><br><span> #ifdef PTMSI_ALLOC</span><br><span>         /* Optional: Allocated P-TMSI */</span><br><span style="color: hsl(0, 100%, 40%);">-        mid = msgb_put(msg, GSM48_MID_TMSI_LEN);</span><br><span style="color: hsl(0, 100%, 40%);">-        gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);</span><br><span style="color: hsl(0, 100%, 40%);">-       mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;</span><br><span style="color: hsl(120, 100%, 40%);">+    mi = (struct osmo_mobile_identity){</span><br><span style="color: hsl(120, 100%, 40%);">+           .type = GSM_MI_TYPE_TMSI,</span><br><span style="color: hsl(120, 100%, 40%);">+             .tmsi = mm->p_tmsi,</span><br><span style="color: hsl(120, 100%, 40%);">+        };</span><br><span style="color: hsl(120, 100%, 40%);">+    l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     *l = rc;</span><br><span> #endif</span><br><span> </span><br><span>       /* Optional: Negotiated READY timer value */</span><br><span>@@ -1606,19 +1630,14 @@</span><br><span>               } else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {</span><br><span> #ifdef BUILD_IU</span><br><span>                     /* In Iu mode search only for ptmsi */</span><br><span style="color: hsl(0, 100%, 40%);">-                  char mi_string[GSM48_MI_SIZE];</span><br><span style="color: hsl(0, 100%, 40%);">-                  uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI);</span><br><span style="color: hsl(0, 100%, 40%);">-                   const uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI);</span><br><span style="color: hsl(0, 100%, 40%);">-                        uint8_t mi_type = *mi & GSM_MI_TYPE_MASK;</span><br><span style="color: hsl(0, 100%, 40%);">-                   uint32_t tmsi;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (mi_type == GSM_MI_TYPE_TMSI) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              memcpy(&tmsi, mi+1, 4);</span><br><span style="color: hsl(0, 100%, 40%);">-                             tmsi = ntohl(tmsi);</span><br><span style="color: hsl(0, 100%, 40%);">-                             mmctx = sgsn_mm_ctx_by_ptmsi(tmsi);</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI),</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI), false)</span><br><span style="color: hsl(120, 100%, 40%);">+                       || mi.type != GSM_MI_TYPE_TMSI) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                           goto rejected;</span><br><span>                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     mmctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);</span><br><span> #else</span><br><span>                      LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR,</span><br><span>                              "Rejecting GMM RA Update Request: No Iu support\n");</span><br><span>@@ -1802,11 +1821,11 @@</span><br><span> static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)</span><br><span> {</span><br><span>       struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t *cur = gh->data, *mi;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t service_type, mi_len, mi_type;</span><br><span style="color: hsl(0, 100%, 40%);">-  uint32_t tmsi;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t *cur = gh->data, *mi_data;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t service_type, mi_len;</span><br><span>        struct tlv_parsed tp;</span><br><span style="color: hsl(0, 100%, 40%);">-   char mi_string[GSM48_MI_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+       char mi_log_string[32];</span><br><span>      enum gsm48_gmm_cause reject_cause;</span><br><span>   int rc;</span><br><span> </span><br><span>@@ -1826,15 +1845,14 @@</span><br><span> </span><br><span>    /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */</span><br><span>      mi_len = *cur++;</span><br><span style="color: hsl(0, 100%, 40%);">-        mi = cur;</span><br><span style="color: hsl(0, 100%, 40%);">-       if (mi_len > 8)</span><br><span style="color: hsl(0, 100%, 40%);">-              goto err_inval;</span><br><span style="color: hsl(0, 100%, 40%);">- mi_type = *mi & GSM_MI_TYPE_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+ mi_data = cur;</span><br><span>       cur += mi_len;</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               goto err_inval;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_mobile_identity_name_buf(mi_log_string, sizeof(mi_log_string), &mi);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,</span><br><span style="color: hsl(120, 100%, 40%);">+    DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,</span><br><span>               get_value_string(gprs_service_t_strs, service_type));</span><br><span> </span><br><span>    LOGPC(DMM, LOGL_INFO, "\n");</span><br><span>@@ -1842,11 +1860,11 @@</span><br><span>     /* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */</span><br><span>       tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       switch (mi_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (mi.type) {</span><br><span>   case GSM_MI_TYPE_IMSI:</span><br><span>               /* Try to find MM context based on IMSI */</span><br><span>           if (!ctx)</span><br><span style="color: hsl(0, 100%, 40%);">-                       ctx = sgsn_mm_ctx_by_imsi(mi_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                 ctx = sgsn_mm_ctx_by_imsi(mi.imsi);</span><br><span>          if (!ctx) {</span><br><span>                  /* FIXME: We need to have a context for service request? */</span><br><span>                  reject_cause = GMM_CAUSE_IMPL_DETACHED;</span><br><span>@@ -1855,11 +1873,9 @@</span><br><span>             msgid2mmctx(ctx, msg);</span><br><span>               break;</span><br><span>       case GSM_MI_TYPE_TMSI:</span><br><span style="color: hsl(0, 100%, 40%);">-          memcpy(&tmsi, mi+1, 4);</span><br><span style="color: hsl(0, 100%, 40%);">-             tmsi = ntohl(tmsi);</span><br><span>          /* Try to find MM context based on P-TMSI */</span><br><span>                 if (!ctx)</span><br><span style="color: hsl(0, 100%, 40%);">-                       ctx = sgsn_mm_ctx_by_ptmsi(tmsi);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);</span><br><span>                 if (!ctx) {</span><br><span>                  /* FIXME: We need to have a context for service request? */</span><br><span>                  reject_cause = GMM_CAUSE_IMPL_DETACHED;</span><br><span>@@ -1869,7 +1885,7 @@</span><br><span>              break;</span><br><span>       default:</span><br><span>             LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "</span><br><span style="color: hsl(0, 100%, 40%);">-                 "MI type %s\n", gsm48_mi_type_name(mi_type));</span><br><span style="color: hsl(120, 100%, 40%);">+                       "MI %s\n", mi_log_string);</span><br><span>                 reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;</span><br><span>          goto rejected;</span><br><span>       }</span><br><span>diff --git a/tests/gbproxy/gbproxy_test.c b/tests/gbproxy/gbproxy_test.c</span><br><span>index 6dfe2c5..6433eb6 100644</span><br><span>--- a/tests/gbproxy/gbproxy_test.c</span><br><span>+++ b/tests/gbproxy/gbproxy_test.c</span><br><span>@@ -158,7 +158,8 @@</span><br><span>                 fprintf(stream, "%*s    TLLI-Cache: %d\n",</span><br><span>                         indent, "", state->logical_link_count);</span><br><span>                 llist_for_each_entry(link_info, &state->logical_links, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   char mi_buf[200];</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_mobile_identity mi;</span><br><span style="color: hsl(120, 100%, 40%);">+                       const char *imsi_str;</span><br><span>                        time_t age = now ? now - link_info->timestamp : 0;</span><br><span>                        int stored_msgs = 0;</span><br><span>                         struct llist_head *iter;</span><br><span>@@ -166,13 +167,14 @@</span><br><span>                     llist_for_each(iter, &link_info->stored_msgs)</span><br><span>                                 stored_msgs++;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                      if (link_info->imsi_len > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            snprintf(mi_buf, sizeof(mi_buf), "(invalid)");</span><br><span style="color: hsl(0, 100%, 40%);">-                                gsm48_mi_to_string(mi_buf, sizeof(mi_buf),</span><br><span style="color: hsl(0, 100%, 40%);">-                                                 link_info->imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                             link_info->imsi_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (link_info->imsi > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+                               || mi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+                                   imsi_str = "(invalid)";</span><br><span style="color: hsl(120, 100%, 40%);">+                             else</span><br><span style="color: hsl(120, 100%, 40%);">+                                  imsi_str = mi.imsi;</span><br><span>                  } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                snprintf(mi_buf, sizeof(mi_buf), "(none)");</span><br><span style="color: hsl(120, 100%, 40%);">+                         imsi_str = "(none)";</span><br><span>                       }</span><br><span>                    fprintf(stream, "%*s      TLLI %08x",</span><br><span>                                   indent, "", link_info->tlli.current);</span><br><span>@@ -186,7 +188,7 @@</span><br><span>                                                link_info->sgsn_tlli.assigned);</span><br><span>                   }</span><br><span>                    fprintf(stream, ", IMSI %s, AGE %d",</span><br><span style="color: hsl(0, 100%, 40%);">-                          mi_buf, (int)age);</span><br><span style="color: hsl(120, 100%, 40%);">+                            imsi_str, (int)age);</span><br><span> </span><br><span>                     if (stored_msgs)</span><br><span>                             fprintf(stream, ", STORED %d", stored_msgs);</span><br><span>@@ -4809,10 +4811,7 @@</span><br><span> </span><br><span>  OSMO_ASSERT(gbproxy_check_imsi(&match, imsi1, ARRAY_SIZE(imsi1)) == 1);</span><br><span>  OSMO_ASSERT(gbproxy_check_imsi(&match, imsi2, ARRAY_SIZE(imsi2)) == 1);</span><br><span style="color: hsl(0, 100%, 40%);">-     /* imsi3_bad contains 0xE and 0xF digits, but the conversion function</span><br><span style="color: hsl(0, 100%, 40%);">-    * doesn't complain, so gbproxy_check_imsi() doesn't return -1 in this</span><br><span style="color: hsl(0, 100%, 40%);">-   * case. */</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_ASSERT(gbproxy_check_imsi(&match, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(gbproxy_check_imsi(&match, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == -1);</span><br><span>         OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi1, ARRAY_SIZE(tmsi1)) == -1);</span><br><span>         OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1);</span><br><span>         OSMO_ASSERT(gbproxy_check_imsi(&match, imei1, ARRAY_SIZE(imei1)) == -1);</span><br><span>@@ -4823,7 +4822,7 @@</span><br><span> </span><br><span>     OSMO_ASSERT(gbproxy_check_imsi(&match, imsi1, ARRAY_SIZE(imsi1)) == 0);</span><br><span>  OSMO_ASSERT(gbproxy_check_imsi(&match, imsi2, ARRAY_SIZE(imsi2)) == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_ASSERT(gbproxy_check_imsi(&match, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(gbproxy_check_imsi(&match, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == -1);</span><br><span>         OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi1, ARRAY_SIZE(tmsi1)) == -1);</span><br><span>         OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1);</span><br><span>         OSMO_ASSERT(gbproxy_check_imsi(&match, imei1, ARRAY_SIZE(imei1)) == -1);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/18716">change 18716</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/c/osmo-sgsn/+/18716"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-sgsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I4cacb10bac419633ca0c14f244f9903f7f517b49 </div>
<div style="display:none"> Gerrit-Change-Number: 18716 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>