From c83cd898ef3c167c370d0c3240f355f192388ec7 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Wed, 11 Nov 2015 14:01:06 +0100 Subject: 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 --- openbsc/src/gprs/gtphub.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'openbsc/src/gprs') 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. */ -- cgit v1.2.3