#pragma once #include #include #include #include #include #include #include #include #include #include "../lib/tun.h" #include "../lib/ippool.h" #include "../lib/syserr.h" #include "../lib/in46_addr.h" #include "sgsn.h" #define APN_TYPE_IPv4 0x01 /* v4-only */ #define APN_TYPE_IPv6 0x02 /* v6-only */ #define APN_TYPE_IPv4v6 0x04 /* v4v6 dual-stack */ /* See 3GPP TS 23.060 Annex C: */ #define ETHERNET_MTU 1500 /* The maximum sane MTU over GTP-U somebody may wish to configure. * IPv6 min hdr size is 40, so we pick IPv4 one since it's less, for somebody * who may want to run IP4/UDP/GTPU: */ #define IPV4_HDR_MIN_SIZE 20 #define UDP_HDR_MIN_SIZE 8 #define GTPU_HDR_MIN_SIZE 8 #define MAX_POSSIBLE_APN_MTU ((ETHERNET_MTU) - (GTPU_HDR_MIN_SIZE) - (UDP_HDR_MIN_SIZE) - (IPV4_HDR_MIN_SIZE)) /* MAX_POSSIBLE_APN_MTU = 1500 - 8 - 8 - 20 = 1500 - 36 = 1464 */ #define IPV4_HDR_MAX_SIZE 60 #define IPV6_HDR_MAX_SIZE 40 /* Assume no extension headers in general... */ #define UDP_HDR_MAX_SIZE 8 #define GTPU_HDR_MAX_SIZE 12 /* Assume no extension headers in general... */ #define MAX_DESIRED_APN_MTU ((ETHERNET_MTU) - (GTPU_HDR_MAX_SIZE) - (UDP_HDR_MAX_SIZE) - (IPV4_HDR_MAX_SIZE)) /* MAX_DESIRED_APN_MTU = 1500 - 60 - 8 - 12 = 1500 - 80 = 1420 */ struct ggsn_ctx; struct apn_ctx_ip { struct { struct in46_prefix ifconfig_prefix; struct in46_prefix ll_prefix; struct in46_prefix static_prefix; struct in46_prefix dynamic_prefix; /* v4 DNS server names */ struct in46_addr dns[2]; } cfg; /* v4 address pool */ struct ippool_t *pool; }; struct apn_name { struct llist_head list; char *name; }; enum apn_gtpu_mode { APN_GTPU_MODE_TUN = 0, /* default */ APN_GTPU_MODE_KERNEL_GTP, }; struct apn_ctx { /* list of APNs inside GGSN */ struct llist_head list; /* back-pointer to GGSN */ struct ggsn_ctx *ggsn; bool started; struct { /* Primary name */ char *name; /* Description string */ char *description; /* List of secondary APN names */ struct llist_head name_list; /* types supported address types on this APN */ uint32_t apn_type_mask; /* GTP-U via TUN device or in Linux kernel */ enum apn_gtpu_mode gtpu_mode; /* administratively shut down (true) or not (false) */ bool shutdown; /* transmit G-PDU sequence numbers (true) or not (false) */ bool tx_gpdu_seq; /* MTU announced to the UE */ uint16_t mtu; } cfg; /* corresponding tun device */ struct { struct { /* name of the network device */ char *dev_name; /* ip-up and ip-down script names/paths */ char *ipup_script; char *ipdown_script; } cfg; struct tun_t *tun; struct osmo_fd fd; } tun; /* ipv6 link-local address */ struct in6_addr v6_lladdr; struct apn_ctx_ip v4; struct apn_ctx_ip v6; }; struct pdp_priv_t { struct pdp_t *lib; /* pointer to libgtp associated pdp_t instance */ struct sgsn_peer *sgsn; struct apn_ctx *apn; struct llist_head entry; /* to be included into sgsn_peer */ /* struct ggsn_ctx can be reached through lib->gsn->priv, or through sgsn->ggsn */ }; struct ggsn_ctx { /* global list of GGSNs */ struct llist_head list; /* list of APNs in this GGSN */ struct llist_head apn_list; /* list of SGSN peers (struct sgsn_peer) in this GGSN. TODO: hash table with key ? */ struct llist_head sgsn_list; bool started; struct { char *name; /* Description string */ char *description; /* an APN that shall be used as default for any non-matching APN */ struct apn_ctx *default_apn; /* ADdress to which we listen for GTP */ struct in46_addr listen_addr; /* Local GTP-C address advertised in GTP */ struct in46_addr gtpc_addr; /* Local GTP-U address advertised in GTP */ struct in46_addr gtpu_addr; /* directory for state file */ char *state_dir; /* Time between Echo requests on each SGSN */ unsigned int echo_interval; /* administratively shut down (true) or not (false) */ bool shutdown; } cfg; /* The libgtp (G)GSN instance, i.e. what listens to GTP */ struct gsn_t *gsn; /* osmo-fd for gsn */ struct osmo_fd gtp_fd0; struct osmo_fd gtp_fd1c; struct osmo_fd gtp_fd1u; }; /* ggsn_vty.c */ extern struct llist_head g_ggsn_list; extern struct vty_app_info g_vty_info; extern int ggsn_vty_init(void); struct ggsn_ctx *ggsn_find(const char *name); struct ggsn_ctx *ggsn_find_or_create(void *ctx, const char *name); struct apn_ctx *ggsn_find_apn(struct ggsn_ctx *ggsn, const char *name); struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name); /* ggsn_main.c */ extern struct ctrl_handle *g_ctrlh; extern void *tall_ggsn_ctx; extern struct osmo_tdef_group ggsn_tdef_group[]; /* ggsn.c */ extern int ggsn_start(struct ggsn_ctx *ggsn); extern int ggsn_stop(struct ggsn_ctx *ggsn); extern int apn_start(struct apn_ctx *apn); extern int apn_stop(struct apn_ctx *apn); void ggsn_close_one_pdp(struct pdp_t *pdp); #define LOGPAPN(level, apn, fmt, args...) \ LOGP(DGGSN, level, "APN(%s): " fmt, (apn)->cfg.name, ## args) #define LOGPGGSN(level, ggsn, fmt, args...) \ LOGP(DGGSN, level, "GGSN(%s): " fmt, (ggsn)->cfg.name, ## args) #define LOGPPDP(level, pdp, fmt, args...) LOGPDPX(DGGSN, level, pdp, fmt, ## args)