pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-gprs/+/32983 )
Change subject: llc: Implement LLGM-TRIGGER.req ......................................................................
llc: Implement LLGM-TRIGGER.req
Change-Id: Id1af5912f407fe055a59a4bb217936307697975f --- M include/osmocom/gprs/llc/llc_prim.h M include/osmocom/gprs/llc/llc_private.h M src/llc/llc.c M src/llc/llc_llgmm.c M tests/llc/llc_prim_test.c M tests/llc/llc_prim_test.err M tests/llc/llc_prim_test.ok 7 files changed, 130 insertions(+), 3 deletions(-)
Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved
diff --git a/include/osmocom/gprs/llc/llc_prim.h b/include/osmocom/gprs/llc/llc_prim.h index d675954..c03f396 100644 --- a/include/osmocom/gprs/llc/llc_prim.h +++ b/include/osmocom/gprs/llc/llc_prim.h @@ -88,6 +88,16 @@ return get_value_string(osmo_gprs_llc_bssgp_prim_type_names, val); }
+/* TS 04.64 Section 7.2.1.3 LLGMM-TRIGGER */ +/* 3GPP TS 24.008 2.1.2 "Cell Notification" is considered a different trigger + * type than Cell Update since lower layers behave different (tx LLC NULL vs UI + * frame). Furthermore, the one knowing about requirement to use one or the other + * is the upper layer (GMM), as well as the one responsible of READY timer. */ +enum osmo_gprs_llc_llgmm_trigger_type { + OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_UPDATE, + OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_NOTIFICATION, + OSMO_GPRS_LLC_LLGM_TRIGGER_PAGE_RESP, +};
/* Parameters for OSMO_GPRS_LLC_LLGMM_* prims */ struct osmo_gprs_llc_llgmm_prim { @@ -104,7 +114,7 @@ } assign_req; /* OSMO_GPRS_LLC_LLGMM_TRIGGER | Req */ struct { - uint8_t cause; + uint8_t cause; /* enum osmo_gprs_llc_llgmm_trigger_type */ } trigger_req; /* OSMO_GPRS_LLC_LLGMM_SUSPEND | Req */ struct { diff --git a/include/osmocom/gprs/llc/llc_private.h b/include/osmocom/gprs/llc/llc_private.h index ed68c7b..78e6e9f 100644 --- a/include/osmocom/gprs/llc/llc_private.h +++ b/include/osmocom/gprs/llc/llc_private.h @@ -323,6 +323,7 @@ int gprs_llc_lle_tx_xid_req(struct gprs_llc_lle *lle, uint8_t *l3par, unsigned int l3par_len); int gprs_llc_lle_tx_xid_resp(struct gprs_llc_lle *lle, uint8_t *l3par, unsigned int l3par_len); int gprs_llc_lle_tx_ui(struct gprs_llc_lle *lle, uint8_t *l3_pdu, size_t l3_pdu_len, bool encryptable); +int gprs_llc_lle_tx_null(const struct gprs_llc_lle *lle);
/* llc_prim.c: */ struct osmo_gprs_llc_prim *gprs_llc_prim_alloc(enum osmo_gprs_llc_prim_sap sap, unsigned int type, diff --git a/src/llc/llc.c b/src/llc/llc.c index 4be7a9a..93a11ec 100644 --- a/src/llc/llc.c +++ b/src/llc/llc.c @@ -292,6 +292,46 @@ return 0; }
+/* 6.4.1.7 NULL command */ +int gprs_llc_lle_tx_null(const struct gprs_llc_lle *lle) +{ + int rc; + struct msgb *msg; + struct gprs_llc_pdu_decoded pdu_dec = { + .sapi = lle->sapi, + .fmt = OSMO_GPRS_LLC_FMT_U, + .func = OSMO_GPRS_LLC_FUNC_NULL, + .flags = 0 /* P=0 */, + }; + struct osmo_gprs_llc_prim *llc_prim; + + /* LLC payload is put directly below: */ + if (g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN) + llc_prim = gprs_llc_prim_alloc_bssgp_dl_unitdata_req(lle->llme->tlli, NULL, 4096 - sizeof(llc_prim)); + else + llc_prim = gprs_llc_prim_alloc_grr_unitdata_req(lle->llme->tlli, NULL, 4096 - sizeof(llc_prim)); + msg = llc_prim->oph.msg; + msg->l3h = msg->tail; + + rc = gprs_llc_pdu_encode(msg, &pdu_dec); + if (rc < 0) { + LOGLLC(LOGL_NOTICE, "Failed to encode U DM\n"); + msgb_free(msg); + return rc; + } + if (g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_MS) { + llc_prim->bssgp.ll_pdu = msgb_l3(msg); + llc_prim->bssgp.ll_pdu_len = msgb_l3len(msg); + } else { + llc_prim->grr.ll_pdu = msgb_l3(msg); + llc_prim->grr.ll_pdu_len = msgb_l3len(msg); + } + + /* Send BSSGP-DL-UNITDATA.req (SGSN) / GRR-UNITDATA.req (MS) */ + gprs_llc_prim_call_down_cb(llc_prim); + return 0; +} + /* Transmit a UI frame over the given SAPI: 'encryptable' indicates whether particular message can be encrypted according to 3GPP TS 24.008 § 4.7.1.2 diff --git a/src/llc/llc_llgmm.c b/src/llc/llc_llgmm.c index bf161e3..d85a30e 100644 --- a/src/llc/llc_llgmm.c +++ b/src/llc/llc_llgmm.c @@ -274,6 +274,46 @@ return rc; }
+/* 7.2.1.3 LLGMM-TRIGGER.req (SGSN):*/ +static int llc_prim_handle_llgmm_trigger_req(struct osmo_gprs_llc_prim *llc_prim) +{ + struct gprs_llc_lle *lle; + int rc; + struct gprs_llc_llme *llme = gprs_llc_find_llme_by_tlli(llc_prim->llgmm.tlli); + + if (!llme) { + LOGLLC(LOGL_NOTICE, "Rx %s: Unknown TLLI 0x%08x\n", + osmo_gprs_llc_prim_name(llc_prim), llc_prim->llgmm.tlli); + rc = -ENOKEY; + goto ret_free; + } + LOGLLME(llme, LOGL_INFO, "%s\n", osmo_gprs_llc_prim_name(llc_prim)); + + lle = gprs_llc_llme_get_lle(llme, OSMO_GPRS_LLC_SAPI_GMM); + + /* "If there is a frame waiting to be transmitted in the MS, then this + * frame shall be transmitted on the corresponding SAPI or optionally a + * UI frame with no information field shall be transmitted on any SAPI. + * Otherwise if Cause indicates Cell Update and if Cell Notification is + * indicated by the SGSN (see 3GPP TS 24.008 [8a]), then a NULL frame + * with P=0 shall be transmitted on any SAPI." + */ + switch (llc_prim->llgmm.trigger_req.cause) { + case OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_NOTIFICATION: + rc = gprs_llc_lle_tx_null(lle); + break; + case OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_UPDATE: + case OSMO_GPRS_LLC_LLGM_TRIGGER_PAGE_RESP: + default: + rc = gprs_llc_lle_tx_ui(lle, NULL, 0, false); + break; + } + +ret_free: + msgb_free(llc_prim->oph.msg); + return rc; +} + /* 7.2.1.4 LLGMM-SUSPEND.req (MS/SGSN):*/ static int llc_prim_handle_llgmm_suspend_req(struct osmo_gprs_llc_prim *llc_prim) { @@ -332,7 +372,7 @@ break; case OSMO_PRIM(OSMO_GPRS_LLC_LLGMM_TRIGGER, PRIM_OP_REQUEST): OSMO_ASSERT(g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_MS); - rc = gprs_llc_prim_handle_unsupported(llc_prim); + rc = llc_prim_handle_llgmm_trigger_req(llc_prim); break; case OSMO_PRIM(OSMO_GPRS_LLC_LLGMM_SUSPEND, PRIM_OP_REQUEST): OSMO_ASSERT(g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_MS || diff --git a/tests/llc/llc_prim_test.c b/tests/llc/llc_prim_test.c index b3ff512..bcba783 100644 --- a/tests/llc/llc_prim_test.c +++ b/tests/llc/llc_prim_test.c @@ -172,13 +172,31 @@ rc = osmo_gprs_llc_prim_upper_down(llc_prim); OSMO_ASSERT(rc == 0);
- /* Rx LLC-GMM-Attach-Req at MS from SGSN (should be a response message + /* Rx LLC-GMM-Attach-Accept at MS from SGSN (should be a response message * but we don't care about upper layers here): */ llc_prim = osmo_gprs_llc_prim_alloc_grr_unitdata_ind(tlli, pdu_llc_gmm_att_req, sizeof(pdu_llc_gmm_att_req)); OSMO_ASSERT(llc_prim); rc = osmo_gprs_llc_prim_lower_up(llc_prim); OSMO_ASSERT(rc == 0);
+ /* Test GMM asking LLC to transmit a response for a Paging Request: */ + llc_prim = osmo_gprs_llc_prim_alloc_llgmm_trigger_req(tlli, OSMO_GPRS_LLC_LLGM_TRIGGER_PAGE_RESP); + OSMO_ASSERT(llc_prim); + rc = osmo_gprs_llc_prim_upper_down(llc_prim); + OSMO_ASSERT(rc == 0); + + /* Test GMM asking LLC to transmit for Cell Update: */ + llc_prim = osmo_gprs_llc_prim_alloc_llgmm_trigger_req(tlli, OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_UPDATE); + OSMO_ASSERT(llc_prim); + rc = osmo_gprs_llc_prim_upper_down(llc_prim); + OSMO_ASSERT(rc == 0); + + /* Test GMM asking LLC to transmit for Cell Notification: */ + llc_prim = osmo_gprs_llc_prim_alloc_llgmm_trigger_req(tlli, OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_NOTIFICATION); + OSMO_ASSERT(llc_prim); + rc = osmo_gprs_llc_prim_upper_down(llc_prim); + OSMO_ASSERT(rc == 0); + printf("==== %s() [end] ====\n", __func__); }
diff --git a/tests/llc/llc_prim_test.err b/tests/llc/llc_prim_test.err index 444f3da..7cc72f5 100644 --- a/tests/llc/llc_prim_test.err +++ b/tests/llc/llc_prim_test.err @@ -3,6 +3,12 @@ DLGLOBAL INFO Rx from lower layers: GRR-UNITDATA.indication DLGLOBAL DEBUG Rx GRR-UNITDATA.indication: SAPI=1 (GMM), UI func=UI C/R=0 PM=0 E=0 IP=0 N(U)=0 FCS=f218e2 DLGLOBAL DEBUG LLE(ffffffff/f43cec71,GMM){UNASSIGNED} Rx SAPI=1 (GMM), UI func=UI C/R=0 PM=0 E=0 IP=0 N(U)=0 FCS=f218e2 +DLGLOBAL INFO Rx from upper layers: LLGMM-TRIGGER.request +DLGLOBAL INFO LLME(ffffffff/f43cec71){UNASSIGNED} LLGMM-TRIGGER.request +DLGLOBAL INFO Rx from upper layers: LLGMM-TRIGGER.request +DLGLOBAL INFO LLME(ffffffff/f43cec71){UNASSIGNED} LLGMM-TRIGGER.request +DLGLOBAL INFO Rx from upper layers: LLGMM-TRIGGER.request +DLGLOBAL INFO LLME(ffffffff/f43cec71){UNASSIGNED} LLGMM-TRIGGER.request DLGLOBAL INFO Rx from lower layers: BSSGP-UL-UNITDATA.indication DLGLOBAL DEBUG Rx BSSGP-UL-UNITDATA.indication: SAPI=1 (GMM), UI func=UI C/R=0 PM=0 E=0 IP=0 N(U)=0 FCS=f218e2 DLGLOBAL NOTICE LLME(ffffffff/e1c5d364){UNASSIGNED} LLC RX: unknown TLLI 0xe1c5d364, creating LLME on the fly diff --git a/tests/llc/llc_prim_test.ok b/tests/llc/llc_prim_test.ok index 4534568..ee381e6 100644 --- a/tests/llc/llc_prim_test.ok +++ b/tests/llc/llc_prim_test.ok @@ -1,6 +1,9 @@ ==== test_llc_prim_ms() [start] ==== test_llc_prim_down_cb(): Rx GRR-UNITDATA.request l3=[01 c0 01 08 01 02 e5 e0 01 0a 00 05 f4 f4 3c ec 71 32 f4 07 00 05 00 17 19 33 43 2b 37 15 9e f9 88 79 cb a2 8c 66 21 e7 26 88 b1 98 87 9c 00 17 05 22 96 cc ] test_llc_prim_up_cb(): Rx LL-UNITDATA.indication TLLI=0xf43cec71 SAPI=GMM l3=[08 01 01 d5 71 00 00 08 29 26 24 00 00 00 00 71 62 f2 24 6c 84 44 04 11 e5 10 00 ] +test_llc_prim_down_cb(): Rx GRR-UNITDATA.request l3=[01 c0 05 4a 85 74 ] +test_llc_prim_down_cb(): Rx GRR-UNITDATA.request l3=[01 c0 09 ce 0d f7 ] +test_llc_prim_down_cb(): Rx GRR-UNITDATA.request l3=[01 e0 1c a2 b3 ] ==== test_llc_prim_ms() [end] ==== ==== test_llc_prim_sgsn() [start] ==== test_llc_prim_up_cb(): Rx LL-UNITDATA.indication TLLI=0xe1c5d364 SAPI=GMM l3=[08 01 01 d5 71 00 00 08 29 26 24 00 00 00 00 71 62 f2 24 6c 84 44 04 11 e5 10 00 ]