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
This commit is contained in:
Pau Espin 2023-05-23 15:59:24 +02:00
parent 05b127acbb
commit 72ea2cf2fc
4 changed files with 86 additions and 3 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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;
}

View File

@ -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);