pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmo-gprs/+/32985 )

Change subject: rlcmac: Submit GMMRR-PAGE.ind upon rx of Paging Request Type 1/2
......................................................................

rlcmac: Submit GMMRR-PAGE.ind upon rx of Paging Request Type 1/2

Change-Id: I64db4277b5c54870a258d63c554f470011bcc989
---
M include/osmocom/gprs/rlcmac/rlcmac_private.h
M src/rlcmac/rlcmac.c
M src/rlcmac/rlcmac_prim.c
M tests/rlcmac/rlcmac_prim_test.c
M tests/rlcmac/rlcmac_prim_test.err
M tests/rlcmac/rlcmac_prim_test.ok
6 files changed, 319 insertions(+), 2 deletions(-)

Approvals:
  Jenkins Builder: Verified
  fixeria: Looks good to me, but someone else must approve
  laforge: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved




diff --git a/include/osmocom/gprs/rlcmac/rlcmac_private.h 
b/include/osmocom/gprs/rlcmac/rlcmac_private.h
index e73d23e..76fa3fd 100644
--- a/include/osmocom/gprs/rlcmac/rlcmac_private.h
+++ b/include/osmocom/gprs/rlcmac/rlcmac_private.h
@@ -86,9 +86,13 @@

 /* rlcmac.c */
 struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_tlli(uint32_t tlli);
+struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_ptmsi(uint32_t ptmsi);
+struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_imsi(const char *imsi);
 struct gprs_rlcmac_dl_tbf *gprs_rlcmac_find_dl_tbf_by_tfi(uint8_t dl_tfi);
 struct gprs_rlcmac_ul_tbf *gprs_rlcmac_find_ul_tbf_by_tfi(uint8_t ul_tfi);
 int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia, uint32_t 
fn);
+int gprs_rlcmac_handle_ccch_pag_req1(const struct gsm48_paging1 *pag);
+int gprs_rlcmac_handle_ccch_pag_req2(const struct gsm48_paging2 *pag);
 int gprs_rlcmac_handle_bcch_si13(const struct gsm48_system_information_type_13 
*si13);
 int gprs_rlcmac_handle_gprs_dl_block(const struct osmo_gprs_rlcmac_prim 
*rlcmac_prim,
                                     enum gprs_rlcmac_coding_scheme cs);
diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c
index 00b45ff..22464b1 100644
--- a/src/rlcmac/rlcmac.c
+++ b/src/rlcmac/rlcmac.c
@@ -134,7 +134,6 @@
 struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_tlli(uint32_t tlli)
 {
        struct gprs_rlcmac_entity *gre;
-
        llist_for_each_entry(gre, &g_rlcmac_ctx->gre_list, entry) {
                if (gre->tlli == tlli)
                        return gre;
@@ -142,6 +141,26 @@
        return NULL;
 }

+struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_ptmsi(uint32_t ptmsi)
+{
+       struct gprs_rlcmac_entity *gre;
+       llist_for_each_entry(gre, &g_rlcmac_ctx->gre_list, entry) {
+               if (gre->ptmsi == ptmsi)
+                       return gre;
+       }
+       return NULL;
+}
+
+struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_imsi(const char *imsi)
+{
+       struct gprs_rlcmac_entity *gre;
+       llist_for_each_entry(gre, &g_rlcmac_ctx->gre_list, entry) {
+               if (strncmp(gre->imsi, imsi, ARRAY_SIZE(gre->imsi)) == 0)
+                       return gre;
+       }
+       return NULL;
+}
+
 struct gprs_rlcmac_dl_tbf *gprs_rlcmac_find_dl_tbf_by_tfi(uint8_t dl_tfi)
 {
        struct gprs_rlcmac_entity *gre;
@@ -304,6 +323,203 @@
        return rc;
 }

+
+/* TS 44.018 3.3.2.1.1:
+* It is used when sending paging information to a mobile station in packet 
idle mode, if PCCCH is not present in the cell.
+* If the mobile station in packet idle mode is identified by its IMSI, it 
shall parse the message for a corresponding Packet
+* Page Indication field:
+* - if the Packet Page Indication field indicates a packet paging procedure, 
the mobile station shall proceed as
+*   specified in sub-clause 3.5.1.2.
+* 3.5.1.2 "On receipt of a packet paging request":
+* On the receipt of a paging request message, the RR sublayer of addressed 
mobile station indicates the receipt of a
+* paging request to the MM sublayer, see 3GPP TS 24.007.
+*/
+/* TS 44.018 9.1.22 "Paging request type 1" */
+int gprs_rlcmac_handle_ccch_pag_req1(const struct gsm48_paging1 *pag)
+{
+       uint8_t len;
+       const uint8_t *buf = pag->data;
+       int rc;
+       struct osmo_mobile_identity mi1 = {}; /* GSM_MI_TYPE_NONE */
+       struct osmo_mobile_identity mi2 = {}; /* GSM_MI_TYPE_NONE */
+       P1_Rest_Octets_t p1ro = {};
+       unsigned p1_rest_oct_len;
+       struct osmo_gprs_rlcmac_prim *rlcmac_prim;
+       struct gprs_rlcmac_entity *gre;
+
+       LOGRLCMAC(LOGL_INFO, "Rx Paging Request Type 1\n");
+
+
+       /* The L2 pseudo length of this message is the sum of lengths of all
+        * information elements present in the message except the P1 Rest 
Octets and L2
+        * Pseudo Length information elements. */
+       if (pag->l2_plen == GSM_MACBLOCK_LEN - sizeof(pag->l2_plen)) {
+               /* no P1 Rest Octets => no Packet Page Indication => Discard */
+               return 0;
+       }
+
+       len = *buf;
+       buf++;
+
+       if (GSM_MACBLOCK_LEN < (buf - (uint8_t *)pag) + len)
+               return -EBADMSG;
+
+       if ((rc = osmo_mobile_identity_decode(&mi1, buf, len, false)) < 0)
+               return rc;
+       buf += len;
+
+       if (GSM_MACBLOCK_LEN < (buf - (uint8_t *)pag) + 1) {
+               /* No MI2 and no P1 Rest Octets => no Packet Page Indication => 
Discard */
+               return 0;
+       }
+
+       if (*buf == GSM48_IE_MOBILE_ID) {
+               buf++;
+               if (GSM_MACBLOCK_LEN < (buf - (uint8_t *)pag) + 1)
+                       return -EBADMSG;
+               len = *buf;
+               buf++;
+               if (GSM_MACBLOCK_LEN < (buf - (uint8_t *)pag) + len)
+                       return -EBADMSG;
+               if ((rc = osmo_mobile_identity_decode(&mi2, buf, len, false)) < 
0)
+                       return rc;
+               buf += len;
+       }
+
+       p1_rest_oct_len = GSM_MACBLOCK_LEN - (buf - (uint8_t *)pag);
+       if (p1_rest_oct_len == 0) {
+               /*No P1 Rest Octets => no Packet Page Indication => Discard */
+               return 0;
+       }
+
+       rc = osmo_gprs_rlcmac_decode_p1ro(&p1ro, buf, p1_rest_oct_len);
+       if (rc != 0) {
+               LOGRLCMAC(LOGL_ERROR, "Failed to parse P1 Rest Octets\n");
+               return rc;
+       }
+
+       if (p1ro.Packet_Page_Indication_1 == 1) { /* for GPRS */
+               switch (mi1.type) {
+               case GSM_MI_TYPE_IMSI:
+                       if ((gre = gprs_rlcmac_find_entity_by_imsi(mi1.imsi))) {
+                               /* TS 24.007 C.13: Submit GMMRR-PAGE.ind: */
+                               rlcmac_prim = 
gprs_rlcmac_prim_alloc_gmmrr_page_ind(gre->tlli);
+                               rc = gprs_rlcmac_prim_call_up_cb(rlcmac_prim);
+                       }
+                       break;
+               case GSM_MI_TYPE_TMSI:
+                       if ((gre = gprs_rlcmac_find_entity_by_ptmsi(mi1.tmsi))) 
{
+                               /* TS 24.007 C.13: Submit GMMRR-PAGE.ind: */
+                               rlcmac_prim = 
gprs_rlcmac_prim_alloc_gmmrr_page_ind(gre->tlli);
+                               rc = gprs_rlcmac_prim_call_up_cb(rlcmac_prim);
+                       }
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       if (p1ro.Packet_Page_Indication_2 == 1) { /* for GPRS */
+               switch (mi2.type) {
+               case GSM_MI_TYPE_IMSI:
+                       if ((gre = gprs_rlcmac_find_entity_by_imsi(mi2.imsi))) {
+                               /* TS 24.007 C.13: Submit GMMRR-PAGE.ind: */
+                               rlcmac_prim = 
gprs_rlcmac_prim_alloc_gmmrr_page_ind(gre->tlli);
+                               rc = gprs_rlcmac_prim_call_up_cb(rlcmac_prim);
+                       }
+                       break;
+               case GSM_MI_TYPE_TMSI:
+                       if ((gre = gprs_rlcmac_find_entity_by_ptmsi(mi2.tmsi))) 
{
+                               /* TS 24.007 C.13: Submit GMMRR-PAGE.ind: */
+                               rlcmac_prim = 
gprs_rlcmac_prim_alloc_gmmrr_page_ind(gre->tlli);
+                               rc = gprs_rlcmac_prim_call_up_cb(rlcmac_prim);
+                       }
+                       break;
+               default:
+                       break; /* MI2 not present */
+               }
+       }
+
+       return rc;
+}
+
+/* TS 44.018 9.1.23 "Paging request type 2" */
+int gprs_rlcmac_handle_ccch_pag_req2(const struct gsm48_paging2 *pag)
+{
+       uint8_t len;
+       const uint8_t *buf = pag->data;
+       int rc;
+       struct osmo_mobile_identity mi3 = {}; /* GSM_MI_TYPE_NONE */
+       P2_Rest_Octets_t p2ro = {};
+       unsigned p2_rest_oct_len;
+       struct osmo_gprs_rlcmac_prim *rlcmac_prim;
+       struct gprs_rlcmac_entity *gre;
+
+       LOGRLCMAC(LOGL_INFO, "Rx Paging Request Type 2\n");
+
+       /* The L2 pseudo length of this message is the sum of lengths of all
+        * information elements present in the message except the P1 Rest 
Octets and L2
+        * Pseudo Length information elements. */
+       if (pag->l2_plen == GSM_MACBLOCK_LEN - sizeof(pag->l2_plen)) {
+               /* no P2 Rest Octets => no Packet Page Indication => Discard */
+               return 0;
+       }
+
+       if (GSM_MACBLOCK_LEN < (buf - (uint8_t *)pag) + 1)
+               return -EBADMSG;
+
+       /* No MI3 => Discard */
+       if (*buf != GSM48_IE_MOBILE_ID)
+               return 0;
+
+       buf++;
+       if (GSM_MACBLOCK_LEN < (buf - (uint8_t *)pag) + 1)
+               return -EBADMSG;
+       len = *buf;
+       buf++;
+       if (GSM_MACBLOCK_LEN < (buf - (uint8_t *)pag) + len)
+               return -EBADMSG;
+       if ((rc = osmo_mobile_identity_decode(&mi3, buf, len, false)) < 0)
+               return rc;
+       buf += len;
+
+       p2_rest_oct_len = GSM_MACBLOCK_LEN - (buf - (uint8_t *)pag);
+       if (p2_rest_oct_len == 0) {
+               /*No P1 Rest Octets => no Packet Page Indication => Discard */
+               return 0;
+       }
+
+       rc = osmo_gprs_rlcmac_decode_p2ro(&p2ro, buf, p2_rest_oct_len);
+       if (rc != 0) {
+               LOGRLCMAC(LOGL_ERROR, "Failed to parse P2 Rest Octets\n");
+               return rc;
+       }
+
+       if (p2ro.Packet_Page_Indication_3 != 1) /* NOT for GPRS */
+               return 0;
+
+       switch (mi3.type) {
+       case GSM_MI_TYPE_IMSI:
+               if ((gre = gprs_rlcmac_find_entity_by_imsi(mi3.imsi))) {
+                       /* TS 24.007 C.13: Submit GMMRR-PAGE.ind: */
+                       rlcmac_prim = 
gprs_rlcmac_prim_alloc_gmmrr_page_ind(gre->tlli);
+                       rc = gprs_rlcmac_prim_call_up_cb(rlcmac_prim);
+               }
+               break;
+       case GSM_MI_TYPE_TMSI:
+               if ((gre = gprs_rlcmac_find_entity_by_ptmsi(mi3.tmsi))) {
+                       /* TS 24.007 C.13: Submit GMMRR-PAGE.ind: */
+                       rlcmac_prim = 
gprs_rlcmac_prim_alloc_gmmrr_page_ind(gre->tlli);
+                       rc = gprs_rlcmac_prim_call_up_cb(rlcmac_prim);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return rc;
+}
+
 int gprs_rlcmac_handle_bcch_si13(const struct gsm48_system_information_type_13 
*si13)
 {
        int rc;
diff --git a/src/rlcmac/rlcmac_prim.c b/src/rlcmac/rlcmac_prim.c
index 6e2285b..a5f796a 100644
--- a/src/rlcmac/rlcmac_prim.c
+++ b/src/rlcmac/rlcmac_prim.c
@@ -559,7 +559,6 @@

 static int rlcmac_prim_handle_l1ctl_ccch_data_ind(struct osmo_gprs_rlcmac_prim 
*rlcmac_prim)
 {
-       /* TODO: check if it's IMM_ASS: */
        int rc;

        switch (rlcmac_prim->l1ctl.ccch_data_ind.data[2]) {
@@ -567,6 +566,12 @@
                rc = gprs_rlcmac_handle_ccch_imm_ass((struct gsm48_imm_ass 
*)rlcmac_prim->l1ctl.ccch_data_ind.data,
                                                     
rlcmac_prim->l1ctl.ccch_data_ind.fn);
                break;
+       case GSM48_MT_RR_PAG_REQ_1:
+               rc = gprs_rlcmac_handle_ccch_pag_req1((const struct 
gsm48_paging1 *)rlcmac_prim->l1ctl.ccch_data_ind.data);
+               break;
+       case GSM48_MT_RR_PAG_REQ_2:
+               rc = gprs_rlcmac_handle_ccch_pag_req2((const struct 
gsm48_paging2 *)rlcmac_prim->l1ctl.ccch_data_ind.data);
+               break;
        case GSM48_MT_RR_SYSINFO_13:
                rc = gprs_rlcmac_handle_bcch_si13((struct 
gsm48_system_information_type_13 *)rlcmac_prim->l1ctl.ccch_data_ind.data);
                break;
diff --git a/tests/rlcmac/rlcmac_prim_test.c b/tests/rlcmac/rlcmac_prim_test.c
index 6213a04..c8d1616 100644
--- a/tests/rlcmac/rlcmac_prim_test.c
+++ b/tests/rlcmac/rlcmac_prim_test.c
@@ -186,6 +186,45 @@
        0x2b, 0x2b, 0x2b, 0x2b
 };

+/*
+GSM CCCH - Paging Request Type 1
+ L2 Pseudo Length
+  0011 00.. = L2 Pseudo Length value: 12
+ .... 0110 = Protocol discriminator: Radio Resources Management messages (0x6)
+  .... 0110 = Protocol discriminator: Radio Resources Management messages (0x6)
+  0000 .... = Skip Indicator: No indication of selected PLMN (0)
+ Message Type: Paging Request Type 1
+ Page Mode
+  .... 0000 = Page Mode: Normal paging (0)
+ Channel Needed
+  ..00 .... = Channel 1: Any channel (0)
+  00.. .... = Channel 2: Any channel (0)
+ Mobile Identity - Mobile Identity 1 - IMSI (262420000000423)
+  Length: 8
+  0010 .... = Identity Digit 1: 2
+  .... 1... = Odd/even indication: Odd number of identity digits
+  .... .001 = Mobile Identity Type: IMSI (1)
+  IMSI: 262420000000423
+  [Association IMSI: 262420000000423]
+    Mobile Country Code (MCC): Germany (262)
+    Mobile Network Code (MNC): Vodafone GmbH (42)
+ P1 Rest Octets
+  L... .... = NLN(PCH): Not Present
+  .L.. .... = Priority 1: Not Present
+  ..L. .... = Priority 2: Not Present
+  ...L .... = Group Call Information: Not Present
+  .... H... = Packet Page Indication 1: For GPRS
+  .... .H.. = Packet Page Indication 2: For GPRS
+  Padding Bits: default padding
+
+*/
+static uint8_t ccch_pag_req_1[] = {
+       0x31, 0x06, 0x21, 0x00, 0x08, 0x29, 0x26, 0x24, 0x00, 0x00,
+       0x00, 0x40, 0x32, 0x27, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b
+};
+
+
 #define clock_debug(fmt, args...) \
        do { \
                struct timespec ts; \
@@ -1029,6 +1068,38 @@
        cleanup_test();
 }

+/* SGSN->PCU->BTS --PCH--> MS containing "Paging Request Type 1" asking for PS 
services.
+ * RLCMAC will send GMMRR-PAGE.ind to GMM layer, which is in charge of 
orchestrating the response. */
+static void test_ccch_pag_req1(void)
+{
+       struct osmo_gprs_rlcmac_prim *rlcmac_prim;
+       int rc;
+
+       printf("=== %s start ===\n", __func__);
+       prepare_test();
+       uint32_t ptmsi = 0x00001234;
+       char *imsi = "262420000000423";
+       uint32_t tlli = 0x0000001;
+
+       /* Notify RLCMAC about our TLLI */
+       rlcmac_prim = 
osmo_gprs_rlcmac_prim_alloc_gmmrr_assign_req(GPRS_RLCMAC_TLLI_UNASSIGNED, tlli);
+       rlcmac_prim->gmmrr.assign_req.ptmsi = ptmsi;
+       OSMO_STRLCPY_ARRAY(rlcmac_prim->gmmrr.assign_req.imsi, imsi);
+       rc = osmo_gprs_rlcmac_prim_upper_down(rlcmac_prim);
+
+       OSMO_ASSERT(sizeof(ccch_pag_req_1) == GSM_MACBLOCK_LEN);
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_ccch_data_ind(0, 
ccch_pag_req_1);
+       rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+       /* Above prim is expected to trigger RLCMAC layer submitting 
GMMRR-Page.ind as here. */
+
+       /* Here GMM would start UL TBF through LLGM-TRIGGER.req(PAGE_RESPONSE),
+        * and LLC in turn submits GRR-UNITDATA.req */
+
+       printf("=== %s end ===\n", __func__);
+       cleanup_test();
+}
+
 static const struct log_info_cat test_log_categories[] = { };
 static const struct log_info test_log_info = {
        .cat = test_log_categories,
@@ -1060,6 +1131,7 @@
        test_ul_tbf_request_another_ul_tbf();
        test_dl_tbf_ccch_assign();
        test_dl_tbf_ccch_assign_requests_ul_tbf_pacch();
+       test_ccch_pag_req1();

        talloc_free(tall_ctx);
 }
diff --git a/tests/rlcmac/rlcmac_prim_test.err 
b/tests/rlcmac/rlcmac_prim_test.err
index d55626f..12e64d4 100644
--- a/tests/rlcmac/rlcmac_prim_test.err
+++ b/tests/rlcmac/rlcmac_prim_test.err
@@ -796,3 +796,10 @@
 DLGLOBAL INFO UL_TBF{FINISHED}: Send L1CTL-CFG_UL_TBF.req ul_tbf_nr=0 (release)
 DLGLOBAL DEBUG Tx to lower layers: L1CTL-CFG_UL_TBF.request
 DLGLOBAL INFO UL_TBF{FINISHED}: Deallocated
+DLGLOBAL INFO Rx from upper layers: GMMRR-ASSIGN.request
+DLGLOBAL INFO GMMRR-ASSIGN.req: creating new entity TLLI=0x00000001
+DLGLOBAL INFO DL_TBF_ASS{IDLE}: Allocated
+DLGLOBAL DEBUG Rx from lower layers: L1CTL-CCCH_DATA.indication
+DLGLOBAL INFO Rx Paging Request Type 1
+DLGLOBAL NOTICE P1 Rest Octets: 74 remaining bits unhandled by decoder
+DLGLOBAL INFO DL_TBF_ASS{IDLE}: Deallocated
diff --git a/tests/rlcmac/rlcmac_prim_test.ok b/tests/rlcmac/rlcmac_prim_test.ok
index 24abafa..100749a 100644
--- a/tests/rlcmac/rlcmac_prim_test.ok
+++ b/tests/rlcmac/rlcmac_prim_test.ok
@@ -142,3 +142,7 @@
 test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=47 ts=6 data_len=34 
data=[00 06 00 39 01 c0 00 08 01 01 d5 71 00 00 08 29 26 24 2b 2b 2b 2b 2b 2b 
2b 2b 2b 2b 2b 2b 2b 2b 2b 00 ]
 === test_dl_tbf_ccch_assign_requests_ul_tbf_pacch end ===
 test_rlcmac_prim_down_cb(): Rx L1CTL-CFG_UL_TBF.request ul_tbf_nr=0 
ul_slotmask=0x00
+=== test_ccch_pag_req1 start ===
+sys={0.000000}, mono={0.000000}: clock_override_set
+test_rlcmac_prim_up_cb(): Rx GMMRR-PAGE.indication TLLI=0x00000001
+=== test_ccch_pag_req1 end ===

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

Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: I64db4277b5c54870a258d63c554f470011bcc989
Gerrit-Change-Number: 32985
Gerrit-PatchSet: 3
Gerrit-Owner: pespin <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to