sm: Handle GMMSM-MODIFY.ind primitive

Change-Id: Ic765b7a565cac4abcf34d8c6868e103971d17822
This commit is contained in:
Pau Espin 2023-07-18 18:43:38 +02:00
parent 70c6407f69
commit f87b9da362
3 changed files with 145 additions and 1 deletions

View File

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

View File

@ -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 */
}
}

View File

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