From 31e9f03dbf9dee2d5e4a97ea96d7a9b5a63414ca Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 1 Dec 2017 17:54:32 +0100 Subject: Add configure flag to disable ipv6 support Change-Id: I651a12d63d025bde61dcbc3c6b949cd0fed43580 --- configure.ac | 20 ++++++++++++++------ ggsn/Makefile.am | 5 ++++- ggsn/ggsn.c | 38 ++++++++++++++++++++++++++++++++++---- ggsn/ggsn_vty.c | 47 ++++++++++++++++++++++++++++++++++++----------- lib/in46_addr.c | 24 ++++++++++++++++++++++-- lib/in46_addr.h | 4 ++++ lib/ippool.c | 20 +++++++++++++++++--- lib/tun.c | 13 +++++++++++-- sgsnemu/sgsnemu.c | 32 +++++++++++++++++++++++--------- tests/lib/in46a_test.c | 27 ++++++++++++++++++++++++--- 10 files changed, 189 insertions(+), 41 deletions(-) diff --git a/configure.ac b/configure.ac index 4fd0132..f4661b3 100644 --- a/configure.ac +++ b/configure.ac @@ -39,9 +39,9 @@ AC_SUBST(EXEC_LDFLAGS) case "${host}" in - i*86-*-linux-gnu*) + i*86-*-linux-gnu*) EXEC_LDADD="" ;; - *solaris*) + *solaris*) EXEC_LDADD="-lresolv -lsocket -lnsl" ;; esac @@ -64,13 +64,20 @@ dnl GTP Linux kernel dependencies AC_ARG_ENABLE([gtp-linux], AS_HELP_STRING([--enable-gtp-linux], [Build GTP tunneling Linux kernel]), [enable_gtp_linux="$enableval"], [enable_gtp_linux="no"]) - AS_IF([test "x$enable_gtp_linux" = "xyes"], [ PKG_CHECK_MODULES([LIBGTPNL], [libgtpnl >= 1.0.0]) ]) - AM_CONDITIONAL([ENABLE_GTP_KERNEL], [test "$enable_gtp_linux" = "yes"]) +# Enable/disable IPv6 support +AC_ARG_ENABLE([ipv6], [AS_HELP_STRING([--enable-ipv6], [Build IPv6 support])], + [enable_ipv6="$enableval"],[enable_ipv6="yes"]) +if test "x$enable_ipv6" = "xyes" ; then + AC_DEFINE(BUILD_IPv6, 1, [Define if we want to build IPv6 support]) +fi +AM_CONDITIONAL(BUILD_IPv6, test "x$enable_ipv6" = "xyes") +#AC_SUBST(enable_ipv6) + # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT @@ -127,7 +134,7 @@ AC_EGREP_HEADER(struct iphdr, netinet/ip.h, # Checks for library functions. AC_PROG_GCC_TRADITIONAL # AC_FUNC_MALLOC -# AC_FUNC_MEMCMP +# AC_FUNC_MEMCMP AC_CHECK_FUNCS([gethostbyname inet_ntoa memset select socket strdup strerror strtol]) AC_CHECK_FUNCS(inet_aton inet_addr, break) @@ -170,4 +177,5 @@ AC_OUTPUT echo " osmo-ggsn Configuration: - GTP Linux kernel support: ${enable_gtp_linux}" + GTP Linux kernel support: ${enable_gtp_linux} + IPv6 support: ${enable_ipv6}" diff --git a/ggsn/Makefile.am b/ggsn/Makefile.am index 8a468a9..07adf80 100644 --- a/ggsn/Makefile.am +++ b/ggsn/Makefile.am @@ -12,7 +12,10 @@ osmo_ggsn_LDADD += -lgtpnl endif osmo_ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a -osmo_ggsn_SOURCES = ggsn_vty.c ggsn.c ggsn.h gtp-kernel.h icmpv6.c icmpv6.h checksum.c checksum.h +osmo_ggsn_SOURCES = ggsn_vty.c ggsn.c ggsn.h gtp-kernel.h checksum.c checksum.h +if BUILD_IPv6 +osmo_ggsn_SOURCES += icmpv6.c icmpv6.h +endif if ENABLE_GTP_KERNEL osmo_ggsn_SOURCES += gtp-kernel.c diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 0beaef7..3018af4 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -65,7 +65,9 @@ #include "../gtp/pdp.h" #include "../gtp/gtp.h" #include "gtp-kernel.h" +#if defined(BUILD_IPv6) #include "icmpv6.h" +#endif #include "ggsn.h" void *tall_ggsn_ctx; @@ -115,7 +117,9 @@ int apn_stop(struct apn_ctx *apn, bool force) LOGPAPN(LOGL_NOTICE, apn, "%sStopping\n", force ? "FORCED " : ""); /* check if pools have any active PDP contexts and bail out */ pool_close_all_pdp(apn->v4.pool); +#if defined(BUILD_IPv6) pool_close_all_pdp(apn->v6.pool); +#endif /* shutdown whatever old state might be left */ if (apn->tun.tun) { @@ -137,12 +141,13 @@ int apn_stop(struct apn_ctx *apn, bool force) ippool_free(apn->v4.pool); apn->v4.pool = NULL; } +#if defined(BUILD_IPv6) if (apn->v6.pool) { LOGPAPN(LOGL_INFO, apn, "Releasing IPv6 pool\n"); ippool_free(apn->v6.pool); apn->v6.pool = NULL; } - +#endif apn->started = false; return 0; } @@ -155,9 +160,11 @@ static int alloc_ippool_blacklist(struct apn_ctx *apn, struct in46_prefix **blac *blacklist = NULL; +#if defined(BUILD_IPv6) if (ipv6) flags = IP_TYPE_IPv6_NONLINK; else +#endif flags = IP_TYPE_IPv4; while (1) { @@ -191,7 +198,9 @@ static int alloc_ippool_blacklist(struct apn_ctx *apn, struct in46_prefix **blac int apn_start(struct apn_ctx *apn) { int ippool_flags = IPPOOL_NONETWORK | IPPOOL_NOBROADCAST; +#if defined(BUILD_IPv6) struct in46_prefix ipv6_tun_linklocal_ip; +#endif struct in46_prefix *blacklist; int blacklist_size; @@ -226,7 +235,7 @@ int apn_start(struct apn_ctx *apn) return -1; } } - +#if defined(BUILD_IPv6) if (apn->v6.cfg.ifconfig_prefix.addr.len) { LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n", in46p_ntoa(&apn->v6.cfg.ifconfig_prefix)); @@ -239,13 +248,13 @@ int apn_start(struct apn_ctx *apn) return -1; } } - +#endif if (apn->tun.cfg.ipup_script) { LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n", apn->tun.cfg.ipup_script); tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script); } - +#if defined(BUILD_IPv6) if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) { if (tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK) < 1) { LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of " @@ -255,17 +264,20 @@ int apn_start(struct apn_ctx *apn) } apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6; } +#endif /* set back-pointer from TUN device to APN */ apn->tun.tun->priv = apn; break; case APN_GTPU_MODE_KERNEL_GTP: LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name); +#if defined(BUILD_IPv6) if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) { LOGPAPN(LOGL_ERROR, apn, "Kernel GTP currently supports only IPv4\n"); apn_stop(apn, false); return -1; } +#endif /* use GTP kernel module for data packet encapsulation */ if (gtp_kernel_init(apn->ggsn->gsn, apn->tun.cfg.dev_name, &apn->v4.cfg.ifconfig_prefix, apn->tun.cfg.ipup_script) < 0) { @@ -294,6 +306,7 @@ int apn_start(struct apn_ctx *apn) talloc_free(blacklist); } +#if defined(BUILD_IPv6) /* Create IPv6 pool */ if (apn->v6.cfg.dynamic_prefix.addr.len) { LOGPAPN(LOGL_INFO, apn, "Creating IPv6 pool %s\n", @@ -310,6 +323,7 @@ int apn_start(struct apn_ctx *apn) } talloc_free(blacklist); } +#endif LOGPAPN(LOGL_NOTICE, apn, "Successfully started\n"); apn->started = true; @@ -468,6 +482,7 @@ static void process_pco(struct apn_ctx *apn, struct pdp_t *pdp) build_ipcp_pco(msg, 0, &apn->v4.cfg.dns[0], &apn->v4.cfg.dns[1]); } +#if defined(BUILD_IPv6) if (pco_contains_proto(&pdp->pco_req, PCO_P_DNS_IPv6_ADDR)) { for (i = 0; i < ARRAY_SIZE(apn->v6.cfg.dns); i++) { struct in46_addr *i46a = &apn->v6.cfg.dns[i]; @@ -476,6 +491,7 @@ static void process_pco(struct apn_ctx *apn, struct pdp_t *pdp) msgb_t16lv_put(msg, PCO_P_DNS_IPv6_ADDR, i46a->len, i46a->v6.s6_addr); } } +#endif if (pco_contains_proto(&pdp->pco_req, PCO_P_DNS_IPv4_ADDR)) { for (i = 0; i < ARRAY_SIZE(apn->v4.cfg.dns); i++) { @@ -502,12 +518,14 @@ static bool apn_supports_ipv4(const struct apn_ctx *apn) return false; } +#if defined(BUILD_IPv6) static bool apn_supports_ipv6(const struct apn_ctx *apn) { if (apn->v6.cfg.static_prefix.addr.len || apn->v6.cfg.dynamic_prefix.addr.len) return true; return false; } +#endif int create_context_ind(struct pdp_t *pdp) { @@ -575,6 +593,7 @@ int create_context_ind(struct pdp_t *pdp) gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL); return 0; } +#if defined(BUILD_IPv6) } else if (addr.len == sizeof(struct in6_addr)) { struct in46_addr tmp; @@ -594,6 +613,7 @@ int create_context_ind(struct pdp_t *pdp) /* use allocated 64bit prefix as lower 64bit, used as link id by MS */ memcpy(tmp.v6.s6_addr+8, &member->addr.v6, 8); in46a_to_eua(&tmp, &pdp->eua); +#endif } else OSMO_ASSERT(0); @@ -635,7 +655,9 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) struct ippoolm_t *ipm; struct in46_addr dst; struct iphdr *iph = (struct iphdr *)pack; +#if defined(BUILD_IPv6) struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; +#endif struct ippool_t *pool; if (iph->version == 4) { @@ -644,6 +666,7 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) dst.len = 4; dst.v4.s_addr = iph->daddr; pool = apn->v4.pool; +#if defined(BUILD_IPv6) } else if (iph->version == 6) { /* Due to the fact that 3GPP requires an allocation of a * /64 prefix to each MS, we must instruct @@ -652,6 +675,7 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) dst.len = 8; dst.v6 = ip6h->ip6_dst; pool = apn->v6.pool; +#endif } else { LOGP(DTUN, LOGL_NOTICE, "non-IPv packet received from tun\n"); return -1; @@ -673,16 +697,20 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) return 0; } +#if defined(BUILD_IPv6) /* RFC3307 link-local scope multicast address */ static const struct in6_addr all_router_mcast_addr = { .s6_addr = { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 } }; +#endif /* MS-originated GTP1-U packet, needs to be sent via TUN device */ static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) { struct iphdr *iph = (struct iphdr *)pack; +#if defined(BUILD_IPv6) struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; +#endif struct tun_t *tun = (struct tun_t *)pdp->ipif; struct apn_ctx *apn = tun->priv; @@ -692,11 +720,13 @@ static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) LOGPPDP(LOGL_DEBUG, pdp, "Packet received: forwarding to tun\n"); switch (iph->version) { +#if defined(BUILD_IPv6) case 6: /* daddr: all-routers multicast addr */ if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr)) return handle_router_mcast(pdp->gsn, pdp, &apn->v6_lladdr, pack, len); break; +#endif case 4: break; default: diff --git a/ggsn/ggsn_vty.c b/ggsn/ggsn_vty.c index 6e15ae4..4932c20 100644 --- a/ggsn/ggsn_vty.c +++ b/ggsn/ggsn_vty.c @@ -334,8 +334,10 @@ static struct cmd_node apn_node = { static const struct value_string pdp_type_names[] = { { APN_TYPE_IPv4, "v4" }, +#if defined(BUILD_IPv6) { APN_TYPE_IPv6, "v6" }, { APN_TYPE_IPv4v6, "v4v6" }, +#endif { 0, NULL } }; @@ -345,13 +347,17 @@ static const struct value_string apn_gtpu_mode_names[] = { { 0, NULL } }; - +#if defined(BUILD_IPv6) +#define V4V6V46_ARGS "(v4|v6|v4v6)" #define V4V6V46_STRING "IPv4(-only) PDP Type\n" \ "IPv6(-only) PDP Type\n" \ "IPv4v6 (dual-stack) PDP Type\n" - +#else +#define V4V6V46_ARGS "(v4)" +#define V4V6V46_STRING "IPv4(-only) PDP Type\n" +#endif DEFUN(cfg_apn_type_support, cfg_apn_type_support_cmd, - "type-support (v4|v6|v4v6)", + "type-support " V4V6V46_ARGS, "Enable support for PDP Type\n" V4V6V46_STRING) { @@ -363,7 +369,7 @@ DEFUN(cfg_apn_type_support, cfg_apn_type_support_cmd, } DEFUN(cfg_apn_no_type_support, cfg_apn_no_type_support_cmd, - "no type-support (v4|v6|v4v6)", + "no type-support " V4V6V46_ARGS, NO_STR "Disable support for PDP Type\n" V4V6V46_STRING) { @@ -480,6 +486,7 @@ DEFUN(cfg_apn_no_ip_ifconfig, cfg_apn_no_ip_ifconfig_cmd, return CMD_SUCCESS; } +#if defined(BUILD_IPv6) DEFUN(cfg_apn_ipv6_prefix, cfg_apn_ipv6_prefix_cmd, "ipv6 prefix (static|dynamic) X:X::X:X/M", IP6_STR PREFIX_STR "IPv6 Address/Prefix-Length\n") @@ -512,6 +519,7 @@ DEFUN(cfg_apn_no_ipv6_ifconfig, cfg_apn_no_ipv6_ifconfig_cmd, memset(&apn->v6.cfg.ifconfig_prefix, 0, sizeof(apn->v6.cfg.ifconfig_prefix)); return CMD_SUCCESS; } +#endif #define DNS_STRINGS "Configure DNS Server\n" "primary/secondary DNS\n" "IP address of DNS Sever\n" @@ -528,6 +536,7 @@ DEFUN(cfg_apn_ip_dns, cfg_apn_ip_dns_cmd, return CMD_SUCCESS; } +#if defined(BUILD_IPv6) DEFUN(cfg_apn_ipv6_dns, cfg_apn_ipv6_dns_cmd, "ipv6 dns <0-1> X:X::X:X", IP6_STR DNS_STRINGS) @@ -540,20 +549,27 @@ DEFUN(cfg_apn_ipv6_dns, cfg_apn_ipv6_dns_cmd, return CMD_SUCCESS; } +#endif +#if defined(BUILD_IPv6) +#define IPV46_ARGS "(ip|ipv6)" +#else +#define IPV46_ARGS "(ip)" +#endif DEFUN(cfg_apn_no_dns, cfg_apn_no_dns_cmd, - "no (ip|ipv6) dns <0-1>", + "no " IPV46_ARGS " dns <0-1>", NO_STR IP_STR IP6_STR "Disable DNS Server\n" "primary/secondary DNS\n") { struct apn_ctx *apn = (struct apn_ctx *) vty->index; - struct in46_addr *a; + struct in46_addr *a = NULL; int idx = atoi(argv[1]); if (!strcmp(argv[0], "ip")) a = &apn->v4.cfg.dns[idx]; +#if defined(BUILD_IPv6) else a = &apn->v6.cfg.dns[idx]; - +#endif memset(a, 0, sizeof(*a)); return CMD_SUCCESS; @@ -656,6 +672,7 @@ static void config_write_apn(struct vty *vty, struct apn_ctx *apn) if (apn->v4.cfg.ifconfig_prefix.addr.len) vty_dump_prefix(vty, " ip ifconfig", &apn->v4.cfg.ifconfig_prefix); +#if defined(BUILD_IPv6) /* IPv6 prefixes + DNS */ if (apn->v6.cfg.static_prefix.addr.len) vty_dump_prefix(vty, " ipv6 prefix static", &apn->v6.cfg.static_prefix); @@ -668,7 +685,7 @@ static void config_write_apn(struct vty *vty, struct apn_ctx *apn) } if (apn->v6.cfg.ifconfig_prefix.addr.len) vty_dump_prefix(vty, " ipv6 ifconfig", &apn->v6.cfg.ifconfig_prefix); - +#endif /* must be last */ vty_out(vty, " %sshutdown%s", apn->cfg.shutdown ? "" : "no ", VTY_NEWLINE); } @@ -704,8 +721,12 @@ static const char *print_gsnaddr(const struct ul16_t *in) struct in46_addr in46; in46.len = in->l; +#if defined(BUILD_IPv6) OSMO_ASSERT(in->l <= sizeof(in46.v6)); - memcpy(&in46.v6, in->v, in->l); +#else + OSMO_ASSERT(in->l <= sizeof(in46.v4)); +#endif + memcpy(&in46.v4, in->v, in->l); return in46a_ntoa(&in46); } @@ -781,7 +802,9 @@ static void ippool_show_pdp_contexts(struct vty *vty, struct ippool_t *pool) static void apn_show_pdp_contexts(struct vty *vty, struct apn_ctx *apn) { ippool_show_pdp_contexts(vty, apn->v4.pool); +#if defined(BUILD_IPv6) ippool_show_pdp_contexts(vty, apn->v6.pool); +#endif } DEFUN(show_pdpctx, show_pdpctx_cmd, @@ -885,14 +908,16 @@ int ggsn_vty_init(void) install_element(APN_NODE, &cfg_apn_ipdown_script_cmd); install_element(APN_NODE, &cfg_apn_no_ipdown_script_cmd); install_element(APN_NODE, &cfg_apn_ip_prefix_cmd); - install_element(APN_NODE, &cfg_apn_ipv6_prefix_cmd); install_element(APN_NODE, &cfg_apn_ip_dns_cmd); - install_element(APN_NODE, &cfg_apn_ipv6_dns_cmd); install_element(APN_NODE, &cfg_apn_no_dns_cmd); install_element(APN_NODE, &cfg_apn_ip_ifconfig_cmd); install_element(APN_NODE, &cfg_apn_no_ip_ifconfig_cmd); +#if defined(BUILD_IPv6) + install_element(APN_NODE, &cfg_apn_ipv6_prefix_cmd); + install_element(APN_NODE, &cfg_apn_ipv6_dns_cmd); install_element(APN_NODE, &cfg_apn_ipv6_ifconfig_cmd); install_element(APN_NODE, &cfg_apn_no_ipv6_ifconfig_cmd); +#endif install_element(APN_NODE, &cfg_apn_gpdu_seq_cmd); install_element(APN_NODE, &cfg_apn_no_gpdu_seq_cmd); diff --git a/lib/in46_addr.c b/lib/in46_addr.c index 36ad6af..79123b5 100644 --- a/lib/in46_addr.c +++ b/lib/in46_addr.c @@ -28,9 +28,11 @@ int in46a_to_af(const struct in46_addr *in) switch (in->len) { case 4: return AF_INET; +#if defined(BUILD_IPv6) case 8: case 16: return AF_INET6; +#endif default: OSMO_ASSERT(0); return -1; @@ -41,17 +43,21 @@ int in46a_to_af(const struct in46_addr *in) int in46a_to_sas(struct sockaddr_storage *out, const struct in46_addr *in) { struct sockaddr_in *sin = (struct sockaddr_in *)out; +#if defined(BUILD_IPv6) struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)out; +#endif switch (in->len) { case 4: sin->sin_family = AF_INET; sin->sin_addr = in->v4; break; +#if defined(BUILD_IPv6) case 16: sin6->sin6_family = AF_INET6; sin6->sin6_addr = in->v6; break; +#endif default: OSMO_ASSERT(0); return -1; @@ -98,7 +104,7 @@ const char *in46p_ntoa(const struct in46_prefix *in46p) * \returns 1 in case they are equal; 0 otherwise */ int in46a_equal(const struct in46_addr *a, const struct in46_addr *b) { - if (a->len == b->len && !memcmp(&a->v6, &b->v6, a->len)) + if (a->len == b->len && !memcmp(&a->v4, &b->v4, a->len)) return 1; else return 0; @@ -115,12 +121,13 @@ int in46a_prefix_equal(const struct in46_addr *a, const struct in46_addr *b) else len = a->len; - if (!memcmp(&a->v6, &b->v6, len)) + if (!memcmp(&a->v4, &b->v4, len)) return 1; else return 0; } +#if defined(BUILD_IPv6) /*! Match if IPv6 addr1 + addr2 are within same \a mask */ static int ipv6_within_mask(const struct in6_addr *addr1, const struct in6_addr *addr2, const struct in6_addr *mask) @@ -167,6 +174,7 @@ static void create_ipv6_netmask(struct in6_addr *netmask, int prefixlen) *p_netmask = htonl(0xFFFFFFFF << (32 - prefixlen)); } } +#endif /*! Determine if given \a addr is within given \a net + \a prefixlen * Builds the netmask from \a net + \a prefixlen and matches it to \a addr @@ -174,7 +182,9 @@ static void create_ipv6_netmask(struct in6_addr *netmask, int prefixlen) int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen) { struct in_addr netmask; +#if defined(BUILD_IPv6) struct in6_addr netmask6; +#endif if (addr->len != net->len) return 0; @@ -186,9 +196,11 @@ int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, return 1; else return 0; +#if defined(BUILD_IPv6) case 16: create_ipv6_netmask(&netmask6, prefixlen); return ipv6_within_mask(&addr->v6, &net->v6, &netmask6); +#endif default: OSMO_ASSERT(0); return 0; @@ -210,6 +222,7 @@ static unsigned int ipv4_netmasklen(const struct in_addr *netmask) return prefix; } +#if defined(BUILD_IPv6) static unsigned int ipv6_netmasklen(const struct in6_addr *netmask) { #if defined(__linux__) @@ -235,6 +248,7 @@ static unsigned int ipv6_netmasklen(const struct in6_addr *netmask) return prefix; } +#endif /*! Convert netmask to prefix length representation * \param[in] netmask in46_addr containing a netmask (consecutive list of 1-bit followed by consecutive list of 0-bit) @@ -245,8 +259,10 @@ unsigned int in46a_netmasklen(const struct in46_addr *netmask) switch (netmask->len) { case 4: return ipv4_netmasklen(&netmask->v4); +#if defined(BUILD_IPv6) case 16: return ipv6_netmasklen(&netmask->v6); +#endif default: OSMO_ASSERT(0); return 0; @@ -264,6 +280,7 @@ int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua) eua->v[1] = PDP_EUA_TYPE_v4; memcpy(&eua->v[2], &src->v4, 4); /* Copy a 4 byte address */ break; +#if defined(BUILD_IPv6) case 8: case 16: eua->l = 18; @@ -271,6 +288,7 @@ int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua) eua->v[1] = PDP_EUA_TYPE_v6; memcpy(&eua->v[2], &src->v6, 16); /* Copy a 16 byte address */ break; +#endif default: OSMO_ASSERT(0); return -1; @@ -296,6 +314,7 @@ int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst) else dst->v4.s_addr = 0; break; +#if defined(BUILD_IPv6) case PDP_EUA_TYPE_v6: dst->len = 16; if (eua->l >= 18) @@ -303,6 +322,7 @@ int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst) else memset(&dst->v6, 0, 16); break; +#endif default: return -1; } diff --git a/lib/in46_addr.h b/lib/in46_addr.h index ff26521..2b3755b 100644 --- a/lib/in46_addr.h +++ b/lib/in46_addr.h @@ -4,13 +4,17 @@ #include "../gtp/pdp.h" +#include "config.h" + /* a simple wrapper around an in6_addr to also contain the length of the address, * thereby implicitly indicating the address family of the address */ struct in46_addr { uint8_t len; union { struct in_addr v4; +#if defined(BUILD_IPv6) struct in6_addr v6; +#endif }; }; diff --git a/lib/ippool.c b/lib/ippool.c index a9a64be..ffc4388 100644 --- a/lib/ippool.c +++ b/lib/ippool.c @@ -22,6 +22,8 @@ #include "ippool.h" #include "lookup.h" +#include "config.h" + int ippool_printaddr(struct ippool_t *this) { unsigned int n; @@ -96,18 +98,24 @@ static unsigned long int ippool_hash4(struct in_addr *addr) return lookup((unsigned char *)&addr->s_addr, sizeof(addr->s_addr), 0); } +#if defined(BUILD_IPv6) static unsigned long int ippool_hash6(struct in6_addr *addr, unsigned int len) { /* TODO: Review hash spread for IPv6 */ return lookup((unsigned char *)addr->s6_addr, len, 0); } +#endif unsigned long int ippool_hash(struct in46_addr *addr) { +#if defined(BUILD_IPv6) if (addr->len == 4) return ippool_hash4(&addr->v4); else return ippool_hash6(&addr->v6, addr->len); +#else + return ippool_hash4(&addr->v4); +#endif } /* Get IP address and mask */ @@ -148,11 +156,14 @@ int ippool_aton(struct in46_addr *addr, size_t *prefixlen, const char *pool_in, *prefixlen = 32; addr->len = sizeof(struct in_addr); addr->v4 = ((struct sockaddr_in*)ai->ai_addr)->sin_addr; - } else { + } +#if defined(BUILD_IPv6) + else { *prefixlen = 128; addr->len = sizeof(struct in6_addr); addr->v6 = ((struct sockaddr_in6*)ai->ai_addr)->sin6_addr; } +#endif freeaddrinfo(ai); /* parse prefixlen */ @@ -177,7 +188,7 @@ int ippool_aton(struct in46_addr *addr, size_t *prefixlen, const char *pool_in, void in46a_inc(struct in46_addr *addr) { size_t addrlen; - uint8_t *a = (uint8_t *)&addr->v6; + uint8_t *a = (uint8_t *)&addr->v4; for (addrlen = addr->len; addrlen > 0; addrlen--) { if (++a[addrlen-1]) break; @@ -215,11 +226,12 @@ int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn, const stru } else { addr = dyn->addr; addrprefixlen = dyn->prefixlen; +#if defined(BUILD_IPv6) /* we want to work with /64 prefixes, i.e. allocate /64 prefixes rather * than /128 (single IPv6 addresses) */ if (addr.len == sizeof(struct in6_addr)) addr.len = 64/8; - +#endif dynsize = (1 << (addr.len*8 - addrprefixlen)); if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */ dynsize--; @@ -404,8 +416,10 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member, if (addr) { if (addr->len == 4 && addr->v4.s_addr) specified = 1; +#if defined(BUILD_IPv6) if (addr->len == 16 && !IN6_IS_ADDR_UNSPECIFIED(&addr->v6)) specified = 1; +#endif } /* First check to see if this type of address is allowed */ diff --git a/lib/tun.c b/lib/tun.c index d8e4b62..ce3eced 100644 --- a/lib/tun.c +++ b/lib/tun.c @@ -62,7 +62,9 @@ #if defined(__linux__) +#if defined(BUILD_IPv6) #include +#endif static int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen) { @@ -197,6 +199,7 @@ static int tun_setaddr4(struct tun_t *this, struct in_addr *addr, return 0; } +#if defined(BUILD_IPv6) static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr, size_t prefixlen) { @@ -280,6 +283,7 @@ static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_ad return 0; } +#endif /* BUILD_IPv6 */ int tun_setaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen) { @@ -288,8 +292,10 @@ int tun_setaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *ds case 4: netmask.s_addr = htonl(0xffffffff << (32 - prefixlen)); return tun_setaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask); +#if defined(BUILD_IPv6) case 16: return tun_setaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen); +#endif default: return -1; } @@ -762,11 +768,13 @@ int tun_runscript(struct tun_t *tun, char *script) */ int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list, size_t prefix_size, int flags) { +#if defined(BUILD_IPv6) static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 }; + bool is_ipv6_ll; +#endif struct ifaddrs *ifaddr, *ifa; struct in46_addr netmask; size_t count = 0; - bool is_ipv6_ll; if (getifaddrs(&ifaddr) == -1) { return -1; @@ -792,7 +800,7 @@ int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list, si } count++; } - +#if defined(BUILD_IPv6) if (ifa->ifa_addr->sa_family == AF_INET6 && (flags & IP_TYPE_IPv6)) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr; struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) ifa->ifa_netmask; @@ -812,6 +820,7 @@ int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list, si } count++; } +#endif } freeifaddrs(ifaddr); diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index c31f875..e422b64 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -1,13 +1,13 @@ -/* +/* * OsmoGGSN - Gateway GPRS Support Node * Copyright (C) 2002, 2003, 2004 Mondru AB. * Copyright (C) 2017 Harald Welte - * + * * The contents of this file may be used under the terms of the GNU * General Public License Version 2, provided that the above copyright * notice and this permission notice is included in all copies or * substantial portions of the software. - * + * */ /* @@ -372,10 +372,10 @@ static int process_options(int argc, char **argv) /* foreground */ /* If fg flag not given run as a daemon */ - /* Do not allow sgsnemu to run as deamon + /* Do not allow sgsnemu to run as deamon if (!args_info.fg_flag) { - closelog(); + closelog(); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); freopen("/dev/null", "r", stdin); @@ -936,10 +936,12 @@ static int process_options(int argc, char **argv) options.tx_gpdu_seq = 1; /* PDP Type */ - if (!strcmp(args_info.pdp_type_arg, "v6")) - options.pdp_type = PDP_EUA_TYPE_v6; - else if (!strcmp(args_info.pdp_type_arg, "v4")) + if (!strcmp(args_info.pdp_type_arg, "v4")) options.pdp_type = PDP_EUA_TYPE_v4; +#if defined(BUILD_IPv6) + else if if (!strcmp(args_info.pdp_type_arg, "v6")) + options.pdp_type = PDP_EUA_TYPE_v6; +#endif else { SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n", args_info.pdp_type_arg); @@ -955,6 +957,7 @@ static int process_options(int argc, char **argv) } +#if defined(BUILD_IPv6) /* read a single value from a /procc file, up to 255 bytes, callee-allocated */ static char *proc_read(const char *path) { @@ -989,6 +992,7 @@ static char *proc_ipv6_conf_read(const char *dev, const char *file) snprintf(path, sizeof(path), fmt, dev, file); return proc_read(path); } +#endif static char *print_ipprot(int t) { @@ -1323,8 +1327,10 @@ static int delete_context(struct pdp_t *pdp) return 0; } +#if defined(BUILD_IPv6) /* Link-Local address prefix fe80::/64 */ static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 }; +#endif /* Callback for receiving messages from tun */ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) @@ -1332,7 +1338,9 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) struct iphash_t *ipm; struct in46_addr src; struct iphdr *iph = (struct iphdr *)pack; +#if defined(BUILD_IPv6) struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; +#endif if (iph->version == 4) { if (len < sizeof(*iph) || len < 4*iph->ihl) { @@ -1341,6 +1349,7 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) } src.len = 4; src.v4.s_addr = iph->saddr; +#if defined(BUILD_IPv6) } else if (iph->version == 6) { /* We only have a single entry in the hash table, and it consists of the link-local * address "fe80::prefix". So we need to make sure to convert non-link-local source @@ -1355,6 +1364,7 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix)); memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix)); } +#endif } else { printf("Dropping packet with invalid IP version %u\n", iph->version); return 0; @@ -1416,6 +1426,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) in46a_ntoa(&addr)); switch (addr.len) { +#if defined(BUILD_IPv6) case 16: /* IPv6 */ /* we have to enable the kernel to perform stateless autoconfiguration, * i.e. send a router solicitation using the lover 64bits of the allocated @@ -1423,6 +1434,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix)); printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr)); break; +#endif case 4: /* IPv4 */ break; } @@ -1443,6 +1455,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) tun_runscript(tun, options.ipup); } +#if defined(BUILD_IPv6) /* now that ip-up has been executed, check if we are configured to * accept router advertisements */ if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) { @@ -1463,6 +1476,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) free(accept_ra); free(forwarding); } +#endif ipset((struct iphash_t *)pdp->peer, &addr); @@ -1700,7 +1714,7 @@ int main(int argc, char **argv) pdp->hisaddr0 = options.remote; pdp->hisaddr1 = options.remote; - pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid, + pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid, 512 = Flat rate, 256 = Hot billing */ pdp->tx_gpdu_seq = options.tx_gpdu_seq; diff --git a/tests/lib/in46a_test.c b/tests/lib/in46a_test.c index d4a5dbc..06813bb 100644 --- a/tests/lib/in46a_test.c +++ b/tests/lib/in46a_test.c @@ -20,29 +20,37 @@ static const struct in46_addr g_ia4 = { .v4.s_addr = 0x0d0c0b0a, }; +#if defined(BUILD_IPv6) static const struct in46_addr g_ia6 = { .len = 16, .v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }, }; +#endif static void test_in46a_to_af(void) { +#if defined(BUILD_IPv6) struct in46_addr ia; +#endif printf("Testing in46a_to_af()\n"); OSMO_ASSERT(in46a_to_af(&g_ia4) == AF_INET); +#if defined(BUILD_IPv6) OSMO_ASSERT(in46a_to_af(&g_ia6) == AF_INET6); ia.len = 8; OSMO_ASSERT(in46a_to_af(&ia) == AF_INET6); +#endif } static void test_in46a_to_sas(void) { struct sockaddr_storage ss; struct sockaddr_in *sin = (struct sockaddr_in *) &ss; +#if defined(BUILD_IPv6) struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss; +#endif printf("Testing in46a_to_sas()\n"); @@ -51,10 +59,12 @@ static void test_in46a_to_sas(void) OSMO_ASSERT(sin->sin_family == AF_INET); OSMO_ASSERT(sin->sin_addr.s_addr == g_ia4.v4.s_addr); +#if defined(BUILD_IPv6) memset(&ss, 0, sizeof(ss)); OSMO_ASSERT(in46a_to_sas(&ss, &g_ia6) == 0); OSMO_ASSERT(sin6->sin6_family == AF_INET6); OSMO_ASSERT(!memcmp(&sin6->sin6_addr, &g_ia6.v6, sizeof(sin6->sin6_addr))); +#endif } static void test_in46a_ntop(void) @@ -79,10 +89,11 @@ static void test_in46a_ntop(void) res = in46a_ntop(&ia, buf, sizeof(buf)); OSMO_ASSERT(res && !strcmp(res, "1.2.3.4")); printf("res = %s\n", res); - +#if defined(BUILD_IPv6) res = in46a_ntop(&g_ia6, buf, sizeof(buf)); OSMO_ASSERT(res && !strcmp(res, "102:304:506:708:90a:b0c:d0e:f10")); printf("res = %s\n", res); +#endif } static void test_in46p_ntoa(void) @@ -108,11 +119,12 @@ static void test_in46a_equal(void) b.v4.s_addr = g_ia4.v4.s_addr; OSMO_ASSERT(in46a_equal(&g_ia4, &b)); +#if defined(BUILD_IPv6) memset(&b, 0xff, sizeof(b)); b.len = g_ia6.len; b.v6 = g_ia6.v6; OSMO_ASSERT(in46a_equal(&g_ia6, &b)); - +#endif } @@ -155,10 +167,12 @@ static void test_in46a_within_mask(void) static void test_in46a_to_eua(void) { +#if defined(BUILD_IPv6) const struct in46_addr ia_v6_8 = { .len = 8, .v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }, }; +#endif struct ul66_t eua; printf("testing in46a_to_eua()\n"); @@ -174,6 +188,7 @@ static void test_in46a_to_eua(void) OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4); OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr); +#if defined(BUILD_IPv6) /* IPv6 address */ OSMO_ASSERT(in46a_to_eua(&g_ia6, &eua) == 0); OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF); @@ -185,6 +200,7 @@ static void test_in46a_to_eua(void) OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF); OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6); OSMO_ASSERT(!memcmp(&eua.v[2], &ia_v6_8.v6, 16)); +#endif } static void test_in46a_from_eua(void) @@ -193,10 +209,11 @@ static void test_in46a_from_eua(void) struct ul66_t eua; const uint8_t v4_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4 }; const uint8_t v4_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4, 1,2,3,4 }; +#if defined(BUILD_IPv6) const uint8_t v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6 }; const uint8_t v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 }; - +#endif memset(&eua, 0, sizeof(eua)); printf("Testing in46a_from_eua()\n"); @@ -232,6 +249,7 @@ static void test_in46a_from_eua(void) OSMO_ASSERT(ia.len == 4); OSMO_ASSERT(ia.v4.s_addr == htonl(0x01020304)); +#if defined(BUILD_IPv6) /* unspecified V6 */ memcpy(eua.v, v6_unspec, sizeof(v6_unspec)); eua.l = sizeof(v6_unspec); @@ -245,6 +263,7 @@ static void test_in46a_from_eua(void) OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 0); OSMO_ASSERT(ia.len == 16); OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len)); +#endif } static void test_in46a_netmasklen(void) @@ -275,6 +294,7 @@ static void test_in46a_netmasklen(void) len = in46a_netmasklen(&netmask); OSMO_ASSERT(len == 0); +#if defined(BUILD_IPv6) printf("Testing in46a_netmasklen() with IPv6 addresses\n"); const struct in46_addr netmaskA = { .len = 16, @@ -303,6 +323,7 @@ static void test_in46a_netmasklen(void) }; len = in46a_netmasklen(&netmaskD); OSMO_ASSERT(len == 0); +#endif } int main(int argc, char **argv) -- cgit v1.2.3