aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2023-07-18 18:43:38 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2023-07-20 10:00:22 +0200
commitf87b9da362335ddbbcb7693a43fe5ca04df84298 (patch)
treef563819be674867169cee40159afc654aff522fd
parent70c6407f69e1df8a80db0a621dad5cfb38015003 (diff)
sm: Handle GMMSM-MODIFY.ind primitive
-rw-r--r--include/osmocom/gprs/sm/sm_private.h5
-rw-r--r--src/sm/sm.c59
-rw-r--r--src/sm/sm_prim.c82
3 files changed, 145 insertions, 1 deletions
diff --git a/include/osmocom/gprs/sm/sm_private.h b/include/osmocom/gprs/sm/sm_private.h
index 98eaf79..b1b3bc2 100644
--- a/include/osmocom/gprs/sm/sm_private.h
+++ b/include/osmocom/gprs/sm/sm_private.h
@@ -156,6 +156,7 @@ int gprs_sm_prim_call_sndcp_up_cb(struct osmo_gprs_sndcp_prim *sndcp_prim);
struct osmo_gprs_sm_prim *gprs_sm_prim_alloc_smreg_pdp_act_cnf(void);
struct osmo_gprs_sm_prim *gprs_sm_prim_alloc_smreg_pdp_act_ind(void);
+struct osmo_gprs_sm_prim *gprs_sm_prim_alloc_smreg_pdp_deact_ind(void);
/* sm.c: */
struct gprs_sm_ms *gprs_sm_ms_alloc(uint32_t ms_id);
@@ -167,9 +168,13 @@ struct gprs_sm_entity *gprs_sm_entity_alloc(struct gprs_sm_ms *ms, uint32_t nsap
void gprs_sm_entity_free(struct gprs_sm_entity *sme);
struct gprs_sm_entity *gprs_sm_find_sme_by_sess_id(uint32_t sess_id);
+void gprs_sm_handle_ie_pdp_ctx_status(struct gprs_sm_ms *ms, const uint8_t *pdp_status);
+
int gprs_sm_submit_gmmsm_assign_req(const struct gprs_sm_entity *sme);
int gprs_sm_submit_smreg_pdp_act_cnf(const struct gprs_sm_entity *sme, enum gsm48_gsm_cause cause);
+int gprs_sm_submit_smreg_pdp_deact_ind(const struct gprs_sm_entity *sme, enum gsm48_gsm_cause cause);
int gprs_sm_submit_snsm_act_ind(const struct gprs_sm_entity *sme);
+int gprs_sm_submit_snsm_deact_ind(const struct gprs_sm_entity *sme);
int gprs_sm_tx_act_pdp_ctx_req(struct gprs_sm_entity *sme);
int gprs_sm_rx(struct gprs_sm_entity *sme, struct gsm48_hdr *gh, unsigned int len);
diff --git a/src/sm/sm.c b/src/sm/sm.c
index 79fbc7d..308117f 100644
--- a/src/sm/sm.c
+++ b/src/sm/sm.c
@@ -236,6 +236,24 @@ int gprs_sm_submit_smreg_pdp_act_cnf(const struct gprs_sm_entity *sme, enum gsm4
return rc;
}
+int gprs_sm_submit_smreg_pdp_deact_ind(const struct gprs_sm_entity *sme, enum gsm48_gsm_cause cause)
+{
+ struct osmo_gprs_sm_prim *sm_prim_tx;
+ int rc;
+
+ sm_prim_tx = gprs_sm_prim_alloc_smreg_pdp_deact_ind();
+ sm_prim_tx->smreg.ms_id = sme->ms->ms_id;
+ sm_prim_tx->smreg.pdp_deact_ind.nsapi[0] = sme->nsapi;
+ sm_prim_tx->smreg.pdp_deact_ind.num_nsapi = 1;
+ sm_prim_tx->smreg.pdp_deact_ind.tear_down_ind = 0;
+ sm_prim_tx->smreg.pdp_deact_ind.cause = cause;
+ sm_prim_tx->smreg.pdp_deact_ind.pco_len = sme->pco_len;
+ if (sme->pco_len)
+ memcpy(sm_prim_tx->smreg.pdp_deact_cnf.pco, &sme->pco, sme->pco_len);
+
+ rc = gprs_sm_prim_call_up_cb(sm_prim_tx);
+ return rc;
+}
int gprs_sm_submit_snsm_act_ind(const struct gprs_sm_entity *sme)
{
@@ -253,6 +271,18 @@ int gprs_sm_submit_snsm_act_ind(const struct gprs_sm_entity *sme)
return rc;
}
+int gprs_sm_submit_snsm_deact_ind(const struct gprs_sm_entity *sme)
+{
+ struct osmo_gprs_sndcp_prim *sndcp_prim_tx;
+ int rc;
+
+ sndcp_prim_tx = osmo_gprs_sndcp_prim_alloc_snsm_deactivate_ind(
+ sme->ms->gmm.tlli, sme->nsapi);
+
+ rc = gprs_sm_prim_call_sndcp_up_cb(sndcp_prim_tx);
+ return rc;
+}
+
/* Tx SM Activate PDP context request, 9.5.1 */
int gprs_sm_tx_act_pdp_ctx_req(struct gprs_sm_entity *sme)
{
@@ -431,3 +461,32 @@ int gprs_sm_rx(struct gprs_sm_entity *sme, struct gsm48_hdr *gh, unsigned int le
return rc;
}
+
+void gprs_sm_handle_ie_pdp_ctx_status(struct gprs_sm_ms *ms, const uint8_t *pdp_status)
+{
+ unsigned int i;
+ /* 24.008 4.7.5.1.3: If the PDP context status information element is
+ * included in ROUTING AREA UPDATE REQUEST message, then the network
+ * shall deactivate all those PDP contexts locally (without peer to
+ * peer signalling between the MS and the network), which are not in SM
+ * state PDP-INACTIVE on network side but are indicated by the MS as
+ * being in state PDP-INACTIVE. */
+
+ for (i = 0; i < ARRAY_SIZE(ms->pdp); i++) {
+ struct gprs_sm_entity *sme = ms->pdp[i];
+ bool inactive;
+ if (!sme)
+ continue;
+
+ inactive = (sme->nsapi < 8) ?
+ !(pdp_status[0] & (1 << sme->nsapi)) :
+ !(pdp_status[1] & (1 << (sme->nsapi - 8)));
+ if (!inactive)
+ continue;
+ LOGSME(sme, LOGL_NOTICE,
+ "PDP context status informs PDP context is PDP-INACTIVE, deleting\n");
+ gprs_sm_submit_snsm_deact_ind(sme);
+ /* See TS 24.007 Appendix C.10: Wait for SNSM-DEACTIVATE.rsp,
+ * then submit SMREG-DEACTIVATE.ind and free the object */
+ }
+}
diff --git a/src/sm/sm_prim.c b/src/sm/sm_prim.c
index b513aa7..66df8c2 100644
--- a/src/sm/sm_prim.c
+++ b/src/sm/sm_prim.c
@@ -187,6 +187,14 @@ struct osmo_gprs_sm_prim *gprs_sm_prim_alloc_smreg_pdp_act_ind(void)
return sm_prim;
}
+/* TS 24.007 6.5.1.7 SMREG-PDP-ACTIVATE-IND */
+struct osmo_gprs_sm_prim *gprs_sm_prim_alloc_smreg_pdp_deact_ind(void)
+{
+ struct osmo_gprs_sm_prim *sm_prim;
+ sm_prim = sm_prim_smreg_alloc(OSMO_GPRS_SM_SMREG_PDP_DEACTIVATE, PRIM_OP_INDICATION, 0);
+ return sm_prim;
+}
+
static int gprs_sm_prim_handle_unsupported(struct osmo_gprs_sm_prim *sm_prim)
{
LOGSM(LOGL_ERROR, "Unsupported sm_prim! %s\n", osmo_gprs_sm_prim_name(sm_prim));
@@ -339,7 +347,7 @@ int gprs_sm_prim_call_sndcp_up_cb(struct osmo_gprs_sndcp_prim *sndcp_prim)
return rc;
}
-/* TS 24.007 6.6.1.1 SMREG-Attach.request:*/
+/* TS 24.007 5.1.2.20 SNSM-ACTIVATE.response: */
static int gprs_sm_prim_handle_snsm_act_resp(struct osmo_gprs_sndcp_prim *sndcp_prim)
{
int rc;
@@ -365,6 +373,37 @@ static int gprs_sm_prim_handle_snsm_act_resp(struct osmo_gprs_sndcp_prim *sndcp_
return rc;
}
+/* TS 24.007 5.1.2.22 SNSM-DEACTIVATE.response: */
+static int gprs_sm_prim_handle_snsm_deact_resp(struct osmo_gprs_sndcp_prim *sndcp_prim)
+{
+ int rc;
+ struct gprs_sm_ms *ms;
+ struct gprs_sm_entity *sme;
+
+ ms = gprs_sm_find_ms_by_tlli(sndcp_prim->snsm.tlli);
+ if (!ms) {
+ LOGSM(LOGL_ERROR, "Rx %s: Unable to find MS with TLLI=0x%08x\n",
+ osmo_gprs_sndcp_prim_name(sndcp_prim), sndcp_prim->snsm.tlli);
+ return -ENOENT;
+ }
+
+ sme = gprs_sm_ms_get_pdp_ctx(ms, sndcp_prim->snsm.activate_rsp.nsapi);
+ if (!sme) {
+ LOGMS(ms, LOGL_ERROR, "Rx %s: Unable to find NSAPI=%u\n",
+ osmo_gprs_sndcp_prim_name(sndcp_prim),
+ sndcp_prim->snsm.activate_rsp.nsapi);
+ return -ENOENT;
+ }
+
+ rc = gprs_sm_submit_smreg_pdp_deact_ind(sme, GSM_CAUSE_REACT_RQD);
+
+ /* Submitting GMM_RELEASE.ind received the GMM release was delayed until
+ * getting SNSM-DEACT.ind->rsp pingpong, since it would free the sme. Do it now:
+ */
+ rc = osmo_fsm_inst_dispatch(sme->ms_fsm.fi, GPRS_SM_MS_EV_GMM_RELEASE_IND, NULL);
+ return rc;
+}
+
/* SNDCP higher layers push SNDCP primitive (SNSM) down to SM layer: */
static int gprs_sm_prim_handle_sndcp_snsm(struct osmo_gprs_sndcp_prim *sndcp_prim)
{
@@ -375,6 +414,8 @@ static int gprs_sm_prim_handle_sndcp_snsm(struct osmo_gprs_sndcp_prim *sndcp_pri
rc = gprs_sm_prim_handle_snsm_act_resp(sndcp_prim);
break;
case OSMO_PRIM(OSMO_GPRS_SNDCP_SNSM_DEACTIVATE, PRIM_OP_RESPONSE):
+ rc = gprs_sm_prim_handle_snsm_deact_resp(sndcp_prim);
+ break;
case OSMO_PRIM(OSMO_GPRS_SNDCP_SNSM_MODIFY, PRIM_OP_RESPONSE):
case OSMO_PRIM(OSMO_GPRS_SNDCP_SNSM_STATUS, PRIM_OP_REQUEST):
case OSMO_PRIM(OSMO_GPRS_SNDCP_SNSM_SEQUENCE, PRIM_OP_RESPONSE):
@@ -530,6 +571,42 @@ static int gprs_sm_prim_handle_gmmsm_unitdata_ind(struct osmo_gprs_gmm_prim *gmm
return rc;
}
+/* Osmocom specific, GMMSM-MODIFY-IND */
+static int gprs_sm_prim_handle_gmmsm_modify_ind(struct osmo_gprs_gmm_prim *gmm_prim)
+{
+ struct osmo_gprs_gmm_gmmsm_prim *gmmsm = &gmm_prim->gmmsm;
+ struct gprs_sm_entity *sme;
+ struct gprs_sm_ms *ms;
+ int rc = 0;
+
+ sme = gprs_sm_find_sme_by_sess_id(gmmsm->sess_id);
+ if (!sme) {
+ LOGSM(LOGL_ERROR, "Rx GMMSM-MODIFY.ind for non existing SM Entity\n");
+ return -EINVAL;
+ }
+
+ ms = sme->ms;
+
+ /* Update allocated PTMSI: */
+ if (gmm_prim->gmmsm.modify_ind.allocated_ptmsi != GSM_RESERVED_TMSI)
+ ms->gmm.ptmsi = gmm_prim->gmmsm.modify_ind.allocated_ptmsi;
+ ms->gmm.ptmsi_sig = gmm_prim->gmmsm.modify_ind.allocated_ptmsi_sig;
+ /* Update allocated TLLI: */
+ ms->gmm.tlli = gmm_prim->gmmsm.modify_ind.allocated_tlli;
+ /* Update the current RAI: */
+ memcpy(&ms->gmm.ra, &gmm_prim->gmmsm.modify_ind.rai, sizeof(ms->gmm.ra));
+
+ if (gmm_prim->gmmsm.modify_ind.pdp_ctx_status_present)
+ gprs_sm_handle_ie_pdp_ctx_status(ms, gmm_prim->gmmsm.modify_ind.pdp_ctx_status);
+ /* Note: sme may be freed here, it needs to be looked up again:
+ * sme = gprs_sm_find_sme_by_sess_id(gmmsm->sess_id);
+ */
+
+ /* TODO: Handle gmm_prim->gmmsm.modify_ind.rx_npdu_numbers_list
+ * Submit SNSM-SEQUENCE-IND, see TS 24.007 "C.16(cont’d) Routing Area Update, Inter SGSN" */
+ return rc;
+}
+
static int gprs_sm_prim_handle_gmmsm(struct osmo_gprs_gmm_prim *gmm_prim)
{
int rc = 0;
@@ -543,6 +620,9 @@ static int gprs_sm_prim_handle_gmmsm(struct osmo_gprs_gmm_prim *gmm_prim)
case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_UNITDATA, PRIM_OP_INDICATION):
rc = gprs_sm_prim_handle_gmmsm_unitdata_ind(gmm_prim);
break;
+ case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_MODIFY, PRIM_OP_INDICATION):
+ rc = gprs_sm_prim_handle_gmmsm_modify_ind(gmm_prim);
+ break;
default:
rc = gprs_sm_prim_handle_gmm_unsupported(gmm_prim);
rc = 1;