From 72ea2cf2fca01567a1b0cd8185baba582f4de153 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Tue, 23 May 2023 15:59:24 +0200 Subject: [PATCH] llc: Add APIs to submit LLGM-trigger/suspend/resume.req primitives This commit also adds an initial implementation of LLGM-suspend/resume.req. Change-Id: I890c7a4ace6fb8ca362ec41bd18e9c229191a587 --- include/osmocom/gprs/llc/llc_prim.h | 3 + include/osmocom/gprs/llc/llc_private.h | 4 ++ src/llc/llc_ll.c | 6 ++ src/llc/llc_llgmm.c | 76 +++++++++++++++++++++++++- 4 files changed, 86 insertions(+), 3 deletions(-) diff --git a/include/osmocom/gprs/llc/llc_prim.h b/include/osmocom/gprs/llc/llc_prim.h index d5a424d..904e9fa 100644 --- a/include/osmocom/gprs/llc/llc_prim.h +++ b/include/osmocom/gprs/llc/llc_prim.h @@ -300,6 +300,9 @@ const char *osmo_gprs_llc_prim_name(const struct osmo_gprs_llc_prim *llc_prim); /* Alloc primitive for LLGMM SAP: */ struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_assign_req(uint32_t tlli); struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_reset_req(uint32_t tlli); +struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_trigger_req(uint32_t tlli, uint8_t cause); +struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_suspend_req(uint32_t tlli); +struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_resume_req(uint32_t tlli); /* Alloc primitive for LL SAP: */ struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_ll_establish_req(uint32_t tlli, enum osmo_gprs_llc_sapi ll_sapi, diff --git a/include/osmocom/gprs/llc/llc_private.h b/include/osmocom/gprs/llc/llc_private.h index 994acd8..ed68c7b 100644 --- a/include/osmocom/gprs/llc/llc_private.h +++ b/include/osmocom/gprs/llc/llc_private.h @@ -254,6 +254,10 @@ struct gprs_llc_llme { /* Internal management */ uint32_t age_timestamp; + + /* TS 44.064 ยง C.2: "In addition, all states should observe the suspended + * operation (reception of LLGMM-SUSPEND-REQ) restrictions" */ + bool suspended; }; static inline struct gprs_llc_lle *gprs_llc_llme_get_lle(struct gprs_llc_llme *llme, diff --git a/src/llc/llc_ll.c b/src/llc/llc_ll.c index 43a0951..a13a7f5 100644 --- a/src/llc/llc_ll.c +++ b/src/llc/llc_ll.c @@ -277,9 +277,15 @@ static int llc_prim_handle_ll_unitdata_req(struct osmo_gprs_llc_prim *llc_prim) lle = gprs_llc_llme_get_lle(llme, llc_prim->ll.sapi); } + if (lle->llme->suspended && llc_prim->ll.sapi != OSMO_GPRS_LLC_SAPI_GMM) { + LOGLLE(lle, LOGL_NOTICE, "Dropping frame to transmit, LLME is suspended\n"); + goto ret_free; + } + rc = gprs_llc_lle_tx_ui(lle, llc_prim->ll.l3_pdu, llc_prim->ll.l3_pdu_len, llc_prim->ll.unitdata_req.apply_gea); +ret_free: msgb_free(llc_prim->oph.msg); return rc; } diff --git a/src/llc/llc_llgmm.c b/src/llc/llc_llgmm.c index 5834041..7b09a69 100644 --- a/src/llc/llc_llgmm.c +++ b/src/llc/llc_llgmm.c @@ -100,7 +100,7 @@ struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_reset_req(uint32_t tlli return llc_prim; } -/* 7.2.1.2 LLGMM-RESET.cnf (SGSN):*/ +/* 7.2.1.2 LLGMM-RESET.cnf (SGSN): */ struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_reset_cnf(uint32_t tlli) { struct osmo_gprs_llc_prim *llc_prim; @@ -109,6 +109,34 @@ struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_reset_cnf(uint32_t tlli return llc_prim; } +/* 7.2.1.3 LLGMM-TRIGGER.req (MS): */ +struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_trigger_req(uint32_t tlli, uint8_t cause) +{ + struct osmo_gprs_llc_prim *llc_prim; + llc_prim = llc_prim_llgmm_alloc(OSMO_GPRS_LLC_LLGMM_TRIGGER, PRIM_OP_REQUEST, 0); + llc_prim->llgmm.tlli = tlli; + llc_prim->llgmm.trigger_req.cause = cause; + return llc_prim; +} + +/* 7.2.1.4 LLGMM-SUSPEND.req (MS/SGSN): */ +struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_suspend_req(uint32_t tlli) +{ + struct osmo_gprs_llc_prim *llc_prim; + llc_prim = llc_prim_llgmm_alloc(OSMO_GPRS_LLC_LLGMM_SUSPEND, PRIM_OP_REQUEST, 0); + llc_prim->llgmm.tlli = tlli; + return llc_prim; +} + +/* 7.2.1.5 LLGMM-RESUME.req (MS/SGSN):*/ +struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_llgm_resume_req(uint32_t tlli) +{ + struct osmo_gprs_llc_prim *llc_prim; + llc_prim = llc_prim_llgmm_alloc(OSMO_GPRS_LLC_LLGMM_RESUME, PRIM_OP_REQUEST, 0); + llc_prim->llgmm.tlli = tlli; + return llc_prim; +} + /******************************** * Handling from upper layers: ********************************/ @@ -246,6 +274,48 @@ ret_free: return rc; } +/* 7.2.1.4 LLGMM-SUSPEND.req (MS/SGSN):*/ +static int llc_prim_handle_llgm_suspend_req(struct osmo_gprs_llc_prim *llc_prim) +{ + int rc = 0; + 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)); + + llme->suspended = true; + +ret_free: + msgb_free(llc_prim->oph.msg); + return rc; +} + +/* 7.2.1.5 LLGMM-RESUME.req (MS/SGSN):*/ +static int llc_prim_handle_llgm_resume_req(struct osmo_gprs_llc_prim *llc_prim) +{ + int rc = 0; + 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)); + + llme->suspended = false; + +ret_free: + msgb_free(llc_prim->oph.msg); + return rc; +} + /* LLC higher layers push LLC primitive down to LLC layer: */ int gprs_llc_prim_llgmm_upper_down(struct osmo_gprs_llc_prim *llc_prim) { @@ -267,12 +337,12 @@ int gprs_llc_prim_llgmm_upper_down(struct osmo_gprs_llc_prim *llc_prim) case OSMO_PRIM(OSMO_GPRS_LLC_LLGMM_SUSPEND, PRIM_OP_REQUEST): OSMO_ASSERT(g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_MS || g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN); - rc = gprs_llc_prim_handle_unsupported(llc_prim); + rc = llc_prim_handle_llgm_suspend_req(llc_prim); break; case OSMO_PRIM(OSMO_GPRS_LLC_LLGMM_RESUME, PRIM_OP_REQUEST): OSMO_ASSERT(g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_MS || g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN); - rc = gprs_llc_prim_handle_unsupported(llc_prim); + rc = llc_prim_handle_llgm_resume_req(llc_prim); break; case OSMO_PRIM(OSMO_GPRS_LLC_LLGMM_IOV, PRIM_OP_REQUEST): OSMO_ASSERT(g_llc_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN);