pespin has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/libosmo-gprs/+/32925 )


Change subject: gmm: Implement periodic RAU procedure
......................................................................

gmm: Implement periodic RAU procedure

Related: OS#5501
Change-Id: Ie7cba8a2fe3b97bebc558c957cc1bcbe3cc81dbc
---
M include/osmocom/gprs/gmm/gmm_ms_fsm.h
M include/osmocom/gprs/gmm/gmm_pdu.h
M include/osmocom/gprs/gmm/gmm_private.h
M src/gmm/gmm.c
M src/gmm/gmm_ms_fsm.c
M src/gmm/gmm_pdu.c
M tests/gmm/Makefile.am
M tests/gmm/gmm_prim_test.c
M tests/gmm/gmm_prim_test.err
M tests/gmm/gmm_prim_test.ok
10 files changed, 556 insertions(+), 15 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmo-gprs refs/changes/25/32925/1

diff --git a/include/osmocom/gprs/gmm/gmm_ms_fsm.h 
b/include/osmocom/gprs/gmm/gmm_ms_fsm.h
index 078c535..1ebc53c 100644
--- a/include/osmocom/gprs/gmm/gmm_ms_fsm.h
+++ b/include/osmocom/gprs/gmm/gmm_ms_fsm.h
@@ -5,6 +5,20 @@

 struct gprs_gmm_entity;

+/* Update type 10.5.5.18 */
+enum gprs_gmm_upd_type {
+       GPRS_GMM_UPD_TYPE_RA = 0,
+       GPRS_GMM_UPD_TYPE_COMBINED_RA_LA = 1,
+       GPRS_GMM_UPD_TYPE_COMBINED_RA_LA_IMSI = 2,
+       GPRS_GMM_UPD_TYPE_PERIODIC = 3,
+       /* others: reserved */
+};
+extern const struct value_string gprs_gmm_upd_type_names[];
+static inline const char *gprs_gmm_upd_type_name(enum gprs_gmm_upd_type val)
+{
+       return get_value_string(gprs_gmm_upd_type_names, val);
+}
+
 /* 3GPP TS 24.008 ยง 4.1.3.1 GMM states in the MS */
 enum gprs_gmm_ms_fsm_states {
        GPRS_GMM_MS_ST_NULL,                    /* 4.1.3.1.1.1 */
@@ -58,12 +72,20 @@
        enum osmo_gprs_gmm_detach_poweroff_type poweroff_type;
 };

+/* Info about last initiated RAU: */
+struct gprs_gmm_ms_fsm_rau_ctx {
+       enum gprs_gmm_upd_type type;
+       /* Retransmission of RAU REQUEST (4.7.5.1.5) */
+       uint8_t req_attempts;
+};
+
 struct gprs_gmm_ms_fsm_ctx {
        struct osmo_fsm_inst *fi;
        struct gprs_gmm_entity *gmme;

        struct gprs_gmm_ms_fsm_attach_ctx attach;
        struct gprs_gmm_ms_fsm_detach_ctx detach;
+       struct gprs_gmm_ms_fsm_rau_ctx rau;
 };

 int gprs_gmm_ms_fsm_init(void);
@@ -81,3 +103,5 @@
                                       enum osmo_gprs_gmm_detach_ms_type 
detach_type,
                                       enum osmo_gprs_gmm_detach_poweroff_type 
poweroff_type);

+int gprs_gmm_ms_fsm_ctx_request_rau(struct gprs_gmm_ms_fsm_ctx *ctx,
+                                   enum gprs_gmm_upd_type rau_type);
diff --git a/include/osmocom/gprs/gmm/gmm_pdu.h 
b/include/osmocom/gprs/gmm/gmm_pdu.h
index 323b2c7..a0a840f 100644
--- a/include/osmocom/gprs/gmm/gmm_pdu.h
+++ b/include/osmocom/gprs/gmm/gmm_pdu.h
@@ -5,6 +5,7 @@
 #include <osmocom/gsm/tlv.h>

 struct gprs_gmm_entity;
+enum gprs_gmm_upd_type;

 #define GPRS_GMM_ALLOC_SIZE        2048
 #define  GPRS_GMM_ALLOC_HEADROOM    256
@@ -36,3 +37,9 @@
                              enum osmo_gprs_gmm_detach_ms_type detach_type,
                              enum osmo_gprs_gmm_detach_poweroff_type 
poweroff_type,
                              struct msgb *msg);
+
+int gprs_gmm_build_rau_req(struct gprs_gmm_entity *gmme,
+                          enum gprs_gmm_upd_type rau_type,
+                          struct msgb *msg);
+
+int gprs_gmm_build_rau_compl(struct gprs_gmm_entity *gmme, struct msgb *msg);
diff --git a/include/osmocom/gprs/gmm/gmm_private.h 
b/include/osmocom/gprs/gmm/gmm_private.h
index daa967f..d93f724 100644
--- a/include/osmocom/gprs/gmm/gmm_private.h
+++ b/include/osmocom/gprs/gmm/gmm_private.h
@@ -126,6 +126,7 @@
 int gprs_gmm_tx_detach_req(struct gprs_gmm_entity *gmme,
                           enum osmo_gprs_gmm_detach_ms_type detach_type,
                           enum osmo_gprs_gmm_detach_poweroff_type 
poweroff_type);
+int gprs_gmm_tx_rau_req(struct gprs_gmm_entity *gmme, enum gprs_gmm_upd_type 
rau_type);
 int gprs_gmm_tx_ciph_auth_resp(const struct gprs_gmm_entity *gmme, const 
uint8_t *sres);

 int gprs_gmm_submit_gmmreg_attach_cnf(struct gprs_gmm_entity *gmme, bool 
accepted, uint8_t cause);
diff --git a/src/gmm/gmm.c b/src/gmm/gmm.c
index 6184a01..38ebc98 100644
--- a/src/gmm/gmm.c
+++ b/src/gmm/gmm.c
@@ -78,6 +78,14 @@
        { 0 } /* empty item at the end */
 };

+const struct value_string gprs_gmm_upd_type_names[] = {
+       { GPRS_GMM_UPD_TYPE_RA, "RA updating" },
+       { GPRS_GMM_UPD_TYPE_COMBINED_RA_LA, "Combined RA/LA updating" },
+       { GPRS_GMM_UPD_TYPE_COMBINED_RA_LA_IMSI, "Combined RA/LA updating with 
IMSI attac" },
+       { GPRS_GMM_UPD_TYPE_PERIODIC,   "Periodic updating" },
+       { 0, NULL }
+};
+
 static void t3314_ready_timer_cb(void *data);
 static void t3312_periodic_rau_timer_cb(void *data);

@@ -296,7 +304,7 @@
 {
        if (gmme->t3314_assigned_sec == 0)
                return;
-       LOGGMME(gmme, LOGL_INFO, "READY timer started\n");
+       LOGGMME(gmme, LOGL_INFO, "READY timer started (expires in %lu 
seconds)\n", gmme->t3314_assigned_sec);
        osmo_timer_schedule(&gmme->t3314, gmme->t3314_assigned_sec, 0);

        /* "Timer T3312 is stopped and shall be set to its initial value
@@ -341,14 +349,11 @@
 /* T3312 (Periodic RAU) is started: */
 void gprs_gmm_gmme_t3312_start(struct gprs_gmm_entity *gmme)
 {
-       unsigned long t3312_sec;
-
-       t3312_sec = osmo_tdef_get(g_gmm_ctx->T_defs, 3312, OSMO_TDEF_S, -1);
-       if (t3312_sec == 0)
+       if (gmme->t3312_assigned_sec == 0)
                return;

-       LOGGMME(gmme, LOGL_INFO, "T3312 started\n");
-       osmo_timer_schedule(&gmme->t3312, t3312_sec, 0);
+       LOGGMME(gmme, LOGL_INFO, "T3312 started (expires in %lu seconds)\n", 
gmme->t3312_assigned_sec);
+       osmo_timer_schedule(&gmme->t3312, gmme->t3312_assigned_sec, 0);
 }

 /* T3312 (Periodic RAU) is stopped: */
@@ -380,6 +385,8 @@
         *   routing area updating procedure when it returns to state
         *   GMM-REGISTERED.NORMAL-SERVICE."
         */
+       gprs_gmm_ms_fsm_ctx_request_rau(&gmme->ms_fsm, 
GPRS_GMM_UPD_TYPE_PERIODIC);
+
 }

 int gprs_gmm_submit_gmmreg_attach_cnf(struct gprs_gmm_entity *gmme, bool 
accepted, uint8_t cause)
@@ -641,6 +648,71 @@
        return rc;
 }

+/* Tx GMM Routing area update request, 9.4.14 */
+int gprs_gmm_tx_rau_req(struct gprs_gmm_entity *gmme,
+                       enum gprs_gmm_upd_type rau_type)
+{
+       struct osmo_gprs_llc_prim *llc_prim;
+       int rc;
+       struct msgb *msg;
+
+       LOGGMME(gmme, LOGL_INFO, "Tx GMM RAU REQUEST\n");
+       llc_prim = osmo_gprs_llc_prim_alloc_ll_unitdata_req(
+                       gmme->tlli, OSMO_GPRS_LLC_SAPI_GMM, NULL, 
GPRS_GMM_ALLOC_SIZE);
+       msg = llc_prim->oph.msg;
+       msg->l3h = msg->tail;
+       rc = gprs_gmm_build_rau_req(gmme, rau_type, msg);
+       if (rc < 0) {
+               msgb_free(msg);
+               return -EBADMSG;
+       }
+       llc_prim->ll.l3_pdu = msg->l3h;
+       llc_prim->ll.l3_pdu_len = msgb_l3len(msg);
+       /* TODO:
+       llc_prim->ll.qos_params.*;
+       llc_prim->ll.radio_prio;
+       llc_prim->ll.apply_gea;
+       llc_prim->ll.apply_gia;
+       */
+
+       rc = gprs_gmm_prim_call_llc_down_cb(llc_prim);
+
+       return rc;
+}
+
+/* Tx GMM Routing area update complete, 9.4.16 */
+static int gprs_gmm_tx_rau_compl(struct gprs_gmm_entity *gmme)
+{
+       struct osmo_gprs_llc_prim *llc_prim;
+       int rc;
+       struct msgb *msg;
+
+       LOGGMME(gmme, LOGL_INFO, "Tx GMM RAU COMPL\n");
+
+       llc_prim = osmo_gprs_llc_prim_alloc_ll_unitdata_req(
+                       gmme->tlli, OSMO_GPRS_LLC_SAPI_GMM, NULL, 
GPRS_GMM_ALLOC_SIZE);
+       msg = llc_prim->oph.msg;
+       msg->l3h = msg->tail;
+       rc = gprs_gmm_build_rau_compl(gmme, msg);
+       if (rc < 0) {
+               msgb_free(msg);
+               return -EBADMSG;
+       }
+       llc_prim->ll.l3_pdu = msg->l3h;
+       llc_prim->ll.l3_pdu_len = msgb_l3len(msg);
+       /* TODO:
+       llc_prim->ll.qos_params.*;
+       llc_prim->ll.radio_prio;
+       llc_prim->ll.apply_gea;
+       llc_prim->ll.apply_gia;
+       */
+
+       rc = gprs_gmm_prim_call_llc_down_cb(llc_prim);
+       if (rc < 0)
+               return rc;
+       return rc;
+}
+
 static int gprs_gmm_rx_att_ack(struct gprs_gmm_entity *gmme, struct gsm48_hdr 
*gh, unsigned int len)
 {
        struct gsm48_attach_ack *aa;
@@ -815,6 +887,130 @@
        return -EINVAL; /* TODO: what to do on error? */
 }

+/* Rx Routing area update accept, 9.4.15 */
+static int gprs_gmm_rx_rau_acc(struct gprs_gmm_entity *gmme, struct gsm48_hdr 
*gh, unsigned int len)
+{
+       struct gsm48_ra_upd_ack *raack;
+       struct tlv_parsed tp;
+       int rc;
+       int periodic_rau_sec;
+
+       if (len < sizeof(*gh) + sizeof(*raack)) {
+               LOGGMME(gmme, LOGL_ERROR, "Rx GMM RAU ACCEPT with wrong size 
%u\n", len);
+               goto rejected;
+       }
+
+       raack = (struct gsm48_ra_upd_ack *)&gh->data[0];
+       LOGGMME(gmme, LOGL_INFO, "Rx GMM RAU ACCEPT upd_result=0x%02x\n", 
raack->upd_result);
+
+       /* TODO: check raack->upd_result */
+
+       periodic_rau_sec = gprs_gmm_gprs_tmr_to_secs(raack->ra_upd_timer);
+       gmme->t3312_assigned_sec = periodic_rau_sec >= 0 ? periodic_rau_sec : 0;
+       if (gmme->t3312_assigned_sec == 0)
+               gprs_gmm_gmme_t3312_stop(gmme);
+       gsm48_parse_ra(&gmme->ra, (const uint8_t *)&raack->ra_id);
+
+       if (len > sizeof(*gh) + sizeof(*raack)) {
+               rc = gprs_gmm_tlv_parse(&tp, &raack->data[0],
+                                       len - (sizeof(*gh) + sizeof(*raack)));
+               if (rc < 0) {
+                       LOGGMME(gmme, LOGL_ERROR, "Rx GMM RAU ACCEPT: failed to 
parse TLVs %d\n", rc);
+                       goto rejected;
+               }
+
+               /* 10.5.5.8 P-TMSI signature */
+               if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PTMSI_SIG)) {
+                       const uint8_t *ptmsi_sig = TLVP_VAL(&tp, 
GSM48_IE_GMM_PTMSI_SIG);
+                       gmme->ptmsi_sig = (ptmsi_sig[0] << 8) | (ptmsi_sig[1] 
<< 4) | ptmsi_sig[2];
+               } else {
+                       gmme->ptmsi_sig = GSM_RESERVED_TMSI;
+               }
+
+               /* 10.5.1.4 Allocated P-TMSI */
+               if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
+                       struct osmo_mobile_identity mi;
+                       if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, 
GSM48_IE_GMM_ALLOC_PTMSI),
+                                                       TLVP_LEN(&tp, 
GSM48_IE_GMM_ALLOC_PTMSI), false)
+                           || mi.type != GSM_MI_TYPE_TMSI) {
+                               LOGGMME(gmme, LOGL_ERROR, "Cannot decode 
P-TMSI\n");
+                               goto rejected;
+                       }
+                       gmme->old_ptmsi = gmme->ptmsi;
+                       gmme->ptmsi = mi.tmsi;
+                       /* TS 24.008 4.7.1.4.1:"Upon receipt of the assigned 
P-TMSI, the MS
+                        * shall derive the local TLLI from this P-TMSI and 
shall use it for
+                        * addressing at lower layers": */
+                       gmme->old_tlli = gmme->tlli;
+                       gmme->tlli = gprs_tmsi2tlli(gmme->ptmsi, TLLI_LOCAL);
+               }
+               /* FIXME! what to do it PTMSI changes? probably need to update 
other layers... Check GPRS ATTACH ACCEPT func */
+
+               /* 10.5.1.4 MS identity */
+               if (TLVP_PRESENT(&tp, GSM48_IE_GMM_IMEISV)) {
+                       struct osmo_mobile_identity mi;
+                       if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, 
GSM48_IE_GMM_IMEISV),
+                                                       TLVP_LEN(&tp, 
GSM48_IE_GMM_IMEISV), false)
+                           || mi.type != GSM_MI_TYPE_IMEISV) {
+                               LOGGMME(gmme, LOGL_ERROR, "Cannot decode 
IMEISV\n");
+                               goto rejected;
+                       }
+                       /* TODO: */
+               }
+
+               /* 10.5.5.11 List of Receive N-PDU Numbers: TODO */
+
+               /* 10.5.7.3 Negotiated READY timer value */
+               if (TLVP_PRESENT(&tp, GSM48_IE_GMM_TIMER_READY)) {
+                       int secs = gprs_gmm_gprs_tmr_to_secs(*TLVP_VAL(&tp, 
GSM48_IE_GMM_TIMER_READY));
+                       gmme->t3314_assigned_sec = secs >= 0 ? secs : 0;
+               } else {
+                       /* Apply the requested value: */
+                       gmme->t3314_assigned_sec = 
osmo_tdef_get(g_gmm_ctx->T_defs, 3314, OSMO_TDEF_S, -1);
+               }
+               /* "If the negotiated READY timer value is set to zero, the 
READY timer shall be stopped immediately": */
+               if (gmme->t3314_assigned_sec == 0) {
+                       gprs_gmm_gmme_ready_timer_stop(gmme);
+                       /* "If after a READY timer negotiation the READY timer
+                        * value is set to zero, timer T3312 is reset and 
started
+                        * with its initial value." */
+                       gprs_gmm_gmme_t3312_start(gmme);
+               }
+
+               /* 10.5.5.14 GMM cause: TODO */
+
+               /* 10.5.7.4 T3302 value */
+               if (TLVP_PRES_LEN(&tp, GSM48_IE_GMM_TIMER_T3302, 1))
+                       gmme->t3302 = *TLVP_VAL(&tp, GSM48_IE_GMM_TIMER_T3302);
+
+               /* 10.5.1.13 Equivalent PLMNs: TODO */
+               /* 10.5.7.1 PDP context status: TODO */
+
+               /* TODO: lots more Optional IEs */
+       }
+
+       /* Submit LLGMM-ASSIGN-REQ as per TS 24.007 Annex C.1 */
+       rc = gprs_gmm_submit_llgmm_assing_req(gmme);
+       if (rc < 0)
+               goto rejected;
+
+       /* Submit GMMRR-ASSIGN-REQ as per TS 24.007 Annex C.1 */
+       rc = gprs_gmm_submit_gmmrr_assing_req(gmme);
+       if (rc < 0)
+               goto rejected;
+
+       rc = gprs_gmm_tx_rau_compl(gmme);
+       if (rc < 0)
+               goto rejected;
+
+       rc = osmo_fsm_inst_dispatch(gmme->ms_fsm.fi, 
GPRS_GMM_MS_EV_RAU_ACCEPTED, NULL);
+
+       return rc;
+
+rejected:
+       return -EINVAL; /* TODO: what to do on error? */
+}
+
 /* Rx GMM Identity Request, 9.2.10 */
 static int gprs_gmm_rx_id_req(struct gprs_gmm_entity *gmme, struct gsm48_hdr 
*gh, unsigned int len)
 {
@@ -916,6 +1112,9 @@
        case GSM48_MT_GMM_DETACH_ACK:
                rc = gprs_gmm_rx_detach_accept(gmme, gh, len);
                break;
+       case GSM48_MT_GMM_RA_UPD_ACK:
+               rc = gprs_gmm_rx_rau_acc(gmme, gh, len);
+               break;
        case GSM48_MT_GMM_ID_REQ:
                rc = gprs_gmm_rx_id_req(gmme, gh, len);
                break;
diff --git a/src/gmm/gmm_ms_fsm.c b/src/gmm/gmm_ms_fsm.c
index 889d82a..fbfc41c 100644
--- a/src/gmm/gmm_ms_fsm.c
+++ b/src/gmm/gmm_ms_fsm.c
@@ -35,7 +35,7 @@
        [GPRS_GMM_MS_ST_REGISTERED_INITIATED] =         { .T = 3310 },
        [GPRS_GMM_MS_ST_REGISTERED] =                   {},
        [GPRS_GMM_MS_ST_DEREGISTERED_INITIATED] =       {},
-       [GPRS_GMM_MS_ST_RAU_INITIATED] =                {},
+       [GPRS_GMM_MS_ST_RAU_INITIATED] =                { .T = 3330 },
        [GPRS_GMM_MS_ST_SR_INITIATED] =                 {},

 };
@@ -59,6 +59,19 @@
                            ctx->attach.with_imsi);
 }

+static int reinit_rau_proc(struct gprs_gmm_ms_fsm_ctx *ctx)
+{
+       unsigned long val_sec;
+
+       OSMO_ASSERT(ctx->fi->state == GPRS_GMM_MS_ST_RAU_INITIATED);
+
+       /* Rearm T3330 */
+       OSMO_ASSERT(ctx->fi->T == 3330);
+       val_sec = osmo_tdef_get(g_gmm_ctx->T_defs, ctx->fi->T, OSMO_TDEF_S, -1);
+       osmo_timer_schedule(&ctx->fi->timer, val_sec, 0);
+       return gprs_gmm_tx_rau_req(ctx->gmme, ctx->rau.type);
+}
+
 static void st_gmm_ms_null(struct osmo_fsm_inst *fi, uint32_t event, void 
*data)
 {
        switch (event) {
@@ -168,11 +181,18 @@

 static void st_gmm_ms_registered(struct osmo_fsm_inst *fi, uint32_t event, 
void *data)
 {
+       struct gprs_gmm_ms_fsm_ctx *ctx = (struct gprs_gmm_ms_fsm_ctx 
*)fi->priv;
+       int rc;
+
        switch (event) {
        case GPRS_GMM_MS_EV_SR_REQUESTED:
                gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_REGISTERED);
                break;
        case GPRS_GMM_MS_EV_RAU_REQUESTED:
+               rc = gprs_gmm_tx_rau_req(ctx->gmme,
+                                        ctx->rau.type);
+               if (rc < 0)
+                       return;
                gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_RAU_INITIATED);
                break;
        case GPRS_GMM_MS_EV_DETACH_REQUESTED:
@@ -347,7 +367,7 @@

        switch (fi->T) {
        case 3310:
-               /* TS 23.008 clause 4.7.3.1.5 c) */
+               /* TS 24.008 clause 4.7.3.1.5 c) */
                ctx->attach.req_attempts++;
                LOGPFSML(ctx->fi, LOGL_INFO, "T3310 timeout attempts=%u\n", 
ctx->attach.req_attempts);
                OSMO_ASSERT(fi->state == GPRS_GMM_MS_ST_REGISTERED_INITIATED);
@@ -360,6 +380,20 @@
                }
                reinit_attach_proc(ctx);
                break;
+       case 3330:
+               /* TS 24.008 clause 4.7.5.1.5 c) */
+               ctx->rau.req_attempts++;
+               LOGPFSML(ctx->fi, LOGL_INFO, "T3330 timeout attempts=%u\n", 
ctx->rau.req_attempts);
+               OSMO_ASSERT(fi->state == GPRS_GMM_MS_ST_RAU_INITIATED);
+               if (ctx->rau.req_attempts == 4) {
+                       /* "On the fifth expiry of timer T3330, the MS shall
+                        *  abort the GPRS attach procedure" */
+                       LOGPFSML(ctx->fi, LOGL_NOTICE, "GPRS RAU procedure 
failure (T3330 timeout attempts=%u)\n", ctx->rau.req_attempts);
+                       osmo_fsm_inst_dispatch(ctx->fi, 
GPRS_GMM_MS_EV_LOW_LVL_FAIL, NULL);
+                       return 0;
+               }
+               reinit_rau_proc(ctx);
+               break;
        default:
                OSMO_ASSERT(0);
        }
@@ -449,3 +483,14 @@
        rc = gprs_gmm_tx_detach_req(ctx->gmme, detach_type, poweroff_type);
        return rc;
 }
+
+int gprs_gmm_ms_fsm_ctx_request_rau(struct gprs_gmm_ms_fsm_ctx *ctx,
+                                   enum gprs_gmm_upd_type rau_type)
+{
+       int rc = 0;
+
+       ctx->rau.type = rau_type;
+       rc = osmo_fsm_inst_dispatch(ctx->fi, GPRS_GMM_MS_EV_RAU_REQUESTED, 
NULL);
+
+       return rc;
+}
diff --git a/src/gmm/gmm_pdu.c b/src/gmm/gmm_pdu.c
index c6c8118..ae0baef 100644
--- a/src/gmm/gmm_pdu.c
+++ b/src/gmm/gmm_pdu.c
@@ -151,6 +151,26 @@
        },
 };

+static int encode_ms_net_cap(struct gprs_gmm_entity *gmme, struct msgb *msg)
+{
+       int rc;
+       uint8_t *l; /* len */
+       struct bitvec bv = {
+               .data = msg->tail,
+               .data_len = GSM_MACBLOCK_LEN,
+       };
+
+       msgb_put_u8(msg, GSM48_IE_GMM_MS_NET_CAPA);
+
+       l = msgb_put(msg, 1); /* len */
+
+       /* TODO: we hardcode a MS Net Cap for now. We may want to pass it from 
the app at some point: */
+       rc = bitvec_unhex(&bv, "e5e0");
+       *l = OSMO_BYTES_FOR_BITS(bv.cur_bit);
+       msgb_put(msg, *l);
+       return rc;
+}
+
 static int encode_ms_ra_acc_cap(struct gprs_gmm_entity *gmme, struct msgb *msg)
 {
        int rc;
@@ -264,6 +284,68 @@
        return 0;
 }

+/* Chapter 9.4.14: Routing area update request */
+int gprs_gmm_build_rau_req(struct gprs_gmm_entity *gmme,
+                          enum gprs_gmm_upd_type rau_type,
+                          struct msgb *msg)
+{
+       struct gsm48_hdr *gh;
+       uint8_t byte, cksn;
+       int rc;
+       struct gsm48_ra_id *raid_enc;
+       unsigned long t3314_sec;
+       uint8_t ptmsi_type_native = 1; /* Table 10.5.5.29.1 */
+
+       gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+       gh->proto_discr = GSM48_PDISC_MM_GPRS;
+       gh->msg_type = GSM48_MT_GMM_RA_UPD_REQ;
+
+       /* 10.5.5.18 Update type */
+       cksn = gmme->auth_ciph.req.key_seq;
+       byte = (cksn << 4) | (((uint8_t)rau_type) & 0x07);
+       msgb_put_u8(msg, byte);
+
+       /* Old routing area identification 0.5.5.15 */
+       raid_enc = (struct gsm48_ra_id *)msgb_put(msg, sizeof(struct 
gsm48_ra_id));
+       gsm48_encode_ra(raid_enc, &gmme->ra);
+
+       /* MS Radio Access capability 10.5.5.12a */
+       rc = encode_ms_ra_acc_cap(gmme, msg);
+       if (rc < 0)
+               return -EINVAL;
+
+       /* 10.5.5.8 Old P-TMSI signature: */
+       if (gmme->ptmsi_sig != GSM_RESERVED_TMSI) {
+               uint8_t ptmsi_sig[3] = { gmme->ptmsi_sig >> 16, gmme->ptmsi_sig 
>> 8, gmme->ptmsi_sig };
+               msgb_tv_fixed_put(msg, GSM48_IE_GMM_PTMSI_SIG, 
sizeof(ptmsi_sig), ptmsi_sig);
+       }
+
+       /* 10.5.7.3 Requested READY timer value */
+       t3314_sec = osmo_tdef_get(g_gmm_ctx->T_defs, 3314, OSMO_TDEF_S, -1);
+       msgb_tv_put(msg, GSM48_IE_GMM_TIMER_READY, 
gprs_gmm_secs_to_gprs_tmr_floor(t3314_sec));
+
+       /* DRX parameter 10.5.5.6 */
+       memcpy(msgb_put(msg, sizeof(drx_param_def)),
+              &drx_param_def,
+              sizeof(drx_param_def));
+
+       /* 9.4.14.6 MS network capability */
+       rc = encode_ms_net_cap(gmme, msg);
+       if (rc < 0)
+               return -EINVAL;
+
+       /* 9.4.14.7 PDP context status */
+       /* TODO: implement. Table 9.4.14/3GPP TS 24.00 states it is optional 
(O) but 9.4.14.7 states:
+        * "This IE shall be included by the MS." */
+
+       /* 9.4.14.17 P-TMSI type */
+       /* Table 9.4.14/3GPP TS 24.00 states it is optional (O) but 9.4.14.17 
states:
+        * "This IE shall be included by the MS." */
+       msgb_v_put(msg, (GSM48_IE_GMM_PTMSI_TYPE << 4) | (ptmsi_type_native & 
0x01));
+
+       return 0;
+}
+
 /* 9.2.11 Identity response */
 int gprs_gmm_build_identity_resp(struct gprs_gmm_entity *gmme,
                                 uint8_t mi_type,
@@ -394,3 +476,15 @@
        /* TODO: optional fields: P-TMSI signature 10.5.5.8a */
        return 0;
 }
+
+int gprs_gmm_build_rau_compl(struct gprs_gmm_entity *gmme, struct msgb *msg)
+{
+       struct gsm48_hdr *gh;
+
+       gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+       gh->proto_discr = GSM48_PDISC_MM_GPRS;
+       gh->msg_type = GSM48_MT_GMM_RA_UPD_COMPL;
+
+       /* TODO: Add optional IEs */
+       return 0;
+}
diff --git a/tests/gmm/Makefile.am b/tests/gmm/Makefile.am
index d066c5e..83517e5 100644
--- a/tests/gmm/Makefile.am
+++ b/tests/gmm/Makefile.am
@@ -38,10 +38,13 @@
        $(NULL)

 # libosmo-gprs-llc.a is used below to access non-exported private symbols used 
in the test:
+# libosmo-gprs-rlcmac.a is used below to access non-exported private symbols 
used in the test:
 gmm_prim_test_SOURCES = gmm_prim_test.c
 gmm_prim_test_LDADD = \
        $(top_builddir)/src/gmm/libosmo-gprs-gmm.la \
        $(top_builddir)/src/llc/.libs/libosmo-gprs-llc.a \
+       $(top_builddir)/src/rlcmac/.libs/libosmo-gprs-rlcmac.a \
+       $(top_builddir)/src/csn1/libosmo-csn1.la \
        $(LIBOSMOCORE_LIBS) \
        $(LIBOSMOGSM_LIBS) \
        $(NULL)
diff --git a/tests/gmm/gmm_prim_test.c b/tests/gmm/gmm_prim_test.c
index b403829..7eefc73 100644
--- a/tests/gmm/gmm_prim_test.c
+++ b/tests/gmm/gmm_prim_test.c
@@ -28,7 +28,11 @@
 #include <osmocom/core/utils.h>
 #include <osmocom/core/fsm.h>
 #include <osmocom/core/msgb.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/timer_compat.h>
+#include <osmocom/core/select.h>

+#include <osmocom/gprs/rlcmac/rlcmac_private.h>
 #include <osmocom/gprs/llc/llc_prim.h>
 #include <osmocom/gprs/llc/llc_private.h>
 #include <osmocom/gprs/gmm/gmm.h>
@@ -133,6 +137,46 @@
 0xea, 0x71, 0x1b, 0x41
 };

+/*
+GSM A-I/F DTAP - Routing Area Update Accept
+ Protocol Discriminator: GPRS mobility management messages (8)
+  .... 1000 = Protocol discriminator: GPRS mobility management messages (0x8)
+  0000 .... = Skip Indicator: No indication of selected PLMN (0)
+ DTAP GPRS Mobility Management Message Type: Routing Area Update Accept (0x09)
+ Force to Standby
+  .... 0... = Spare bit(s): 0
+  .... .000 = Force to standby: Force to standby not indicated (0)
+ Update Result
+  .000 .... = Update Result: RA updated (0)
+ GPRS Timer - Periodic RA update timer
+  GPRS Timer: 10 sec
+   000. .... = Unit: value is incremented in multiples of 2 seconds (0)
+   ...0 0101 = Timer value: 5
+ Routing Area Identification - RAI: 234-70-5-0
+  Routing area identification: 234-70-5-0
+   Mobile Country Code (MCC): United Kingdom (234)
+   Mobile Network Code (MNC): AMSUK Limited (70)
+   Location Area Code (LAC): 0x0005 (5)
+   Routing Area Code (RAC): 0x00 (0)
+ Mobile Identity - Allocated P-TMSI - TMSI/P-TMSI (0xec999002)
+  Element ID: 0x18
+  Length: 5
+  1111 .... = Unused: 0xf
+  .... 0... = Odd/even indication: Even number of identity digits
+  .... .100 = Mobile Identity Type: TMSI/P-TMSI/M-TMSI (4)
+  TMSI/P-TMSI/M-TMSI/5G-TMSI: 3969486850 (0xec999002)
+ GPRS Timer - Negotiated Ready Timer
+  Element ID: 0x17
+  GPRS Timer: 10 sec
+   000. .... = Unit: value is incremented in multiples of 2 seconds (0)
+   ...0 0101 = Timer value: 5
+*/
+static uint8_t pdu_gmm_rau_acc[] = {
+0x08, 0x09, 0x00, 0x05, 0x32, 0xf4, 0x07, 0x00,
+0x05, 0x00, 0x18, 0x05, 0xf4, 0xec, 0x99, 0x90,
+0x02, 0x17, 0x05
+};
+
 static uint8_t pdu_gmm_detach_acc[] = {
 0x08, 0x06, 0x00
 };
@@ -145,6 +189,42 @@
        return 0;
 }

+#define clock_debug(fmt, args...) \
+       do { \
+               struct timespec ts; \
+               struct timeval tv; \
+               osmo_clock_gettime(CLOCK_MONOTONIC, &ts); \
+               osmo_gettimeofday(&tv, NULL); \
+               fprintf(stdout, "sys={%lu.%06lu}, mono={%lu.%06lu}: " fmt "\n", 
\
+                       tv.tv_sec, tv.tv_usec, ts.tv_sec, ts.tv_nsec/1000, 
##args); \
+       } while (0)
+
+static void clock_override_enable(bool enable)
+{
+       osmo_gettimeofday_override = enable;
+       osmo_clock_override_enable(CLOCK_MONOTONIC, enable);
+}
+
+static void clock_override_set(long sec, long usec)
+{
+       struct timespec *mono;
+       osmo_gettimeofday_override_time.tv_sec = sec;
+       osmo_gettimeofday_override_time.tv_usec = usec;
+       mono = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
+       mono->tv_sec = sec;
+       mono->tv_nsec = usec*1000;
+
+       clock_debug("clock_override_set");
+}
+
+static void clock_override_add_debug(long sec, long usec, bool dbg)
+{
+       osmo_gettimeofday_override_add(sec, usec);
+       osmo_clock_override_add(CLOCK_MONOTONIC, sec, usec*1000);
+       if (dbg)
+               clock_debug("clock_override_add");
+}
+#define clock_override_add(sec, usec) clock_override_add_debug(sec, usec, true)

 int test_gmm_prim_up_cb(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data)
 {
@@ -252,6 +332,7 @@
 int test_gmm_prim_llc_down_cb(struct osmo_gprs_llc_prim *llc_prim, void 
*user_data)
 {
        const char *pdu_name = osmo_gprs_llc_prim_name(llc_prim);
+       struct osmo_gprs_gmm_prim *gmm_prim_tx;

        switch (llc_prim->oph.sap) {
        case OSMO_GPRS_LLC_SAP_LLGMM:
@@ -269,6 +350,15 @@
                printf("%s(): Rx %s TLLI=0x%08x SAPI=%s l3=[%s]\n", __func__, 
pdu_name,
                       llc_prim->ll.tlli, 
osmo_gprs_llc_sapi_name(llc_prim->ll.sapi),
                       osmo_hexdump(llc_prim->ll.l3_pdu, 
llc_prim->ll.l3_pdu_len));
+               switch (OSMO_PRIM_HDR(&llc_prim->oph)) {
+               case OSMO_PRIM(OSMO_GPRS_LLC_LL_UNITDATA, PRIM_OP_REQUEST):
+                       /* Immediately notify GMM that it was transmitted over 
the air: */
+                       gmm_prim_tx = (struct osmo_gprs_gmm_prim 
*)gprs_rlcmac_prim_alloc_gmmrr_llc_transmitted_ind(llc_prim->ll.tlli);
+                       gmm_prim_tx->oph.sap = OSMO_GPRS_GMM_SAP_GMMRR;
+                       gmm_prim_tx->oph.primitive = 
OSMO_GPRS_GMM_GMMRR_LLC_TRANSMITTED;
+                       osmo_gprs_gmm_prim_lower_up(gmm_prim_tx);
+                       break;
+               }
                break;
        default:
                printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
@@ -286,12 +376,15 @@
        uint32_t ptmsi = 0x00001234;
        uint32_t ptmsi_sig = 0x556677;
        uint32_t rand_tlli = 0x80001234;
+       uint32_t tlli;
        char *imsi = "1234567890";
        char *imei = "42342342342342";
        char *imeisv = "4234234234234275";

        printf("==== %s() [start] ====\n", __func__);

+       clock_override_set(0, 0);
+
        rc = osmo_gprs_gmm_init(OSMO_GPRS_GMM_LOCATION_MS);
        OSMO_ASSERT(rc == 0);
        osmo_gprs_gmm_enable_gprs(true);
@@ -338,9 +431,31 @@
        OSMO_ASSERT(llc_prim);
        rc = osmo_gprs_gmm_prim_llc_lower_up(llc_prim);
        OSMO_ASSERT(rc == 0);
+       /* update the used ptmsi to align with what was assigned from the 
network: */
+       ptmsi = 0xea711b41;
+       tlli = gprs_tmsi2tlli(ptmsi, TLLI_LOCAL);
        /* As a result, MS answers GMM Attach Complete */
        /* As a result, MS submits GMMREG ATTACH.cnf */

+       /* Wait for READY timer to expire: */
+       clock_override_add(44, 0); /* 44: See GMM Attach Accept 
(pdu_gmm_att_acc) feed above */
+       clock_debug("Expect T3314 (READY) timeout");
+       osmo_select_main(0);
+
+       clock_override_add(10*60, 0); /* 44: See GMM Attach Accept 
(pdu_gmm_att_acc) feed above */
+       clock_debug("Expect T3312 (periodic RAU) timeout");
+       osmo_select_main(0);
+
+       /* Network sends GMM RAU Accept */
+       llc_prim = gprs_llc_prim_alloc_ll_unitdata_ind(tlli, 
OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmm_rau_acc, sizeof(pdu_gmm_rau_acc));
+       OSMO_ASSERT(llc_prim);
+       rc = osmo_gprs_gmm_prim_llc_lower_up(llc_prim);
+       OSMO_ASSERT(rc == 0);
+       /* update the used ptmsi to align with what was assigned from the 
network: */
+       ptmsi = 0xea711b41;
+       tlli = gprs_tmsi2tlli(ptmsi, TLLI_LOCAL);
+       /* As a result, MS answers GMM RAU Complete */
+
        /* ... */

        /* DETACH */
@@ -353,7 +468,7 @@
        OSMO_ASSERT(rc == 0);

        /* Network sends GMM Detach Accept */
-       llc_prim = gprs_llc_prim_alloc_ll_unitdata_ind(rand_tlli, 
OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmm_detach_acc, 
sizeof(pdu_gmm_detach_acc));
+       llc_prim = gprs_llc_prim_alloc_ll_unitdata_ind(tlli, 
OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmm_detach_acc, 
sizeof(pdu_gmm_detach_acc));
        OSMO_ASSERT(llc_prim);
        rc = osmo_gprs_gmm_prim_llc_lower_up(llc_prim);
        OSMO_ASSERT(rc == 0);
@@ -379,6 +494,8 @@

        printf("==== %s() [start] ====\n", __func__);

+       clock_override_set(0, 0);
+
        rc = osmo_gprs_gmm_init(OSMO_GPRS_GMM_LOCATION_MS);
        OSMO_ASSERT(rc == 0);
        osmo_gprs_gmm_enable_gprs(true);
@@ -460,6 +577,8 @@
        log_set_print_level(osmo_stderr_target, 1);
        log_set_use_color(osmo_stderr_target, 0);

+       clock_override_enable(true);
+
        test_gmm_prim_ms_gmmreg();
        test_gmm_prim_ms_gmmsm();

diff --git a/tests/gmm/gmm_prim_test.err b/tests/gmm/gmm_prim_test.err
index 7aca515..6720d69 100644
--- a/tests/gmm/gmm_prim_test.err
+++ b/tests/gmm/gmm_prim_test.err
@@ -4,28 +4,50 @@
 DLGLOBAL INFO GMM_MS{Null}: state_chg to Deregistered
 DLGLOBAL INFO GMM_MS{Deregistered}: Received Event ATTACH_REQUESTED
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Tx GMM ATTACH 
REQUEST (new TLLI=0x80001234)
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
 DLGLOBAL INFO GMM_MS{Deregistered}: state_chg to RegisteredInitiated
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Rx GMM 
IDENTITY REQUEST mi_type=IMEI
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Tx GMM 
IDENTITY RESPONSE
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Rx GMM 
AUTHENTICATION AND CIPHERING REQUEST
 DLGLOBAL INFO Rx from upper layers: GMMREG-SIM_AUTH.response
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Tx GMM GMM 
AUTHENTICATION AND CIPHERING RESPONSE
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Rx GMM ATTACH 
ACCEPT
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) Tx GMM ATTACH 
COMPL
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) READY timer 
started (expires in 44 seconds)
 DLGLOBAL INFO GMM_MS{RegisteredInitiated}: Received Event ATTACH_ACCEPTED
 DLGLOBAL INFO GMM_MS{RegisteredInitiated}: state_chg to Registered
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) READY timer 
expired
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) T3312 started 
(expires in 600 seconds)
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) T3312 
Periodic RAU timer expired
+DLGLOBAL INFO GMM_MS{Registered}: Received Event RAU_REQUESTED
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) Tx GMM RAU 
REQUEST
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) READY timer 
started (expires in 44 seconds)
+DLGLOBAL INFO GMM_MS{Registered}: state_chg to RAUInitidated
+DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) Rx GMM RAU 
ACCEPT upd_result=0x00
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ec999002:TLLI-ec999002) Tx GMM RAU 
COMPL
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ec999002:TLLI-ec999002) READY timer 
started (expires in 10 seconds)
+DLGLOBAL INFO GMM_MS{RAUInitidated}: Received Event RAU_ACCEPTED
+DLGLOBAL INFO GMM_MS{RAUInitidated}: state_chg to Registered
 DLGLOBAL INFO Rx from upper layers: GMMREG-DETACH.request
 DLGLOBAL INFO GMM_MS{Registered}: Received Event DETACH_REQUESTED
 DLGLOBAL INFO GMM_MS{Registered}: state_chg to DeregisteredInitiated
-DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) Tx GMM DETACH 
REQUEST (MO)
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ec999002:TLLI-ec999002) Tx GMM DETACH 
REQUEST (MO)
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ec999002:TLLI-ec999002) READY timer 
started (expires in 10 seconds)
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
-DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) Rx GMM DETACH 
ACCEPT (MO) force_standby_indicated=false
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ec999002:TLLI-ec999002) Rx GMM DETACH 
ACCEPT (MO) force_standby_indicated=false
 DLGLOBAL INFO GMM_MS{DeregisteredInitiated}: Received Event DETACH_ACCEPTED
 DLGLOBAL INFO GMM_MS{DeregisteredInitiated}: state_chg to Deregistered
-DLGLOBAL DEBUG GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ffffffff) free()
+DLGLOBAL DEBUG GMME(IMSI-1234567890:PTMSI-ec999002:TLLI-ffffffff) free()
 DLGLOBAL INFO GMM_MS{Deregistered}: Deallocated
 DLGLOBAL INFO Rx from upper layers: GMMSM-ESTABLISH.request
 DLGLOBAL INFO GMM_MS{Null}: Allocated
@@ -33,18 +55,25 @@
 DLGLOBAL INFO GMM_MS{Null}: state_chg to Deregistered
 DLGLOBAL INFO GMM_MS{Deregistered}: Received Event ATTACH_REQUESTED
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Tx GMM ATTACH 
REQUEST (new TLLI=0x80001234)
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
 DLGLOBAL INFO GMM_MS{Deregistered}: state_chg to RegisteredInitiated
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Rx GMM 
IDENTITY REQUEST mi_type=IMEI
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Tx GMM 
IDENTITY RESPONSE
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Rx GMM 
AUTHENTICATION AND CIPHERING REQUEST
 DLGLOBAL INFO Rx from upper layers: GMMREG-SIM_AUTH.response
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Tx GMM GMM 
AUTHENTICATION AND CIPHERING RESPONSE
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-00001234:TLLI-80001234) Rx GMM ATTACH 
ACCEPT
 DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) Tx GMM ATTACH 
COMPL
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) READY timer 
started (expires in 44 seconds)
 DLGLOBAL INFO GMM_MS{RegisteredInitiated}: Received Event ATTACH_ACCEPTED
 DLGLOBAL INFO GMM_MS{RegisteredInitiated}: state_chg to Registered
 DLGLOBAL INFO Rx from upper layers: GMMSM-UNITDATA.request
+DLGLOBAL INFO Rx from lower layers: GMRR-LLC_TRANSMITTED.indication
+DLGLOBAL INFO GMME(IMSI-1234567890:PTMSI-ea711b41:TLLI-ea711b41) READY timer 
started (expires in 44 seconds)
 DLGLOBAL INFO Rx from lower layers: LL-UNITDATA.indication
diff --git a/tests/gmm/gmm_prim_test.ok b/tests/gmm/gmm_prim_test.ok
index 068876b..8fe93b3 100644
--- a/tests/gmm/gmm_prim_test.ok
+++ b/tests/gmm/gmm_prim_test.ok
@@ -1,4 +1,5 @@
 ==== test_gmm_prim_ms_gmmreg() [start] ====
+sys={0.000000}, mono={0.000000}: clock_override_set
 test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM 
l3=[08 01 04 97 07 00 00 01 0a 00 05 f4 00 00 12 34 00 f0 00 00 00 00 00 19 55 
66 77 17 16 e1 ]
 test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM 
l3=[08 16 08 42 32 24 43 32 24 43 f2 ]
 test_gmm_prim_up_cb(): Rx GMMREG-SIM_AUTH.indication ac_ref_nr=2 key_seq=0 
rand=e2 a6 f3 f8 bb 9e a7 01 e0 ce 4f 33 64 a9 91 75
@@ -8,11 +9,20 @@
 test_gmm_prim_down_cb(): Rx GMRR-ASSIGN.request old_tlli=0x80001234 
new_tlli=0xea711b41
 test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0xea711b41 SAPI=GMM 
l3=[08 03 ]
 test_gmm_prim_up_cb(): Rx GMMREG-ATTACH.confirm accepted=1 
allocated_ptmsi=0xea711b41 allocated_ptmsi_sig=0xffffffff
-test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0xea711b41 SAPI=GMM 
l3=[08 05 20 0a 00 05 f4 ea 71 1b 41 ]
-test_gmm_prim_llc_down_cb(): Rx LLGMM-ASSIGN.request old_TLLI=0xea711b41 
new_TLLI=0xffffffff
+sys={44.000000}, mono={44.000000}: clock_override_add
+sys={44.000000}, mono={44.000000}: Expect T3314 (READY) timeout
+sys={644.000000}, mono={644.000000}: clock_override_add
+sys={644.000000}, mono={644.000000}: Expect T3312 (periodic RAU) timeout
+test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0xea711b41 SAPI=GMM 
l3=[08 08 03 32 f4 07 00 05 00 00 17 16 0a 00 e5 02 00 00 e1 ]
+test_gmm_prim_llc_down_cb(): Rx LLGMM-ASSIGN.request old_TLLI=0xea711b41 
new_TLLI=0xec999002
+test_gmm_prim_down_cb(): Rx GMRR-ASSIGN.request old_tlli=0xea711b41 
new_tlli=0xec999002
+test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0xec999002 SAPI=GMM 
l3=[08 0a ]
+test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0xec999002 SAPI=GMM 
l3=[08 05 20 0a 00 05 f4 ec 99 90 02 ]
+test_gmm_prim_llc_down_cb(): Rx LLGMM-ASSIGN.request old_TLLI=0xec999002 
new_TLLI=0xffffffff
 test_gmm_prim_up_cb(): Rx GMMREG-DETACH.confirm detach_type='GPRS detach'
 ==== test_gmm_prim_ms_gmmreg() [end] ====
 ==== test_gmm_prim_ms_gmmsm() [start] ====
+sys={0.000000}, mono={0.000000}: clock_override_set
 test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM 
l3=[08 01 04 97 07 00 00 01 0a 00 05 f4 00 00 12 34 00 f0 00 00 00 00 00 19 55 
66 77 17 16 e1 ]
 test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM 
l3=[08 16 08 42 32 24 43 32 24 43 f2 ]
 test_gmm_prim_up_cb(): Rx GMMREG-SIM_AUTH.indication ac_ref_nr=2 key_seq=0 
rand=e2 a6 f3 f8 bb 9e a7 01 e0 ce 4f 33 64 a9 91 75

--
To view, visit https://gerrit.osmocom.org/c/libosmo-gprs/+/32925
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: Ie7cba8a2fe3b97bebc558c957cc1bcbe3cc81dbc
Gerrit-Change-Number: 32925
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <[email protected]>
Gerrit-MessageType: newchange

Reply via email to