diff options
author | Sebastian Stumpf <sebastian.stumpf87@googlemail.com> | 2017-02-06 14:14:31 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2017-07-12 23:26:26 +0200 |
commit | 2e265c897a7a1d099c08807f0587dfbfc83f260d (patch) | |
tree | ee09836ac1fd18fb1c35279195a0fe1f570e6f4b /src/host/virt_phy/src/shared | |
parent | fa2ce6396fae18ded5bb9620b4ab761ab417c4ba (diff) |
VIRT-PHY: Cleanup dirs, makefile, dependencies and formatting code.
Change-Id: Ibd68a03bcc439c262ba513782936c6b62937eaaa
Diffstat (limited to 'src/host/virt_phy/src/shared')
-rw-r--r-- | src/host/virt_phy/src/shared/osmo_mcast_sock.c | 191 | ||||
-rw-r--r-- | src/host/virt_phy/src/shared/virtual_um.c | 103 |
2 files changed, 294 insertions, 0 deletions
diff --git a/src/host/virt_phy/src/shared/osmo_mcast_sock.c b/src/host/virt_phy/src/shared/osmo_mcast_sock.c new file mode 100644 index 00000000..acc6bcb1 --- /dev/null +++ b/src/host/virt_phy/src/shared/osmo_mcast_sock.c @@ -0,0 +1,191 @@ +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/select.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <talloc.h> +#include <unistd.h> +#include <virtphy/osmo_mcast_sock.h> + +struct mcast_server_sock *mcast_server_sock_setup(void *ctx, + char* tx_mcast_group, + int tx_mcast_port, + int loopback) +{ + struct mcast_server_sock *serv_sock = talloc_zero(ctx, + struct mcast_server_sock); + + serv_sock->osmo_fd = talloc_zero(ctx, struct osmo_fd); + serv_sock->sock_conf = talloc_zero(ctx, struct sockaddr_in); + + // setup mcast server socket + serv_sock->osmo_fd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (serv_sock->osmo_fd->fd == -1) { + perror("Failed to create Multicast Server Socket"); + return NULL; + } + + serv_sock->sock_conf->sin_family = AF_INET; + serv_sock->sock_conf->sin_addr.s_addr = inet_addr(tx_mcast_group); + serv_sock->sock_conf->sin_port = htons(tx_mcast_port); + + // determines whether sent mcast packets should be looped back to the local sockets. + // loopback must be enabled if the mcast client is on the same machine + if (setsockopt(serv_sock->osmo_fd->fd, IPPROTO_IP, + IP_MULTICAST_LOOP, &loopback, sizeof(loopback)) < 0) { + perror("Failed to disable loopback.\n"); + return NULL; + } + + return serv_sock; +} + +struct mcast_client_sock *mcast_client_sock_setup( + void *ctx, char* mcast_group, int mcast_port, + int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what), + void *osmo_fd_data) +{ + struct mcast_client_sock *client_sock = talloc_zero(ctx, + struct mcast_client_sock); + struct sockaddr_in *rx_sock_conf = talloc_zero(NULL, + struct sockaddr_in); + int rc, reuseaddr = 1, loopback = 1; + + client_sock->osmo_fd = talloc_zero(ctx, struct osmo_fd); + client_sock->mcast_group = talloc_zero(ctx, struct ip_mreq); + + // Create mcast client socket + client_sock->osmo_fd->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (client_sock->osmo_fd->fd == -1) { + perror("Could not create mcast client socket"); + return NULL; + } + + // Enable SO_REUSEADDR to allow multiple instances of this application to receive copies of the multicast datagrams. + rc = setsockopt(client_sock->osmo_fd->fd, + SOL_SOCKET, + SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); + if (rc < 0) { + perror("Failed to configure REUSEADDR option"); + return NULL; + } + + // Bind to the proper port number with the IP address specified as INADDR_ANY. + rx_sock_conf->sin_family = AF_INET; + rx_sock_conf->sin_addr.s_addr = htonl(INADDR_ANY); + rx_sock_conf->sin_port = htons(mcast_port); + rc = bind(client_sock->osmo_fd->fd, (struct sockaddr *)rx_sock_conf, + sizeof(*rx_sock_conf)); + talloc_free(rx_sock_conf); + if (rc < 0) { + perror("Could not bind mcast client socket"); + return NULL; + } + + // Enable loopback of msgs to the host. + // Loopback must be enabled for the client, so multiple processes are able to recevie a mcast package. + rc = setsockopt(client_sock->osmo_fd->fd, + IPPROTO_IP, + IP_MULTICAST_LOOP, &loopback, sizeof(loopback)); + if (rc < 0) { + perror("Failed to enable IP_MULTICAST_LOOP"); + return NULL; + } + + // Configure and join the multicast group + client_sock->mcast_group->imr_multiaddr.s_addr = inet_addr(mcast_group); + client_sock->mcast_group->imr_interface.s_addr = htonl(INADDR_ANY); + rc = setsockopt(client_sock->osmo_fd->fd, + IPPROTO_IP, + IP_ADD_MEMBERSHIP, client_sock->mcast_group, + sizeof(*client_sock->mcast_group)); + if (rc < 0) { + perror("Failed to join to mcast goup"); + return NULL; + } + + // configure and register the osmocom filedescriptor + client_sock->osmo_fd->cb = fd_rx_cb; + client_sock->osmo_fd->when = BSC_FD_READ; + client_sock->osmo_fd->data = osmo_fd_data; + + osmo_fd_register(client_sock->osmo_fd); + + return client_sock; +} + +struct mcast_bidir_sock *mcast_bidir_sock_setup( + void *ctx, char* tx_mcast_group, int tx_mcast_port, + char* rx_mcast_group, int rx_mcast_port, int loopback, + int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what), + void *osmo_fd_data) +{ + struct mcast_bidir_sock *bidir_sock = talloc(ctx, + struct mcast_bidir_sock); + bidir_sock->rx_sock = mcast_client_sock_setup(ctx, rx_mcast_group, + rx_mcast_port, fd_rx_cb, osmo_fd_data); + bidir_sock->tx_sock = mcast_server_sock_setup(ctx, tx_mcast_group, + tx_mcast_port, loopback); + if (!bidir_sock->rx_sock || !bidir_sock->tx_sock) { + return NULL; + } + return bidir_sock; + +} + +int mcast_client_sock_rx(struct mcast_client_sock *client_sock, void* buf, + int buf_len) +{ + return recv(client_sock->osmo_fd->fd, buf, buf_len, 0); +} + +int mcast_server_sock_tx(struct mcast_server_sock *serv_sock, void* data, + int data_len) +{ + return sendto(serv_sock->osmo_fd->fd, data, data_len, 0, + (struct sockaddr *)serv_sock->sock_conf, + sizeof(*serv_sock->sock_conf)); +} + +int mcast_bidir_sock_tx(struct mcast_bidir_sock *bidir_sock, void* data, + int data_len) +{ + return mcast_server_sock_tx(bidir_sock->tx_sock, data, data_len); +} +int mcast_bidir_sock_rx(struct mcast_bidir_sock *bidir_sock, void* buf, + int buf_len) +{ + return mcast_client_sock_rx(bidir_sock->rx_sock, buf, buf_len); +} + +void mcast_client_sock_close(struct mcast_client_sock *client_sock) +{ + setsockopt(client_sock->osmo_fd->fd, + IPPROTO_IP, + IP_DROP_MEMBERSHIP, client_sock->mcast_group, + sizeof(*client_sock->mcast_group)); + osmo_fd_unregister(client_sock->osmo_fd); + client_sock->osmo_fd->fd = -1; + client_sock->osmo_fd->when = 0; + close(client_sock->osmo_fd->fd); + talloc_free(client_sock->mcast_group); + talloc_free(client_sock->osmo_fd); + talloc_free(client_sock); + +} +void mcast_server_sock_close(struct mcast_server_sock *serv_sock) +{ + close(serv_sock->osmo_fd->fd); + talloc_free(serv_sock->sock_conf); + talloc_free(serv_sock); +} + +void mcast_bidir_sock_close(struct mcast_bidir_sock *bidir_sock) +{ + mcast_client_sock_close(bidir_sock->rx_sock); + mcast_server_sock_close(bidir_sock->tx_sock); + talloc_free(bidir_sock); +} diff --git a/src/host/virt_phy/src/shared/virtual_um.c b/src/host/virt_phy/src/shared/virtual_um.c new file mode 100644 index 00000000..9415bfbb --- /dev/null +++ b/src/host/virt_phy/src/shared/virtual_um.c @@ -0,0 +1,103 @@ +/* Routines for a Virtual Um interface over GSMTAP/UDP */ + +/* (C) 2015 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <osmocom/core/select.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/gsmtap.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/talloc.h> +#include <virtphy/osmo_mcast_sock.h> +#include <virtphy/virtual_um.h> +#include <unistd.h> + +/** + * Virtual UM interface file descriptor callback. + * Should be called by select.c when the fd is ready for reading. + */ +static int virt_um_fd_cb(struct osmo_fd *ofd, unsigned int what) +{ + struct virt_um_inst *vui = ofd->data; + + // check if the read flag is set + if (what & BSC_FD_READ) { + // allocate message buffer of specified size + struct msgb *msg = msgb_alloc(VIRT_UM_MSGB_SIZE, + "Virtual UM Rx"); + int rc; + + // read message from fd in message buffer + rc = mcast_bidir_sock_rx(vui->mcast_sock, msgb_data(msg), + msgb_tailroom(msg)); + // rc is number of bytes actually read + if (rc > 0) { + msgb_put(msg, rc); + msg->l1h = msgb_data(msg); + // call the l1 callback function for a received msg + vui->recv_cb(vui, msg); + } else { + // TODO: this kind of error handling might be a bit harsh + vui->recv_cb(vui, NULL); + // Unregister fd from select loop + osmo_fd_unregister(ofd); + close(ofd->fd); + ofd->fd = -1; + ofd->when = 0; + } + } + + return 0; +} + +struct virt_um_inst *virt_um_init( + void *ctx, char *tx_mcast_group, uint16_t tx_mcast_port, + char *rx_mcast_group, uint16_t rx_mcast_port, + void (*recv_cb)(struct virt_um_inst *vui, struct msgb *msg)) +{ + struct virt_um_inst *vui = talloc_zero(ctx, struct virt_um_inst); + vui->mcast_sock = mcast_bidir_sock_setup(ctx, tx_mcast_group, + tx_mcast_port, rx_mcast_group, rx_mcast_port, 1, + virt_um_fd_cb, vui); + vui->recv_cb = recv_cb; + + return vui; + +} + +void virt_um_destroy(struct virt_um_inst *vui) +{ + mcast_bidir_sock_close(vui->mcast_sock); + talloc_free(vui); +} + +/** + * Write msg to to multicast socket and free msg afterwards + */ +int virt_um_write_msg(struct virt_um_inst *vui, struct msgb *msg) +{ + int rc; + + rc = mcast_bidir_sock_tx(vui->mcast_sock, msgb_data(msg), + msgb_length(msg)); + msgb_free(msg); + + return rc; +} |