diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2023-07-18 18:43:38 +0200 |
---|---|---|
committer | Pau Espin Pedrol <pespin@sysmocom.de> | 2023-07-20 10:00:22 +0200 |
commit | f87b9da362335ddbbcb7693a43fe5ca04df84298 (patch) | |
tree | f563819be674867169cee40159afc654aff522fd | |
parent | 70c6407f69e1df8a80db0a621dad5cfb38015003 (diff) |
sm: Handle GMMSM-MODIFY.ind primitive
Change-Id: Ic765b7a565cac4abcf34d8c6868e103971d17822
-rw-r--r-- | include/osmocom/gprs/sm/sm_private.h | 5 | ||||
-rw-r--r-- | src/sm/sm.c | 59 | ||||
-rw-r--r-- | src/sm/sm_prim.c | 82 |
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; |