This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Neels Hofmeyr nhofmeyr at sysmocom.deSponsored-by: On-Waves ehi diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index ffe0d4a..97e52a6 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 from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what) +{ + unsigned int port_idx = from_ggsns_ofd->priv_nr; + OSMO_ASSERT(port_idx < GTPH_PORT_N); + LOG("reading from GGSN (%s)\n", gtphub_port_idx_names[port_idx]); + if (!(what & BSC_FD_READ)) + return 0; + + struct gtphub *hub = from_ggsns_ofd->data; + + /* TODO this will not be hardcoded. */ + struct gtphub_peer *sgsn = llist_first(&hub->to_sgsns[port_idx].peers, + struct gtphub_peer, entry); + if (!sgsn) { + LOGERR("no sgsn"); + return 0; + } + + return gtp_relay(from_ggsns_ofd, NULL, NULL, + &hub->to_sgsns[port_idx].ofd, + &sgsn->addr.a, sgsn->addr.l); +} + +int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what) +{ + unsigned int port_idx = from_sgsns_ofd->priv_nr; + OSMO_ASSERT(port_idx < GTPH_PORT_N); + LOG("reading from SGSN (%s)\n", gtphub_port_idx_names[port_idx]); + + if (!(what & BSC_FD_READ)) + return 0; + + struct gtphub *hub = from_sgsns_ofd->data; + + /* TODO this will not be hardcoded. */ + struct gtphub_peer *ggsn = llist_first(&hub->to_ggsns[port_idx].peers, + struct gtphub_peer, entry); + if (!ggsn) { + LOGERR("no ggsn to send to\n"); + return 0; + } + + /* so far just remembering the last sgsn */ + struct gtphub_peer *sgsn = llist_first(&hub->to_sgsns[port_idx].peers, + struct gtphub_peer, entry); + if (!sgsn) + sgsn = gtphub_peer_new(&hub->to_sgsns[port_idx]); + + return gtp_relay(from_sgsns_ofd, &sgsn->addr.a, &sgsn->addr.l, + &hub->to_ggsns[port_idx].ofd, + &ggsn->addr.a, ggsn->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_ggsns[port_id], + &cfg->to_ggsns[port_id], + from_ggsns_read_cb, hub, port_id); + if (rc < 0) + return rc; + + rc = gtphub_gtp_bind_init(&hub->to_sgsns[port_id], + &cfg->to_sgsns[port_id], + from_sgsns_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 f225efc..b43e28d 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) @@ -113,7 +103,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 <info at sysmocom.de>\r\n" @@ -142,139 +131,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 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) -{ - LOG("reading from clients socket\n"); - struct osmo_fd *server_ofd = clients_ofd->data; - - 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; - - if (!(what & BSC_FD_READ)) - return 0; - - return gtp_relay(server_ofd, NULL, NULL, - clients_ofd, &last_client_addr, last_client_addr_len); + struct gtphub_cfg_addr *a; + a = &cfg->to_sgsns[GTPH_PORT_CONTROL].bind; + LOG("to-SGSNs bind, Control: %s port %d\n", + a->addr_str, a->port); + a = &cfg->to_sgsns[GTPH_PORT_USER].bind; + LOG("to-SGSNs bind, User: %s port %d\n", + a->addr_str, a->port); + a = &cfg->to_ggsns[GTPH_PORT_CONTROL].bind; + LOG("to-GGSNs bind, Control: %s port %d\n", + a->addr_str, a->port); + a = &cfg->to_ggsns[GTPH_PORT_USER].bind; + LOG("to-GGSNs bind, User: %s port %d\n", + a->addr_str, a->port); } int main(int argc, char **argv) { + osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub"); + osmo_init_logging(>phub_log_info); int rc; - const char* clients_addr_str = "localhost"; - uint16_t clients_port = 3386; - - const char* server_addr_str = "localhost"; - uint16_t server_port = 1234; - - /* Which local interface to use to listen for the GTP server's - * responses */ - const char* server_rx_addr_str = "localhost"; - uint16_t server_rx_port = 4321; - - rc = osmo_sockaddr_init(&server_addr, &server_addr_len, - 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; + struct gtphub_cfg _cfg = { + .to_sgsns = { + { .bind = { + .addr_str = "127.0.0.3", + .port = 2123, + } }, + { .bind = { + .addr_str = "127.0.0.3", + .port = 2152, + } }, + }, + .to_ggsns = { + { .bind = { + .addr_str = "127.0.0.4", + .port = 2123, + } }, + { .bind = { + .addr_str = "127.0.0.4", + .port = 2152, + } }, + }, + }; - memset(&clients_ofd, 0, sizeof(clients_ofd)); - clients_ofd.when = BSC_FD_READ; - clients_ofd.cb = clients_read_cb; - clients_ofd.data = &server_ofd; + struct gtphub_cfg *cfg = &_cfg; - 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); - } + struct gtphub _hub; + struct gtphub *hub = &_hub; - memset(&server_ofd, 0, sizeof(server_ofd)); - server_ofd.when = BSC_FD_READ; - server_ofd.cb = server_read_cb; - server_ofd.data = &clients_ofd; + if (gtphub_init(hub, cfg) != 0) + return -1; - 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); + /* TODO this will not be configured, gtphub will have to find the + * ggsns from incoming GTP PDUs. */ + /* Where the GTP ggsn sits that we're relaying for */ + const char* ggsn_addr_str = "127.0.0.2"; + uint16_t ggsn_port = 2123; + struct gtphub_peer *test_ggsn = gtphub_peer_new(&hub->to_ggsns[GTPH_PORT_CONTROL]); + rc = osmo_sockaddr_init(&test_ggsn->addr.a, &test_ggsn->addr.l, + AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, + ggsn_addr_str, ggsn_port); + if (rc != 0) { + LOGERR("Cannot resolve '%s port %d'\n", ggsn_addr_str, ggsn_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