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 ===