sgsn: Fix crash using new libgtp cb_recovery2 API

When PDP CTX CREATE ACK is received with an increased RestartCtr, cb_recovery2
is called first, which will dettach ggsn from al pdp ctx (free the
pdp_t). But when giving control back from the ctrl, libgtp still uses
that freed ctx and sends it back to osmo-sgsn through cb_conf().

As specs state in any case that we need to handle the message containing
the increased RestartCtr as valid, we then need to avoid freeing the pdp
ctx and leave handling for later in cb_conf.

Depends: osmo-ggsn (libgtp) Change-Id I53e92298f2f6b84d662a3300d922e8c2ccb178bc.
Change-Id: I0989c00e18ca95a099e1a312940eaac71957b444
diff --git a/src/gprs/sgsn_libgtp.c b/src/gprs/sgsn_libgtp.c
index 3813397..7829796 100644
--- a/src/gprs/sgsn_libgtp.c
+++ b/src/gprs/sgsn_libgtp.c
@@ -591,9 +591,10 @@
 }
 
 /* Any message received by GGSN contains a recovery IE */
-static int cb_recovery(struct sockaddr_in *peer, uint8_t recovery)
+static int cb_recovery2(struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
 {
 	struct sgsn_ggsn_ctx *ggsn;
+	struct sgsn_pdp_ctx *pctx = NULL;
 
 	ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr);
 	if (!ggsn) {
@@ -606,11 +607,13 @@
 		ggsn->remote_restart_ctr = recovery;
 	} else if (ggsn->remote_restart_ctr != recovery) {
 		/* counter has changed (GGSN restart): release all PDP */
-		LOGP(DGPRS, LOGL_NOTICE, "GGSN recovery (%u->%u), "
-		     "releasing all PDP contexts\n",
-		     ggsn->remote_restart_ctr, recovery);
+		LOGP(DGPRS, LOGL_NOTICE, "GGSN recovery (%u->%u) pdp=%p, "
+		     "releasing all%s PDP contexts\n",
+		     ggsn->remote_restart_ctr, recovery, pdp, pdp ? " other" : "");
 		ggsn->remote_restart_ctr = recovery;
-		sgsn_ggsn_ctx_drop_all_pdp(ggsn);
+		if (pdp)
+			pctx = pdp->priv;
+		sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, pctx);
 	}
 	return 0;
 }
@@ -896,7 +899,7 @@
 	/* Register callbackcs with libgtp */
 	gtp_set_cb_delete_context(gsn, cb_delete_context);
 	gtp_set_cb_conf(gsn, cb_conf);
-	gtp_set_cb_recovery(gsn, cb_recovery);
+	gtp_set_cb_recovery2(gsn, cb_recovery2);
 	gtp_set_cb_data_ind(gsn, cb_data_ind);
 	gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);
 	gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);