gtphub: improve handling of restarted peer.

Handle peer restart earlier, so that all the tunnels are deleted by the restart
code path, instead of the first one being deleted due to reused TEI. That
caused confusing logging messages.

Also, when receiving Delete confirmations from the peer that didn't restart,
don't complain about unknown peer, but acknowledge and remove the half
invalidated tunnel. This means that the pending delete entry from the restart
code path is not needed / not used, so don't bother to add pending delete
entries upon peer restart.

The test test_peer_restarted_reusing_tei() hits the situation where a tunnel is
removed because of a reused TEI rather than the restart counter. Adjust the
test to expect the "out-of-band" delete request earlier on, and to still see
the half invalidated tunnel around. Enhance the test by adding the delete
response from the peer that didn't restart, and add a final tunnels_are()
verification.

Sponsored-by: On-Waves ehi
diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index c8dddc5..a68fa65 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -1871,14 +1871,6 @@
 			 * dropped because the tunnel is rendered unusable. */
 			gtphub_send_del_pdp_ctx(hub, tun, other_side_idx(side_idx));
 
-			struct pending_delete *pd;
-			pd = pending_delete_new();
-			pd->tun = tun;
-			pd->teardown_ind = 0xff;
-			pd->nsapi = 0;
-			llist_add(&pd->entry, &hub->pending_deletes);
-			expiry_add(&hub->expire_quickly, &pd->expiry_entry, p->timestamp);
-
 			gtphub_tunnel_endpoint_set_peer(&tun->endpoint[side_idx][GTPH_PLANE_CTRL],
 							NULL);
 			gtphub_tunnel_endpoint_set_peer(&tun->endpoint[side_idx][GTPH_PLANE_USER],
@@ -2228,6 +2220,9 @@
 	LOG(LOGL_DEBUG, "from %s peer: %s\n", gtphub_side_idx_names[side_idx],
 	    gtphub_port_str(from_peer));
 
+	gtphub_check_restart_counter(hub, &p, from_peer);
+	gtphub_map_restart_counter(hub, &p);
+
 	struct gtphub_peer_port *to_peer_from_seq;
 	struct gtphub_peer_port *to_peer;
 	if (gtphub_unmap(hub, &p, from_peer,
@@ -2249,6 +2244,15 @@
 			return -1;
 	}
 
+	if (!to_peer && p.tun && p.type == GTP_DELETE_PDP_RSP) {
+		/* It's a delete confirmation for a tunnel that is partly
+		 * invalid, probably marked unsuable due to a restarted peer.
+		 * Remove the tunnel and be happy without forwarding. */
+		expiring_item_del(&p.tun->expiry_entry);
+		p.tun = NULL;
+		return 0;
+	}
+
 	if (!to_peer) {
 		LOG(LOGL_ERROR, "No %s to send to. Dropping packet%s"
 		    " (type=%" PRIu8 ", header-TEI=%" PRIx32 ", seq=%" PRIx16 ").\n",
@@ -2273,9 +2277,6 @@
 	 * or the tunnel has been deleted due to this message. */
 	OSMO_ASSERT(p.tun || (p.type == GTP_DELETE_PDP_RSP));
 
-	gtphub_check_restart_counter(hub, &p, from_peer);
-	gtphub_map_restart_counter(hub, &p);
-
 	/* If the GGSN is replying to an SGSN request, the sequence nr has
 	 * already been unmapped above (to_peer_from_seq != NULL), and we need not
 	 * create a new mapping. */