/* SPDX-License-Identifier: GPL-2.0 */ #pragma once #include #include #include #include #include #include #include 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);