Sponsored-by: On-Waves ehi
---
 openbsc/src/gprs/gtphub.c      | 209 ++++++++++++++++++++++++++++++++++++++++-
 openbsc/src/gprs/gtphub_main.c | 183 +++++++++++-------------------------
 2 files changed, 261 insertions(+), 131 deletions(-)

diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index ffe0d4a..a8bd276 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -20,26 +20,231 @@
  */

 #include <string.h>
+#include <errno.h>
+#include <netinet/in.h>

 #include <openbsc/gtphub.h>
 #include <openbsc/debug.h>

 #include <osmocom/core/utils.h>
 #include <osmocom/core/logging.h>
+#include <osmocom/core/socket.h>

 void *osmo_gtphub_ctx;

 #define LOGERR(fmt, args...) \
        LOGP(DGTPHUB, LOGL_ERROR, fmt, ##args)

+#define LOG(fmt, args...) \
+       LOGP(DGTPHUB, LOGL_NOTICE, fmt, ##args)
+
+/* TODO move this to osmocom/core/select.h ? */
+typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what);
+
+/* TODO move this to osmocom/core/linuxlist.h ? */
+#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
+#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, 
entry)
+
+
+/* general */
+
+const char* const gtphub_port_idx_names[GTPH_PORT_N] = {
+       "CTRL",
+       "USER",
+};
+
+
+/* gtphub */
+
 void gtphub_zero(struct gtphub *hub)
 {
        memset(hub, '\0', sizeof(*hub));
 }

+static int gtphub_sock_init(struct osmo_fd *ofd,
+                           const struct gtphub_cfg_addr *addr,
+                           osmo_fd_cb_t cb,
+                           void *data,
+                           int ofd_id)
+{
+       ofd->when = BSC_FD_READ;
+       ofd->cb = cb;
+       ofd->data = data;
+       ofd->priv_nr = ofd_id;
+
+       int rc;
+       rc = osmo_sock_init_ofd(ofd,
+                               AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
+                               addr->addr_str, addr->port,
+                               OSMO_SOCK_F_BIND);
+       if (rc < 1) {
+               LOGERR("Cannot bind to %s port %d (rc %d)\n",
+                      addr->addr_str, (int)addr->port, rc);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int gtphub_gtp_bind_init(struct gtphub_bind *b,
+                               const struct gtphub_cfg_bind *cfg,
+                               osmo_fd_cb_t cb, void *cb_data,
+                               unsigned int ofd_id)
+{
+       memset(b, '\0', sizeof(*b));
+
+       INIT_LLIST_HEAD(&b->peers);
+
+       if (gtphub_sock_init(&b->ofd, &cfg->bind, cb, cb_data, ofd_id) != 0)
+               return -1;
+       return 0;
+}
+
+/* Recv datagram from from->fd, optionally write sender's address to *from_addr
+ * and *from_addr_len, parse datagram as GTP, and forward on to to->fd using
+ * *to_addr. to_addr may be NULL, if an address is set on to->fd. */
+static int gtp_relay(struct osmo_fd *from,
+                    struct sockaddr_storage *from_addr,
+                    socklen_t *from_addr_len,
+                    struct osmo_fd *to,
+                    struct sockaddr_storage *to_addr,
+                    socklen_t to_addr_len)
+{
+       static uint8_t buf[4096];
+
+       /* recvfrom requires the available length to be set in *from_addr_len. 
*/
+       if (from_addr_len && from_addr)
+               *from_addr_len = sizeof(*from_addr);
+
+       errno = 0;
+       ssize_t received = recvfrom(from->fd, buf, sizeof(buf), 0,
+                                   (struct sockaddr*)from_addr, from_addr_len);
+
+       if (received <= 0) {
+               if (errno != EAGAIN)
+                       LOGERR("error: %s\n", strerror(errno));
+               return -errno;
+       }
+
+       if (from_addr) {
+               LOG("from %s\n", osmo_hexdump((uint8_t*)from_addr, 
*from_addr_len));
+       }
+
+       if (received <= 0) {
+               LOGERR("error: %s\n", strerror(errno));
+               return -EINVAL;
+       }
+
+       /* insert magic here */
+
+       errno = 0;
+       ssize_t sent = sendto(to->fd, buf, received, 0,
+                             (struct sockaddr*)to_addr, to_addr_len);
+
+       if (to_addr) {
+               LOG("to %s\n", osmo_hexdump((uint8_t*)to_addr, to_addr_len));
+       }
+
+       if (sent == -1) {
+               LOGERR("error: %s\n", strerror(errno));
+               return -EINVAL;
+       }
+
+       if (sent != received)
+               LOGERR("sent(%d) != received(%d)\n", (int)sent, (int)received);
+       else
+               LOG("%d b ok\n", (int)sent);
+
+       return 0;
+}
+
+int servers_read_cb(struct osmo_fd *servers_ofd, unsigned int what)
+{
+       unsigned int port_idx = servers_ofd->priv_nr;
+       OSMO_ASSERT(port_idx < GTPH_PORT_N);
+       LOG("reading from servers socket (%s)\n", 
gtphub_port_idx_names[port_idx]);
+       if (!(what & BSC_FD_READ))
+               return 0;
+
+       struct gtphub *hub = servers_ofd->data;
+
+       /* TODO this will not be hardcoded. */
+       struct gtphub_peer *client = 
llist_first(&hub->to_clients[port_idx].peers,
+                                                struct gtphub_peer, entry);
+       if (!client) {
+               LOGERR("no client");
+               return 0;
+       }
+
+       return gtp_relay(servers_ofd, NULL, NULL,
+                        &hub->to_clients[port_idx].ofd,
+                        &client->addr.a, client->addr.l);
+}
+
+int clients_read_cb(struct osmo_fd *clients_ofd, unsigned int what)
+{
+       unsigned int port_idx = clients_ofd->priv_nr;
+       OSMO_ASSERT(port_idx < GTPH_PORT_N);
+       LOG("reading from clients socket (%s)\n", 
gtphub_port_idx_names[port_idx]);
+
+       if (!(what & BSC_FD_READ))
+               return 0;
+
+       struct gtphub *hub = clients_ofd->data;
+
+       /* TODO this will not be hardcoded. */
+       /* so far just remembering the last client */
+       struct gtphub_peer *server = 
llist_first(&hub->to_servers[port_idx].peers,
+                                                struct gtphub_peer, entry);
+       if (!server) {
+               LOGERR("no server to send to\n");
+               return 0;
+       }
+
+       struct gtphub_peer *client = 
llist_first(&hub->to_clients[port_idx].peers,
+                                                struct gtphub_peer, entry);
+       if (!client)
+               client = gtphub_peer_new(&hub->to_clients[port_idx]);
+
+       return gtp_relay(clients_ofd, &client->addr.a, &client->addr.l,
+                        &hub->to_servers[port_idx].ofd,
+                        &server->addr.a, server->addr.l);
+}
+
 int gtphub_init(struct gtphub *hub, struct gtphub_cfg *cfg)
 {
-       LOGERR("%s not implemented\n", __func__);
-       return -1;
+       gtphub_zero(hub);
+
+       int port_id;
+       for (port_id = 0; port_id < GTPH_PORT_N; port_id++) {
+               int rc;
+               rc = gtphub_gtp_bind_init(&hub->to_servers[port_id],
+                                         &cfg->to_servers[port_id],
+                                         servers_read_cb, hub, port_id);
+               if (rc < 0)
+                       return rc;
+
+               rc = gtphub_gtp_bind_init(&hub->to_clients[port_id],
+                                         &cfg->to_clients[port_id],
+                                         clients_read_cb, hub, port_id);
+               if (rc < 0)
+                       return rc;
+
+               /* ... */
+       }
+       return 0;
+}
+
+struct gtphub_peer *gtphub_peer_new(struct gtphub_bind *bind)
+{
+       struct gtphub_peer *n = talloc_zero(osmo_gtphub_ctx, struct 
gtphub_peer);
+       llist_add(&n->entry, &bind->peers);
+       return n;
+}
+
+void gtphub_peer_del(struct gtphub_peer *peer)
+{
+       llist_del(&peer->entry);
+       talloc_free(peer);
 }

diff --git a/openbsc/src/gprs/gtphub_main.c b/openbsc/src/gprs/gtphub_main.c
index f8bcd59..104cbfd 100644
--- a/openbsc/src/gprs/gtphub_main.c
+++ b/openbsc/src/gprs/gtphub_main.c
@@ -20,27 +20,17 @@
  */

 #include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <errno.h>

-#include <sys/socket.h>
-#include <netinet/in.h>
-
 #define _GNU_SOURCE
 #include <getopt.h>

 #include <osmocom/core/application.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/socket.h>
-#include <osmocom/core/select.h>
 #include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>

 #include <openbsc/debug.h>
-
-#include <gtp.h>
-
-#include <unistd.h>
+#include <openbsc/gtphub.h>

 #define LOGERR(fmt, args...) \
        LOGP(DGTPHUB, LOGL_ERROR, fmt, ##args)
@@ -112,7 +102,6 @@ int osmo_sockaddr_init(struct sockaddr_storage *addr, 
socklen_t *addr_len,
 }


-void *tall_bsc_ctx;

 const char *gtphub_copyright =
        "Copyright (C) 2015 sysmocom s.m.f.c GmbH <[email protected]>\r\n"
@@ -141,141 +130,77 @@ static const struct log_info gtphub_log_info = {
        .num_cat = ARRAY_SIZE(gtphub_categories),
 };

-/* Recv datagram from from->fd, optionally write sender's address to *from_addr
- * and *from_addr_len, parse datagram as GTP, and forward on to to->fd using
- * *to_addr. to_addr may be NULL, if an address is set on to->fd. */
-int gtp_relay(struct osmo_fd *from, struct sockaddr_storage *from_addr, 
socklen_t *from_addr_len,
-             struct osmo_fd *to, struct sockaddr_storage *to_addr, socklen_t 
to_addr_len)
+void log_cfg(struct gtphub_cfg *cfg)
 {
-       static uint8_t buf[4096];
-
-       errno = 0;
-       ssize_t received = recvfrom(from->fd, buf, sizeof(buf), 0,
-                                   (struct sockaddr*)from_addr, from_addr_len);
-
-       if (received <= 0) {
-               if (errno != EAGAIN)
-                       LOGERR("error: %s\n", strerror(errno));
-               return -errno;
-       }
-
-       if (from_addr) {
-               LOG("from %s\n", osmo_hexdump((uint8_t*)from_addr, 
*from_addr_len));
-       }
-
-       if (received <= 0) {
-               LOGERR("error: %s\n", strerror(errno));
-               return -EINVAL;
-       }
-
-       /* insert magic here */
-
-       errno = 0;
-       ssize_t sent = sendto(to->fd, buf, received, 0,
-                             (struct sockaddr*)to_addr, to_addr_len);
-
-       if (to_addr) {
-               LOG("to %s\n", osmo_hexdump((uint8_t*)to_addr, to_addr_len));
-       }
-
-       if (sent == -1) {
-               LOGERR("error: %s\n", strerror(errno));
-               return -EINVAL;
-       }
-
-       if (sent != received)
-               LOGERR("sent(%d) != received(%d)\n", (int)sent, (int)received);
-       else
-               LOG("%d b ok\n", (int)sent);
-
-       return 0;
+       struct gtphub_cfg_addr *a;
+       a = &cfg->to_clients[GTPH_PORT_CONTROL].bind;
+       LOG("Clients bind, Control:    %s port %d\n",
+           a->addr_str, a->port);
+       a = &cfg->to_clients[GTPH_PORT_USER].bind;
+       LOG("Clients bind, User:       %s port %d\n",
+           a->addr_str, a->port);
+       a = &cfg->to_servers[GTPH_PORT_CONTROL].bind;
+       LOG("GTP server bind, Control: %s port %d\n",
+           a->addr_str, a->port);
+       a = &cfg->to_servers[GTPH_PORT_USER].bind;
+       LOG("GTP server bind, User:    %s port %d\n",
+           a->addr_str, a->port);
 }

-struct sockaddr_storage last_client_addr;
-socklen_t last_client_addr_len;
-struct sockaddr_storage server_addr;
-socklen_t server_addr_len;
-
-int clients_read_cb(struct osmo_fd *clients_ofd, unsigned int what)
+int main(int argc, char **argv)
 {
-       LOG("reading from clients socket\n");
-       struct osmo_fd *server_ofd = clients_ofd->data;
+       osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub");

-       if (!(what & BSC_FD_READ))
-               return 0;
-
-       last_client_addr_len = sizeof(last_client_addr);
-       return gtp_relay(clients_ofd, &last_client_addr, &last_client_addr_len,
-                        server_ofd, &server_addr, server_addr_len);
-}
-
-int server_read_cb(struct osmo_fd *server_ofd, unsigned int what)
-{
-       LOG("reading from server socket\n");
-       struct osmo_fd *clients_ofd = server_ofd->data;
+       osmo_init_logging(&gtphub_log_info);

-       if (!(what & BSC_FD_READ))
-               return 0;
+       int rc;

-       return gtp_relay(server_ofd, NULL, NULL,
-                        clients_ofd, &last_client_addr, last_client_addr_len);
-}
+       struct gtphub_cfg _cfg = {
+       .to_clients = {
+               { .bind = {
+                               .addr_str = "127.0.0.3",
+                               .port = 2123,
+                         } },
+               { .bind = {
+                               .addr_str = "127.0.0.3",
+                               .port = 2152,
+                         } },
+       },
+       .to_servers = {
+               { .bind = {
+                               .addr_str = "127.0.0.4",
+                               .port = 2123,
+                         } },
+               { .bind = {
+                               .addr_str = "127.0.0.4",
+                               .port = 2152,
+                         } },
+       },
+       };

-int main(int argc, char **argv)
-{
-       osmo_init_logging(&gtphub_log_info);
+       struct gtphub_cfg *cfg = &_cfg;

-       int rc;
+       struct gtphub _hub;
+       struct gtphub *hub = &_hub;

-       /* Which local interface to use to listen for GTP clients */
-       const char* clients_addr_str = "127.0.0.3";
-       uint16_t clients_port = 2123;
+       if (gtphub_init(hub, cfg) != 0)
+               return -1;

+       /* TODO this will not be configured, gtphub will have to find the
+        * servers from incoming GTP PDUs. */
        /* Where the GTP server sits that we're relaying for */
        const char* server_addr_str = "127.0.0.2";
        uint16_t server_port = 2123;
-
-       /* Which local interface to use to listen for the GTP server's
-        * responses */
-       const char* server_rx_addr_str = "127.0.0.4";
-       uint16_t server_rx_port = 2123;
-
-       rc = osmo_sockaddr_init(&server_addr, &server_addr_len,
-                               AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, 
server_addr_str, server_port);
+       struct gtphub_peer *test_server = 
gtphub_peer_new(&hub->to_servers[GTPH_PORT_CONTROL]);
+       rc = osmo_sockaddr_init(&test_server->addr.a, &test_server->addr.l,
+                               AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
+                               server_addr_str, server_port);
        if (rc != 0) {
                LOGERR("Cannot resolve '%s port %d'\n", server_addr_str, 
server_port);
                exit(-1);
        }

-       struct osmo_fd clients_ofd;
-       struct osmo_fd server_ofd;
-
-       memset(&clients_ofd, 0, sizeof(clients_ofd));
-       clients_ofd.when = BSC_FD_READ;
-       clients_ofd.cb = clients_read_cb;
-       clients_ofd.data = &server_ofd;
-
-       rc = osmo_sock_init_ofd(&clients_ofd, AF_UNSPEC, SOCK_DGRAM, 
IPPROTO_UDP, clients_addr_str, clients_port, OSMO_SOCK_F_BIND);
-       if (rc < 1) {
-               LOGERR("Cannot bind to %s port %d\n", clients_addr_str, 
clients_port);
-               exit(-1);
-       }
-
-       memset(&server_ofd, 0, sizeof(server_ofd));
-       server_ofd.when = BSC_FD_READ;
-       server_ofd.cb = server_read_cb;
-       server_ofd.data = &clients_ofd;
-
-       rc = osmo_sock_init_ofd(&server_ofd, AF_UNSPEC, SOCK_DGRAM, 
IPPROTO_UDP, server_rx_addr_str, server_rx_port, OSMO_SOCK_F_BIND);
-       if (rc < 1) {
-               LOGERR("Cannot bind to %s port %d\n", server_rx_addr_str, 
server_rx_port);
-               exit(-1);
-       }
-
-       LOG("GTP server connection: %s port %d <--> %s port %d\n",
-           server_rx_addr_str, (int)server_rx_port,
-           server_addr_str, (int)server_port);
-       LOG("Listening for clients on %s port %d.\n", clients_addr_str, 
clients_port);
+       log_cfg(cfg);

        int daemonize = 0;

-- 
2.1.4

Reply via email to