aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gtphub.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gprs/gtphub.c')
-rw-r--r--openbsc/src/gprs/gtphub.c151
1 files changed, 93 insertions, 58 deletions
diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index 440f00fe3..eae4cf2cf 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -33,11 +33,13 @@
#include <openbsc/gtphub.h>
#include <openbsc/debug.h>
+#include <openbsc/gprs_utils.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/socket.h>
+
#define GTPHUB_DEBUG 1
static const int GTPH_GC_TICK_SECONDS = 1;
@@ -345,13 +347,13 @@ void validate_gtp_header(struct gtp_packet_desc *p)
* The first IEI is reached by passing i = 0.
* imsi must point at allocated space of (at least) 8 bytes.
* Return 1 on success, or 0 if not found. */
-static int get_ie_imsi(union gtpie_member *ie[], uint8_t *imsi, int i)
+static int get_ie_imsi(union gtpie_member *ie[], int i, uint8_t *imsi)
{
return gtpie_gettv0(ie, GTPIE_IMSI, i, imsi, 8) == 0;
}
/* Analogous to get_ie_imsi(). nsapi must point at a single uint8_t. */
-static int get_ie_nsapi(union gtpie_member *ie[], uint8_t *nsapi, int i)
+static int get_ie_nsapi(union gtpie_member *ie[], int i, uint8_t *nsapi)
{
return gtpie_gettv1(ie, GTPIE_NSAPI, i, nsapi) == 0;
}
@@ -379,6 +381,33 @@ static const char *imsi_to_str(uint8_t *imsi)
return str;
}
+static const char *get_ie_imsi_str(union gtpie_member *ie[], int i)
+{
+ uint8_t imsi_buf[8];
+ if (!get_ie_imsi(ie, i, imsi_buf))
+ return NULL;
+ return imsi_to_str(imsi_buf);
+}
+
+static const char *get_ie_apn_str(union gtpie_member *ie[])
+{
+ static char apn_buf[GSM_APN_LENGTH];
+ unsigned int len;
+ if (gtpie_gettlv(ie, GTPIE_APN, 0,
+ &len, apn_buf, sizeof(apn_buf)) != 0)
+ return NULL;
+
+ if (!len)
+ return NULL;
+
+ if (len > (sizeof(apn_buf) - 1))
+ len = sizeof(apn_buf) - 1;
+ apn_buf[len] = '\0';
+
+ return gprs_apn_to_str(apn_buf, (uint8_t*)apn_buf, len);
+}
+
+
/* Validate header, and index information elements. Write decoded packet
* information to *res. res->data will point at the given data buffer. On
* error, p->rc is set <= 0 (see enum gtp_rc). */
@@ -416,15 +445,15 @@ static void gtp_decode(const uint8_t *data, int data_len,
int i;
for (i = 0; i < 10; i++) {
- uint8_t imsi[8];
- if (!get_ie_imsi(res->ie, imsi, i))
+ const char *imsi = get_ie_imsi_str(res->ie, i);
+ if (!imsi)
break;
- LOG("| IMSI %s\n", imsi_to_str(imsi));
+ LOG("| IMSI %s\n", imsi);
}
for (i = 0; i < 10; i++) {
uint8_t nsapi;
- if (!get_ie_nsapi(res->ie, &nsapi, i))
+ if (!get_ie_nsapi(res->ie, i, &nsapi))
break;
LOG("| NSAPI %d\n", (int)nsapi);
}
@@ -481,7 +510,6 @@ int expiry_tick(struct expiry *exq, time_t now)
expiring_item_del(m);
expired ++;
} else {
- LOG("Not expired: %d > %d\n", (int)m->expiry, (int)now);
/* The items are added sorted by expiry. So when we hit
* an unexpired entry, only more unexpired ones will
* follow. */
@@ -654,19 +682,15 @@ static struct gtphub_peer_port *gtphub_resolve_ggsn(struct gtphub *hub,
struct gtp_packet_desc *p);
/* See gtphub_ext.c (wrapped by unit test) */
-int gtphub_resolve_ggsn_addr(struct gtphub *hub,
- struct osmo_sockaddr *result,
- struct gtp_packet_desc *p);
+struct gtphub_peer_port *gtphub_resolve_ggsn_addr(struct gtphub *hub,
+ const char *imsi_str,
+ const char *apn_ni_str);
+int gtphub_ares_init(struct gtphub *hub);
static struct gtphub_peer_port *gtphub_port_find(const struct gtphub_bind *bind,
const struct gsn_addr *addr,
uint16_t port);
-static struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
- struct gtphub_bind *bind,
- const struct gsn_addr *addr,
- uint16_t port);
-
static void gtphub_zero(struct gtphub *hub)
{
ZERO_STRUCT(hub);
@@ -833,7 +857,7 @@ const char *gtphub_peer_str2(struct gtphub_peer *peer)
return gtphub_peer_strb(peer, buf, sizeof(buf));
}
-static const char *gtphub_port_str(struct gtphub_peer_port *port)
+const char *gtphub_port_str(struct gtphub_peer_port *port)
{
static char buf[256];
return gtphub_port_strb(port, buf, sizeof(buf));
@@ -1562,6 +1586,49 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub,
return received;
}
+static void resolved_gssn_del_cb(struct expiring_item *expi)
+{
+ struct gtphub_resolved_ggsn *ggsn;
+ ggsn = container_of(expi, struct gtphub_resolved_ggsn, expiry_entry);
+
+ gtphub_port_ref_count_dec(ggsn->peer);
+ llist_del(&ggsn->entry);
+
+ ggsn->expiry_entry.del_cb = 0;
+ expiring_item_del(&ggsn->expiry_entry);
+
+ talloc_free(ggsn);
+}
+
+void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
+ struct gsn_addr *resolved_addr,
+ time_t now)
+{
+ struct gtphub_peer_port *pp;
+ struct gtphub_resolved_ggsn *ggsn;
+
+ pp = gtphub_port_have(hub, &hub->to_ggsns[GTPH_PLANE_CTRL],
+ resolved_addr, 2123);
+ if (!pp) {
+ LOGERR("Internal: Cannot create/find peer '%s'\n",
+ gsn_addr_to_str(resolved_addr));
+ return;
+ }
+
+ ggsn = talloc_zero(osmo_gtphub_ctx, struct gtphub_resolved_ggsn);
+ OSMO_ASSERT(ggsn);
+
+ ggsn->peer = pp;
+ gtphub_port_ref_count_inc(pp);
+
+ strncpy(ggsn->apn_oi_str, apn_oi_str, sizeof(ggsn->apn_oi_str));
+
+ ggsn->expiry_entry.del_cb = resolved_gssn_del_cb;
+ expiry_add(&hub->expire_tei_maps, &ggsn->expiry_entry, now);
+
+ llist_add(&ggsn->entry, &hub->resolved_ggsns);
+}
+
static int gtphub_gc_peer_port(struct gtphub_peer_port *pp)
{
return pp->ref_count == 0;
@@ -1654,6 +1721,8 @@ void gtphub_init(struct gtphub *hub)
{
gtphub_zero(hub);
+ INIT_LLIST_HEAD(&hub->resolved_ggsns);
+
expiry_init(&hub->expire_seq_maps, GTPH_SEQ_MAPPING_EXPIRY_SECS);
expiry_init(&hub->expire_tei_maps, GTPH_TEI_MAPPING_EXPIRY_MINUTES * 60);
@@ -1693,6 +1762,7 @@ int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg)
int rc;
gtphub_init(hub);
+ gtphub_ares_init(hub);
int plane_idx;
for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
@@ -1882,10 +1952,10 @@ static struct gtphub_peer_port *gtphub_addr_add_port(struct gtphub_peer_addr *a,
return pp;
}
-static struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
- struct gtphub_bind *bind,
- const struct gsn_addr *addr,
- uint16_t port)
+struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
+ struct gtphub_bind *bind,
+ const struct gsn_addr *addr,
+ uint16_t port)
{
struct gtphub_peer_addr *a = gtphub_addr_have(hub, bind, addr);
@@ -1896,47 +1966,12 @@ static struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
return gtphub_addr_add_port(a, port);
}
-/* port_override: <=0: use port from addr; >0: use this number as port. Return
- * NULL if the address cannot be parsed. */
-static struct gtphub_peer_port *gtphub_port_have_sockaddr(struct gtphub *hub,
- struct gtphub_bind *bind,
- const struct osmo_sockaddr *addr,
- int port_override)
-{
- struct gsn_addr gsna;
- uint16_t port;
- if (gsn_addr_from_sockaddr(&gsna, &port, addr) != 0)
- return NULL;
-
- if (port_override > 0)
- port = port_override;
- return gtphub_port_have(hub, bind, &gsna, port);
-}
-
-static struct gtphub_peer_port *gtphub_have_ggsn(struct gtphub *hub,
- struct osmo_sockaddr *addr,
- unsigned int plane_idx,
- int port_override)
-{
- if (port_override == 0)
- port_override = gtphub_plane_idx_default_port[plane_idx];
-
- return gtphub_port_have_sockaddr(hub, &hub->to_ggsns[plane_idx], addr,
- port_override);
-}
-
static struct gtphub_peer_port *gtphub_resolve_ggsn(struct gtphub *hub,
struct gtp_packet_desc *p)
{
- int rc;
-
- struct osmo_sockaddr addr;
-
- rc = gtphub_resolve_ggsn_addr(hub, &addr, p);
- if (rc < 0)
- return NULL;
-
- return gtphub_have_ggsn(hub, &addr, p->plane_idx, -1);
+ return gtphub_resolve_ggsn_addr(hub,
+ get_ie_imsi_str(p->ie, 0),
+ get_ie_apn_str(p->ie));
}