aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2018-07-23 11:24:07 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2018-07-23 11:25:53 +0200
commitb5f93346df89aec1d2e1469831278616a3dbd5b6 (patch)
tree340edb78be9a50f0c56dc363bcae6758158712b6
parent8e8c7ef3c7c2822737e7b74d299d520f0f4d94e0 (diff)
gtp: Add new replacement cb_recovery2 for cb_recovery
Sometimes the originating pdp ctx causing the Recovery Procedure is required, in order to drop all pdp ctx but this one, which specs specify should be handled as valid: """ The SGSN receiving the Recovery information element shall handle it as when an Echo Response message is received but shall consider the PDP context being created as active if the response indicates successful context activation at the GGSN. """ Change-Id: I53e92298f2f6b84d662a3300d922e8c2ccb178bc
-rw-r--r--gtp/gtp.c51
-rw-r--r--gtp/gtp.h6
2 files changed, 45 insertions, 12 deletions
diff --git a/gtp/gtp.c b/gtp/gtp.c
index 95abbef..1d58088 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -190,6 +190,15 @@ int gtp_set_cb_conf(struct gsn_t *gsn,
return 0;
}
+static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer,
+ struct pdp_t * pdp, uint8_t recovery)
+{
+ if (gsn->cb_recovery)
+ gsn->cb_recovery(peer, recovery);
+ if (gsn->cb_recovery2)
+ gsn->cb_recovery2(peer, pdp, recovery);
+}
+
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
{
@@ -197,6 +206,20 @@ int gtp_set_cb_recovery(struct gsn_t *gsn,
return 0;
}
+/* cb_recovery()
+ * pdp may be NULL if Recovery IE was received from a message independent
+ * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
+ * local setup. In case pdp is known, caller may want to keep that pdp alive to
+ * handle subsequent msg cb as this specific pdp ctx is still valid according to
+ * specs.
+ */
+int gtp_set_cb_recovery2(struct gsn_t *gsn,
+ int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery))
+{
+ gsn->cb_recovery2 = cb_recovery2;
+ return 0;
+}
+
int gtp_set_cb_data_ind(struct gsn_t *gsn,
int (*cb_data_ind) (struct pdp_t * pdp,
void *pack, unsigned len))
@@ -977,8 +1000,7 @@ int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
if (gsn->cb_conf)
gsn->cb_conf(type, recovery, NULL, cbp);
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, NULL, recovery);
return 0;
}
@@ -1310,6 +1332,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
struct pdp_t pdp_buf;
union gtpie_member *ie[GTPIE_SIZE];
uint8_t recovery;
+ bool recovery_recvd = false;
+ int rc;
uint16_t seq = get_seq(pack);
int hlen = get_hlen(pack);
@@ -1410,8 +1434,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
/* Recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ /* we use recovery futher down after announcing new pdp ctx to user */
+ recovery_recvd = true;
}
/* Selection mode (conditional) */
@@ -1612,6 +1636,9 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
/* Switch to using the old pdp context */
pdp = pdp_old;
+ if (recovery_recvd)
+ emit_cb_recovery(gsn, peer, pdp, recovery);
+
/* Confirm to peer that things were "successful" */
return gtp_create_pdp_resp(gsn, version, pdp,
GTPCAUSE_ACC_REQ);
@@ -1633,13 +1660,16 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version,
/* Callback function to validata login */
if (gsn->cb_create_context_ind != 0)
- return gsn->cb_create_context_ind(pdp);
+ rc = gsn->cb_create_context_ind(pdp);
else {
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
"No create_context_ind callback defined\n");
- return gtp_create_pdp_resp(gsn, version, pdp,
+ rc = gtp_create_pdp_resp(gsn, version, pdp,
GTPCAUSE_NOT_SUPPORTED);
}
+ if (recovery_recvd)
+ emit_cb_recovery(gsn, peer, pdp, recovery);
+ return rc;
}
/* Handle Create PDP Context Response */
@@ -1696,8 +1726,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
/* Extract recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, pdp, recovery);
}
/* Extract protocol configuration options (optional) */
@@ -2106,8 +2135,7 @@ static int gtp_update_pdp_ind(struct gsn_t *gsn, uint8_t version,
/* Recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, pdp, recovery);
}
if (version == 0) {
@@ -2267,8 +2295,7 @@ static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
/* Extract recovery (optional) */
if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) {
- if (gsn->cb_recovery)
- gsn->cb_recovery(peer, recovery);
+ emit_cb_recovery(gsn, peer, pdp, recovery);
}
/* Check all conditional information elements */
diff --git a/gtp/gtp.h b/gtp/gtp.h
index f185424..ed594f1 100644
--- a/gtp/gtp.h
+++ b/gtp/gtp.h
@@ -271,6 +271,7 @@ struct gsn_t {
int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
+ int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
/* Counters */
@@ -361,6 +362,11 @@ extern int gtp_set_cb_conf(struct gsn_t *gsn,
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer,
+ uint8_t recovery))
+ OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
+int gtp_set_cb_recovery2(struct gsn_t *gsn,
+ int (*cb) (struct sockaddr_in * peer,
+ struct pdp_t * pdp,
uint8_t recovery));
/* Internal functions (not part of the API */