laforge submitted this change.
GMM: rework PDP context status
Use an uint16 instead of an pointer with an unknown length.
Also encode the current active PDP context (e.g. on 2G/4G
mobilty this could change). It resynchronizes the UE with the SGSN
state.
Change-Id: I12d3110c9365132f96ef7ff8a1be22a431682c81
---
M src/sgsn/gprs_gmm.c
M tests/sgsn/sgsn_test.c
2 files changed, 77 insertions(+), 55 deletions(-)
diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c
index 6122421..357b762 100644
--- a/src/sgsn/gprs_gmm.c
+++ b/src/sgsn/gprs_gmm.c
@@ -196,6 +196,61 @@
sgsn_mm_ctx_cleanup_free(ctx);
}
+
+/* 3GPP TS 24.008 § 10.5.7.1 Process PDP context status value, bit 0 corresponds to nsapi 0 */
+static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
+ uint16_t pdp_status)
+{
+ struct sgsn_pdp_ctx *pdp, *pdp2;
+ /* 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. */
+
+ /* NSAPI 0 - 4 are spare, ignore these */
+ pdp_status &= 0xffe0;
+
+ llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
+ bool active = (pdp_status & (1 << pdp->nsapi));
+ if (active)
+ continue;
+
+ LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
+ "due to PDP CTX STATUS IE=0x%02x\n",
+ pdp->nsapi, pdp_status);
+ pdp->ue_pdp_active = false;
+ if (pdp->ggsn)
+ sgsn_delete_pdp_ctx(pdp);
+ else /* GTP side already detached, freeing */
+ sgsn_pdp_ctx_free(pdp);
+ }
+}
+
+/* 3GPP TS 24.008 § 10.5.7.1 Encode PDP context status value, bit 0 correspond to nsapi 0 */
+uint16_t encode_ms_ctx_status(struct sgsn_mm_ctx *mmctx)
+{
+ struct sgsn_pdp_ctx *pdp;
+
+ uint16_t pdp_status = 0;
+
+ llist_for_each_entry(pdp, &mmctx->pdp_list, list) {
+ if (pdp->ue_pdp_active)
+ pdp_status |= (1 << pdp->nsapi);
+ }
+
+ return pdp_status;
+}
+
+/* 3GPP TS 24.008 § 4.7.13.4/10.5.7.1 Service request procedure not accepted by the
+ * network. Returns true if MS has active PDP contexts in pdp_status */
+bool pdp_status_has_active_nsapis(uint16_t pdp_status)
+{
+ /* NSAPI 0 - 4 are spare and should be ignored 0 */
+ return (pdp_status >> 5) != 0;
+}
+
/* Chapter 9.4.18 */
static int _tx_status(struct msgb *msg, uint8_t cause,
struct sgsn_mm_ctx *mmctx)
@@ -1487,6 +1542,8 @@
rua = (struct gsm48_ra_upd_ack *) msgb_put(msg, sizeof(*rua));
rua->force_stby = 0; /* not indicated */
rua->upd_result = 0; /* RA updated */
+
+ /* Periodic RA update timer */
t = osmo_tdef_get(sgsn->cfg.T_defs, 3312, OSMO_TDEF_S, -1);
rua->ra_upd_timer = gprs_secs_to_tmr_floor(t);
@@ -1515,12 +1572,19 @@
}
*l = rc;
#endif
+ /* MS identity */
+ /* List of Received N-PDU */
/* Optional: Negotiated READY timer value */
t = osmo_tdef_get(sgsn->cfg.T_defs, 3314, OSMO_TDEF_S, -1);
msgb_tv_put(msg, GSM48_IE_GMM_TIMER_READY, gprs_secs_to_tmr_floor(t));
- /* Option: MS ID, ... */
+ /* GMM cause */
+ /* PDP Context Status */
+ uint16_t pdp_ctx_status = encode_ms_ctx_status(mm);
+ msgb_tlv_put(msg, GSM48_IE_GMM_PDP_CTX_STATUS, 2, (uint8_t *) &pdp_ctx_status);
+
+ /* MS ID, ... */
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
@@ -1545,48 +1609,6 @@
return gsm48_gmm_sendmsg(msg, 0, NULL, false);
}
-static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
- const uint8_t *pdp_status)
-{
- struct sgsn_pdp_ctx *pdp, *pdp2;
- /* 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. */
-
- llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
- bool inactive = (pdp->nsapi < 8) ?
- !(pdp_status[0] & (1 << pdp->nsapi)) :
- !(pdp_status[1] & (1 << (pdp->nsapi - 8)));
- if (!inactive)
- continue;
-
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
- "due to PDP CTX STATUS IE=0x%02x%02x\n",
- pdp->nsapi, pdp_status[1], pdp_status[0]);
- pdp->ue_pdp_active = false;
- if (pdp->ggsn)
- sgsn_delete_pdp_ctx(pdp);
- else /* GTP side already detached, freeing */
- sgsn_pdp_ctx_free(pdp);
- }
-}
-
-/* 3GPP TS 24.008 § 4.7.13.4 Service request procedure not accepted by the
- * network. Returns true if MS has active PDP contexts in pdp_status */
-bool pdp_status_has_active_nsapis(const uint8_t *pdp_status, const size_t pdp_status_len)
-{
- size_t i;
-
- for (i = 0; i < pdp_status_len; i++)
- if (pdp_status[i] != 0)
- return true;
-
- return false;
-}
-
/* Chapter 9.4.14: Routing area update request */
static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
struct gprs_llc_llme *llme)
@@ -1777,7 +1799,7 @@
/* Look at PDP Context Status IE and see if MS's view of
* activated/deactivated NSAPIs agrees with our view */
if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_PDP_CTX_STATUS)) {
- const uint8_t *pdp_status = TLVP_VAL(&req.tlv, GSM48_IE_GMM_PDP_CTX_STATUS);
+ uint16_t pdp_status = osmo_load16le(TLVP_VAL(&req.tlv, GSM48_IE_GMM_PDP_CTX_STATUS));
process_ms_ctx_status(mmctx, pdp_status);
}
@@ -1936,8 +1958,7 @@
/* Look at PDP Context Status IE and see if MS's view of
* activated/deactivated NSAPIs agrees with our view */
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
- const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
- const size_t pdp_status_len = TLVP_LEN(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
+ uint16_t pdp_status = tlvp_val16be(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
process_ms_ctx_status(ctx, pdp_status);
@@ -1946,7 +1967,7 @@
* Active state in pdp_status but there is no PDP contexts on
* SGSN side then Reject with the cause will force the mobile to
* reset PDP contexts */
- if (llist_empty(&ctx->pdp_list) && pdp_status_has_active_nsapis(pdp_status, pdp_status_len)) {
+ if (llist_empty(&ctx->pdp_list) && pdp_status_has_active_nsapis(pdp_status)) {
reject_cause = GMM_CAUSE_NO_PDP_ACTIVATED;
goto rejected;
}
diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c
index 29dad74..6dcda84 100644
--- a/tests/sgsn/sgsn_test.c
+++ b/tests/sgsn/sgsn_test.c
@@ -1582,20 +1582,21 @@
cleanup_test();
}
-bool pdp_status_has_active_nsapis(const uint8_t *pdp_status, const size_t pdp_status_len);
+bool pdp_status_has_active_nsapis(uint16_t pdp_status);
static void test_pdp_status_has_active_nsapis(void)
{
- const size_t pdp_status_len = 2;
- const uint8_t pdp_status1[] = { 0b00100000, 0b00000000 }; /* PDP NSAPI 5 active */
- const uint8_t pdp_status2[] = { 0b00000000, 0b00000000 }; /* no active PDP NSAPI */
- const uint8_t pdp_status3[] = { 0b00000000, 0b00000001 }; /* PDP NSAPI 8 active */
+ uint16_t pdp_status1 = 0b0000000000100000; /* PDP NSAPI 5 active */
+ uint16_t pdp_status2 = 0b0000000000000000; /* no active PDP NSAPI */
+ uint16_t pdp_status3 = 0b0000000100000000; /* PDP NSAPI 8 active */
+ uint16_t pdp_status4 = 0b0000000000000001; /* reserved NSAPI 0 active -> no active */
printf("Testing pdp_status_has_active_nsapis\n");
- OSMO_ASSERT(pdp_status_has_active_nsapis(pdp_status1, pdp_status_len));
- OSMO_ASSERT(!pdp_status_has_active_nsapis(pdp_status2, pdp_status_len));
- OSMO_ASSERT(pdp_status_has_active_nsapis(pdp_status3, pdp_status_len));
+ OSMO_ASSERT(pdp_status_has_active_nsapis(pdp_status1));
+ OSMO_ASSERT(!pdp_status_has_active_nsapis(pdp_status2));
+ OSMO_ASSERT(pdp_status_has_active_nsapis(pdp_status3));
+ OSMO_ASSERT(!pdp_status_has_active_nsapis(pdp_status4));
}
static struct log_info_cat gprs_categories[] = {
To view, visit change 39241. To unsubscribe, or for help writing mail filters, visit settings.