blob: 09ba52e5dbc38207b126ef20535b43293bcc1bba [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0 */
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include <sys/socket.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/utils.h>
struct nl_sock;
struct osmo_stream_srv_link;
/***********************************************************************
* Utility
***********************************************************************/
/* ensure we are called from main thread context */
#define ASSERT_MAIN_THREAD(d) OSMO_ASSERT(pthread_self() == (d)->main_thread)
#define MAX_UDP_PACKET 65535
bool sockaddr_equals(const struct sockaddr *a, const struct sockaddr *b);
struct addrinfo *addrinfo_helper(uint16_t family, uint16_t type, uint8_t proto,
const char *host, uint16_t port, bool passive);
enum {
DTUN,
DEP,
DGT,
DUECUPS,
};
/***********************************************************************
* netdev / netlink
***********************************************************************/
int netdev_add_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss);
int netdev_del_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss);
int netdev_set_link(struct nl_sock *nlsk, int ifindex, bool up);
int netdev_add_defaultroute(struct nl_sock *nlsk, int ifindex, uint8_t family);
/***********************************************************************
* GTP Endpoint (UDP socket)
***********************************************************************/
struct gtp_daemon;
/* local UDP socket for GTP communication */
struct gtp_endpoint {
/* entry in global list */
struct llist_head list;
/* back-pointer to daemon */
struct gtp_daemon *d;
unsigned long use_count;
/* file descriptor */
int fd;
/* local IP:port */
struct sockaddr_storage bind_addr;
char *name;
/* the thread handling Rx from the fd/socket */
pthread_t thread;
};
struct gtp_endpoint *
gtp_endpoint_find_or_create(struct gtp_daemon *d, const struct sockaddr_storage *bind_addr);
struct gtp_endpoint *
_gtp_endpoint_find(struct gtp_daemon *d, const struct sockaddr_storage *bind_addr);
void _gtp_endpoint_deref_destroy(struct gtp_endpoint *ep);
bool _gtp_endpoint_release(struct gtp_endpoint *ep);
bool gtp_endpoint_release(struct gtp_endpoint *ep);
/***********************************************************************
* TUN Device
***********************************************************************/
struct tun_device {
/* entry in global list */
struct llist_head list;
/* back-pointer to daemon */
struct gtp_daemon *d;
unsigned long use_count;
/* which device we refer to */
const char *devname;
int ifindex;
/* file descriptor */
int fd;
/* network namespace */
const char *netns_name;
int netns_fd;
/* netlink socket in the namespace of the tun device */
struct nl_sock *nl;
/* list of local addresses? or simply only have the kernel know thses? */
/* the thread handling Rx from the tun fd */
pthread_t thread;
};
struct tun_device *
tun_device_find_or_create(struct gtp_daemon *d, const char *devname, const char *netns_name);
struct tun_device *
tun_device_find_netns(struct gtp_daemon *d, const char *netns_name);
struct tun_device *
_tun_device_find(struct gtp_daemon *d, const char *devname);
void _tun_device_deref_destroy(struct tun_device *tun);
bool _tun_device_release(struct tun_device *tun);
bool tun_device_release(struct tun_device *tun);
/***********************************************************************
* GTP Tunnel
***********************************************************************/
/* Every tunnel is identified uniquely by the following tuples:
*
* a) local endpoint + TEID
* this is what happens on incoming GTP messages
*
* b) tun device + end-user-address (+ filter, if any)
* this is what happens when IP arrives on the tun device
*/
struct gtp_tunnel {
/* entry in global list / hash table */
struct llist_head list;
/* back-pointer to daemon */
struct gtp_daemon *d;
const char *name;
/* the TUN device associated with this tunnel */
struct tun_device *tun_dev;
/* the GTP endpoint (UDP socket) associated with this tunnel */
struct gtp_endpoint *gtp_ep;
/* TEID on transmit (host byte order) */
uint32_t tx_teid;
/* TEID one receive (host byte order) */
uint32_t rx_teid;
/* End user Address (inner IP) */
struct sockaddr_storage user_addr;
/* Remote UDP IP/Port*/
struct sockaddr_storage remote_udp;
/* TODO: Filter */
};
struct gtp_tunnel *
_gtp_tunnel_find_r(struct gtp_daemon *d, uint32_t rx_teid, struct gtp_endpoint *ep);
struct gtp_tunnel *
_gtp_tunnel_find_eua(struct tun_device *tun, const struct sockaddr *sa, uint8_t proto);
struct gtp_tunnel_params {
/* TEID in receive and transmit direction */
uint32_t rx_teid;
uint32_t tx_teid;
/* end user address */
struct sockaddr_storage user_addr;
/* remote GTP/UDP IP+Port */
struct sockaddr_storage remote_udp;
/* local GTP/UDP IP+Port (used to lookup/create local EP) */
struct sockaddr_storage local_udp;
/* local TUN device name (used to lookup/create local tun) */
const char *tun_name;
const char *tun_netns_name;
};
struct gtp_tunnel *gtp_tunnel_alloc(struct gtp_daemon *d, const struct gtp_tunnel_params *cpars);
void _gtp_tunnel_destroy(struct gtp_tunnel *t);
bool gtp_tunnel_destroy(struct gtp_daemon *d, const struct sockaddr_storage *bind_addr, uint32_t rx_teid);
/***********************************************************************
* GTP Daemon
***********************************************************************/
#define UECUPS_SCTP_PORT 4268
struct osmo_signalfd;
struct gtp_daemon {
/* global lists of various objects */
struct llist_head gtp_endpoints;
struct llist_head tun_devices;
struct llist_head gtp_tunnels;
struct llist_head subprocesses;
/* lock protecting all of the above lists */
pthread_rwlock_t rwlock;
/* main thread ID */
pthread_t main_thread;
/* client CUPS interface */
struct llist_head cups_clients;
struct osmo_stream_srv_link *cups_link;
struct osmo_signalfd *signalfd;
struct {
char *cups_local_ip;
uint16_t cups_local_port;
} cfg;
};
extern struct gtp_daemon *g_daemon;
int gtpud_vty_init(void);