aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2015-11-11 14:01:06 +0100
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2015-11-16 15:16:39 +0100
commitc83cd898ef3c167c370d0c3240f355f192388ec7 (patch)
tree30d6cbbd4cacdb1174d41398a6855bcf53180d41
parente921e32c828e4c4a62fa3edc17bf49abf8e6d8d7 (diff)
gtphub: fix handling of sender from nonstandard port.
Allow a peer sending from an unknown port but a known address, and just create the port (and unmap the seq nr back to this port later to return the response to the sender). Only an SGSN on the Ctrl plane is allowed to make the very first contact from an unknown address. Sponsored-by: On-Waves ehi
-rw-r--r--openbsc/src/gprs/gtphub.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index 9a29cc076..d6dbb4d0c 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -1365,6 +1365,9 @@ static int gtphub_handle_echo(struct gtphub *hub, struct gtp_packet_desc *p, uin
return sizeof(echo_response_data);
}
+struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
+ const struct osmo_sockaddr *addr);
+
/* Parse buffer as GTP packet, replace elements in-place and return the ofd and
* address to forward to. Return a pointer to the osmo_fd, but copy the
* sockaddr to *to_addr. The reason for this is that the sockaddr may expire at
@@ -1419,7 +1422,10 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub,
}
if (!ggsn) {
- ggsn = gtphub_port_find_sa(&hub->to_ggsns[plane_idx], from_addr);
+ /* Find a GGSN peer with a matching address. The sender's port
+ * may in fact differ. */
+ ggsn = gtphub_known_addr_have_port(&hub->to_ggsns[plane_idx],
+ from_addr);
}
/* If any PDP context has been created, we already have an entry for
@@ -1560,8 +1566,9 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub,
if (!sgsn) {
/* If any contact has been made before, we already have an
- * entry for this SGSN. */
- sgsn = gtphub_port_find_sa(&hub->to_sgsns[plane_idx], from_addr);
+ * entry for this SGSN. The port may differ. */
+ sgsn = gtphub_known_addr_have_port(&hub->to_sgsns[plane_idx],
+ from_addr);
}
if (!sgsn) {
@@ -2041,6 +2048,31 @@ struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
return gtphub_addr_add_port(a, port);
}
+/* Find a GGSN peer with a matching address. If the address is known but the
+ * port not, create a new port for that peer address. */
+struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
+ const struct osmo_sockaddr *addr)
+{
+ struct gtphub_peer_addr *pa;
+ struct gtphub_peer_port *pp;
+
+ struct gsn_addr gsna;
+ uint16_t port;
+ gsn_addr_from_sockaddr(&gsna, &port, addr);
+
+ pa = gtphub_addr_find(bind, &gsna);
+ if (!pa)
+ return NULL;
+
+ pp = gtphub_addr_find_port(pa, port);
+
+ if (!pp)
+ pp = gtphub_addr_add_port(pa, port);
+
+ return pp;
+}
+
+
/* Return 0 if the message in p is not applicable for GGSN resolution, -1 if
* resolution should be possible but failed, and 1 if resolution was
* successful. *pp will be set to NULL if <1 is returned. */