pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ggsn/+/42465?usp=email )
Change subject: Depend on libosmo-netif for icmpv6 APIs ......................................................................
Depend on libosmo-netif for icmpv6 APIs
Most of icmpv6.* and checksum.* was moved to libosmo-netif from this same repository so it can be reused. Link to libosmo-netif and adapt code to new public symbol naming.
Depends: libosmo-netif.git Change-Id I78ec7270c717af0a1b8ffd9398cd69ea7a0dbee2 Change-Id: I8d8fae362f302d48afaed28a9c664f76ca4a2739 --- M TODO-RELEASE M configure.ac M contrib/jenkins.sh M debian/control M ggsn/Makefile.am M ggsn/ggsn.c M lib/Makefile.am D lib/checksum.c D lib/checksum.h M lib/icmpv6.c M lib/icmpv6.h M sgsnemu/Makefile.am M sgsnemu/sgsnemu.c 13 files changed, 50 insertions(+), 533 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ggsn refs/changes/65/42465/1
diff --git a/TODO-RELEASE b/TODO-RELEASE index 0ed7189..aab5c0a 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -7,3 +7,4 @@ # If any interfaces have been added since the last public release: c:r:a + 1. # If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line +libosmo-netif >1.7.0 osmo_icmpv6_*() diff --git a/configure.ac b/configure.ac index ade3ae9..2fd4d36 100644 --- a/configure.ac +++ b/configure.ac @@ -158,6 +158,7 @@ PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.12.0) PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.12.0) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.12.0) +PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.7.0)
AC_ARG_ENABLE(sanitize, [AS_HELP_STRING( diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 4404cfa..1473418 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -28,6 +28,7 @@ osmo-build-dep.sh libgtpnl fi osmo-build-dep.sh libosmocore "" --disable-doxygen +osmo-build-dep.sh libosmo-netif "" --disable-doxygen
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
diff --git a/debian/control b/debian/control index 8c9237d..0bd4694 100644 --- a/debian/control +++ b/debian/control @@ -8,6 +8,7 @@ libdpkg-perl, git, dh-autoreconf, libosmocore-dev (>= 1.12.0), + libosmo-netif-dev (>= 1.7.0), osmo-gsm-manuals-dev (>= 1.7.0), libgtpnl-dev (>= 1.3.0) Standards-Version: 3.9.6 diff --git a/ggsn/Makefile.am b/ggsn/Makefile.am index ad6b2b2..c82f458 100644 --- a/ggsn/Makefile.am +++ b/ggsn/Makefile.am @@ -11,9 +11,17 @@ $(LIBOSMOCORE_CFLAGS) \ $(LIBOSMOCTRL_CFLAGS) \ $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMONETIF_CFLAGS) \ $(NULL)
-osmo_ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS) +osmo_ggsn_LDADD = \ + @EXEC_LDADD@ \ + -lgtp -L../gtp ../lib/libmisc.a \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOCTRL_LIBS) \ + $(LIBOSMOVTY_LIBS) \ + $(LIBOSMONETIF_LIBS) \ + $(NULL)
if ENABLE_GTP_KERNEL AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS) diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 329b15f..3177713 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -46,6 +46,8 @@ #include <osmocom/ctrl/control_if.h> #include <osmocom/gsm/apn.h>
+#include <osmocom/netif/icmpv6.h> + #include <osmocom/gtp/pdp.h> #include <osmocom/gtp/gtp.h>
@@ -789,11 +791,13 @@
if (IN6_IS_ADDR_MULTICAST(&ip6h->ip6_dst)) { /* daddr: all-routers multicast addr */ - if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr)) + if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &osmo_icmpv6_all_router_mcast_addr)) return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6, &apn->v6_lladdr, apn->cfg.mtu, pack, len); /* daddr: solicited-node multicast addr */ - if (memcmp(&ip6h->ip6_dst.s6_addr, solicited_node_mcast_addr_prefix, sizeof(solicited_node_mcast_addr_prefix)) == 0) + if (memcmp(&ip6h->ip6_dst.s6_addr, + osmo_icmpv6_solicited_node_mcast_addr_prefix, + sizeof(osmo_icmpv6_solicited_node_mcast_addr_prefix)) == 0) return handle_solicited_node_mcast(pack, len); } break; diff --git a/lib/Makefile.am b/lib/Makefile.am index 1fdc93f..7f0f14f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,7 +1,6 @@ noinst_LIBRARIES = libmisc.a
noinst_HEADERS = \ - checksum.h \ gnugetopt.h \ gtp-kernel.h \ icmpv6.h \ @@ -21,10 +20,10 @@ -DSBINDIR='"$(sbindir)"' \ -I$(top_srcdir)/include \ $(LIBOSMOCORE_CFLAGS) \ + $(LIBOSMONETIF_CFLAGS) \ $(NULL)
libmisc_a_SOURCES = \ - checksum.c \ debug.c \ getopt.c \ getopt1.c \ diff --git a/lib/checksum.c b/lib/checksum.c deleted file mode 100644 index 4b23897..0000000 --- a/lib/checksum.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IP/TCP/UDP checksumming routines - * - * Authors: Jorge Cwik, jorge@laser.satlink.net - * Arnt Gulbrandsen, agulbra@nvg.unit.no - * Tom May, ftom@netcom.com - * Andreas Schwab, schwab@issan.informatik.uni-dortmund.de - * Lots of code moved from tcp.c and ip.c; see those files - * for more names. - * - * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: - * Fixed some nasty bugs, causing some horrible crashes. - * A: At some points, the sum (%0) was used as - * length-counter instead of the length counter - * (%1). Thanks to Roman Hodek for pointing this out. - * B: GCC seems to mess up if one uses too many - * data-registers to hold input values and one tries to - * specify d0 and d1 as scratch registers. Letting gcc - * choose these registers itself solves the problem. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access - kills, so most of the assembly has to go. */ - -#if defined(__FreeBSD__) -#define _KERNEL /* needed on FreeBSD 10.x for s6_addr32 */ -#include <sys/types.h> -#include <netinet/in.h> -#include <sys/endian.h> -#endif - -#include "checksum.h" -#include <arpa/inet.h> - -static inline unsigned short from32to16(unsigned int x) -{ - /* add up 16-bit and 16-bit for 16+c bit */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); - return x; -} - -static unsigned int do_csum(const unsigned char *buff, int len) -{ - int odd; - unsigned int result = 0; - - if (len <= 0) - goto out; - odd = 1 & (unsigned long) buff; - if (odd) { -#if BYTE_ORDER == LITTLE_ENDIAN - result += (*buff << 8); -#else - result = *buff; -#endif - len--; - buff++; - } - if (len >= 2) { - if (2 & (unsigned long) buff) { - result += *(unsigned short *) buff; - len -= 2; - buff += 2; - } - if (len >= 4) { - const unsigned char *end = buff + ((unsigned)len & ~3); - unsigned int carry = 0; - do { - unsigned int w = *(unsigned int *) buff; - buff += 4; - result += carry; - result += w; - carry = (w > result); - } while (buff < end); - result += carry; - result = (result & 0xffff) + (result >> 16); - } - if (len & 2) { - result += *(unsigned short *) buff; - buff += 2; - } - } - if (len & 1) -#if BYTE_ORDER == LITTLE_ENDIAN - result += *buff; -#else - result += (*buff << 8); -#endif - result = from32to16(result); - if (odd) - result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); -out: - return result; -} - -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - */ -uint16_t ip_fast_csum(const void *iph, unsigned int ihl) -{ - return (uint16_t)~do_csum(iph, ihl*4); -} - -/* - * computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit) - * - * returns a 32-bit number suitable for feeding into itself - * or csum_tcpudp_magic - * - * this function must be called with even lengths, except - * for the last fragment, which may be odd - * - * it's best to have buff aligned on a 32-bit boundary - */ -uint32_t csum_partial(const void *buff, int len, uint32_t wsum) -{ - unsigned int sum = (unsigned int)wsum; - unsigned int result = do_csum(buff, len); - - /* add in old sum, and carry.. */ - result += sum; - if (sum > result) - result += 1; - return (uint32_t)result; -} - -/* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c - */ -uint16_t ip_compute_csum(const void *buff, int len) -{ - return (uint16_t)~do_csum(buff, len); -} - -uint16_t csum_ipv6_magic(const struct in6_addr *saddr, - const struct in6_addr *daddr, - uint32_t len, uint8_t proto, uint32_t csum) -{ - int carry; - uint32_t ulen; - uint32_t uproto; - uint32_t sum = (uint32_t)csum; - - sum += (uint32_t)saddr->s6_addr32[0]; - carry = (sum < (uint32_t)saddr->s6_addr32[0]); - sum += carry; - - sum += (uint32_t)saddr->s6_addr32[1]; - carry = (sum < (uint32_t)saddr->s6_addr32[1]); - sum += carry; - - sum += (uint32_t)saddr->s6_addr32[2]; - carry = (sum < (uint32_t)saddr->s6_addr32[2]); - sum += carry; - - sum += (uint32_t)saddr->s6_addr32[3]; - carry = (sum < (uint32_t)saddr->s6_addr32[3]); - sum += carry; - - sum += (uint32_t)daddr->s6_addr32[0]; - carry = (sum < (uint32_t)daddr->s6_addr32[0]); - sum += carry; - - sum += (uint32_t)daddr->s6_addr32[1]; - carry = (sum < (uint32_t)daddr->s6_addr32[1]); - sum += carry; - - sum += (uint32_t)daddr->s6_addr32[2]; - carry = (sum < (uint32_t)daddr->s6_addr32[2]); - sum += carry; - - sum += (uint32_t)daddr->s6_addr32[3]; - carry = (sum < (uint32_t)daddr->s6_addr32[3]); - sum += carry; - - ulen = (uint32_t)htonl((uint32_t) len); - sum += ulen; - carry = (sum < ulen); - sum += carry; - - uproto = (uint32_t)htonl(proto); - sum += uproto; - carry = (sum < uproto); - sum += carry; - - return csum_fold((uint32_t)sum); -} - -/* fold a partial checksum */ -uint16_t csum_fold(uint32_t csum) -{ - uint32_t sum = (uint32_t)csum; - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - return (uint16_t)~sum; -} diff --git a/lib/checksum.h b/lib/checksum.h deleted file mode 100644 index 4b22431..0000000 --- a/lib/checksum.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include <stdint.h> -#include <netinet/in.h> - -uint16_t ip_fast_csum(const void *iph, unsigned int ihl); -uint32_t csum_partial(const void *buff, int len, uint32_t wsum); -uint16_t ip_compute_csum(const void *buff, int len); - -uint16_t csum_ipv6_magic(const struct in6_addr *saddr, - const struct in6_addr *daddr, - uint32_t len, uint8_t proto, uint32_t csum); - -uint16_t csum_fold(uint32_t csum); diff --git a/lib/icmpv6.c b/lib/icmpv6.c index 4226fc0..51a2b81 100644 --- a/lib/icmpv6.c +++ b/lib/icmpv6.c @@ -22,172 +22,16 @@ #include <osmocom/core/msgb.h> #include <osmocom/core/utils.h>
+#include <osmocom/netif/icmpv6.h> + #include <osmocom/gtp/gtp.h> #include <osmocom/gtp/pdp.h>
-#include "checksum.h" #include "ippool.h" #include "syserr.h" #include "icmpv6.h" #include "config.h"
-/* 29.061 11.2.1.3.4 IPv6 Router Configuration Variables in GGSN */ -#define GGSN_MaxRtrAdvInterval 21600 /* 6 hours */ -#define GGSN_MinRtrAdvInterval 16200 /* 4.5 hours */ -#define GGSN_AdvValidLifetime 0xffffffff /* infinite */ -#define GGSN_AdvPreferredLifetime 0xffffffff /* infinite */ - -/* RFC3307 link-local scope multicast address */ -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 } -}; - -/* RFC4291 link-local solicited-node multicast address, FF02:0:0:0:0:1:FF, 104 bits = 13 bytes */ -const uint8_t solicited_node_mcast_addr_prefix[13] = { - 0xff, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0xFF -}; - -/* Prepends the ipv6 header and returns checksum content */ -uint16_t icmpv6_prepend_ip6hdr(struct msgb *msg, const struct in6_addr *saddr, - const struct in6_addr *daddr) -{ - uint32_t len; - uint16_t skb_csum; - struct ip6_hdr *i6h; - - /* checksum */ - skb_csum = csum_partial(msgb_data(msg), msgb_length(msg), 0); - len = msgb_length(msg); - skb_csum = csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, skb_csum); - - /* Push IPv6 header in front of ICMPv6 packet */ - i6h = (struct ip6_hdr *) msgb_push(msg, sizeof(*i6h)); - /* 4 bits version, 8 bits TC, 20 bits flow-ID */ - i6h->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000); - i6h->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(len); - i6h->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_ICMPV6; - i6h->ip6_ctlun.ip6_un1.ip6_un1_hlim = 255; - i6h->ip6_src = *saddr; - i6h->ip6_dst = *daddr; - return skb_csum; -} - -/*! construct a RFC4861 compliant ICMPv6 router soliciation - * \param[in] saddr Source IPv6 address for router advertisement - * \param[in] daddr Destination IPv6 address for router advertisement IPv6 header - * \param[in] prefix The single prefix to be advertised (/64 implied!) - * \returns callee-allocated message buffer containing router advertisement */ -struct msgb *icmpv6_construct_rs(const struct in6_addr *saddr) -{ - struct msgb *msg = msgb_alloc_headroom(512,128, "IPv6 RS"); - struct icmpv6_rsol_hdr *rs; - OSMO_ASSERT(msg); - rs = (struct icmpv6_rsol_hdr *) msgb_put(msg, sizeof(*rs)); - rs->hdr.type = 133; /* see RFC4861 4.1 */ - rs->hdr.code = 0; /* see RFC4861 4.1 */ - rs->hdr.csum = 0; /* updated below */ - rs->reserved = 0; /* see RFC4861 4.1 */ - - rs->hdr.csum = icmpv6_prepend_ip6hdr(msg, saddr, &all_router_mcast_addr); - - return msg; -} -/*! construct a 3GPP 29.061 compliant router advertisement for a given prefix - * \param[in] saddr Source IPv6 address for router advertisement - * \param[in] daddr Destination IPv6 address for router advertisement IPv6 header - * \param[in] prefix The single prefix to be advertised (/64 implied!) - * \returns callee-allocated message buffer containing router advertisement */ -static struct msgb *icmpv6_construct_ra(const struct in6_addr *saddr, - const struct in6_addr *daddr, - const struct in6_addr *prefix, - uint32_t mtu) -{ - struct msgb *msg = msgb_alloc_headroom(512,128, "IPv6 RA"); - struct icmpv6_radv_hdr *ra; - struct icmpv6_opt_prefix *ra_opt_pref; - struct icmpv6_opt_mtu *ra_opt_mtu; - - OSMO_ASSERT(msg); - - ra = (struct icmpv6_radv_hdr *) msgb_put(msg, sizeof(*ra)); - ra->hdr.type = 134; /* see RFC4861 4.2 */ - ra->hdr.code = 0; /* see RFC4861 4.2 */ - ra->hdr.csum = 0; /* updated below */ - ra->cur_ho_limit = 64; /* seems reasonable? */ - /* the GGSN shall leave the M-flag cleared in the Router - * Advertisement messages */ - ra->m = 0; - /* The GGSN may set the O-flag if there are additional - * configuration parameters that need to be fetched by the MS */ - ra->o = 0; /* no DHCPv6 */ - ra->res = 0; - /* RFC4861 Default: 3 * MaxRtrAdvInterval */ - ra->router_lifetime = htons(3*GGSN_MaxRtrAdvInterval); - ra->reachable_time = 0; /* Unspecified */ - - /* RFC4861 Section 4.6.2 */ - ra_opt_pref = (struct icmpv6_opt_prefix *) msgb_put(msg, sizeof(*ra_opt_pref)); - ra_opt_pref->hdr.type = 3; /* RFC4861 4.6.2 */ - ra_opt_pref->hdr.len = 4; /* RFC4861 4.6.2 */ - ra_opt_pref->prefix_len = 64; /* only prefix length as per 3GPP */ - /* The Prefix is contained in the Prefix Information Option of - * the Router Advertisements and shall have the A-flag set - * and the L-flag cleared */ - ra_opt_pref->a = 1; - ra_opt_pref->l = 0; - ra_opt_pref->res = 0; - /* The lifetime of the prefix shall be set to infinity */ - ra_opt_pref->valid_lifetime = htonl(GGSN_AdvValidLifetime); - ra_opt_pref->preferred_lifetime = htonl(GGSN_AdvPreferredLifetime); - ra_opt_pref->res2 = 0; - memcpy(ra_opt_pref->prefix, prefix, sizeof(ra_opt_pref->prefix)); - - /* RFC4861 Section 4.6.4, MTU */ - ra_opt_mtu = (struct icmpv6_opt_mtu *) msgb_put(msg, sizeof(*ra_opt_mtu)); - ra_opt_mtu->hdr.type = 5; /* RFC4861 4.6.4 */ - ra_opt_mtu->hdr.len = 1; /* RFC4861 4.6.4 */ - ra_opt_mtu->reserved = 0; - ra_opt_mtu->mtu = htonl(mtu); - - /* The Prefix is contained in the Prefix Information Option of - * the Router Advertisements and shall have the A-flag set - * and the L-flag cleared */ - ra_opt_pref->a = 1; - ra_opt_pref->l = 0; - ra_opt_pref->res = 0; - /* The lifetime of the prefix shall be set to infinity */ - ra_opt_pref->valid_lifetime = htonl(GGSN_AdvValidLifetime); - ra_opt_pref->preferred_lifetime = htonl(GGSN_AdvPreferredLifetime); - ra_opt_pref->res2 = 0; - memcpy(ra_opt_pref->prefix, prefix, sizeof(ra_opt_pref->prefix)); - - /* checksum */ - ra->hdr.csum = icmpv6_prepend_ip6hdr(msg, saddr, daddr); - - return msg; -} - -/* Validate an ICMPv6 router solicitation according to RFC4861 6.1.1 */ -static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len) -{ - const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; - //const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h)); - - /* Hop limit field must have 255 */ - if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_hlim != 255) - return false; - /* FIXME: ICMP checksum is valid */ - /* ICMP length (derived from IP length) is 8 or more octets */ - if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_plen < 8) - return false; - /* FIXME: All included options have a length > 0 */ - /* FIXME: If IP source is unspecified, no source link-layer addr option */ - return true; -} - /* Validate an ICMPv6 neighbor solicitation according to RFC4861 7.1.1 */ static bool icmpv6_validate_neigh_solicit(const uint8_t *pack, unsigned len) { @@ -207,37 +51,6 @@ return true; }
-/* Validate an ICMPv6 router advertisement according to RFC4861 6.1.2. - Returns pointer packet header on success, NULL otherwise. */ -struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned len) -{ - const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; - const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h)); - - /* ICMP length (derived from IP length) is 16 or more octets */ - if (len < sizeof(*ip6h) + 16) - return NULL; - - if (ic6h->type != 134) /* router advertismenet type */ - return NULL; - - /*Routers must use their link-local address */ - if (!IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src)) - return NULL; - /* Hop limit field must have 255 */ - if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_hlim != 255) - return NULL; - /* ICMP Code is 0 */ - if (ic6h->code != 0) - return NULL; - /* ICMP length (derived from IP length) is 16 or more octets */ - if (ip6h->ip6_ctlun.ip6_un1.ip6_un1_plen < 16) - return NULL; - /* FIXME: All included options have a length > 0 */ - /* FIXME: If IP source is unspecified, no source link-layer addr option */ - return (struct icmpv6_radv_hdr *)ic6h; -} - /* handle incoming packets to the all-routers multicast address */ int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_addr *pdp_prefix, @@ -246,7 +59,7 @@ const uint8_t *pack, unsigned len) { const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; - const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h)); + const struct osmo_icmpv6_hdr *ic6h = (struct osmo_icmpv6_hdr *) (pack + sizeof(*ip6h)); struct msgb *msg;
if (len < sizeof(*ip6h)) { @@ -271,7 +84,7 @@ LOGP(DICMP6, LOGL_NOTICE, "ICMPv6 type 133 but code %d\n", ic6h->code); return -1; } - if (!icmpv6_validate_router_solicit(pack, len)) { + if (!osmo_icmpv6_validate_router_solicit(pack, len)) { LOGP(DICMP6, LOGL_NOTICE, "Invalid Router Solicitation: %s\n", osmo_hexdump(pack, len)); return -1; @@ -279,7 +92,7 @@ /* Send router advertisement from GGSN link-local * address to MS link-local address, including prefix * allocated to this PDP context */ - msg = icmpv6_construct_ra(own_ll_addr, &ip6h->ip6_src, pdp_prefix, mtu); + msg = osmo_icmpv6_construct_ra(own_ll_addr, &ip6h->ip6_src, pdp_prefix, mtu); /* Send the constructed RA to the MS */ gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg)); msgb_free(msg); @@ -295,7 +108,7 @@ int handle_solicited_node_mcast(const uint8_t *pack, unsigned len) { const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; - const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h)); + const struct osmo_icmpv6_hdr *ic6h = (struct osmo_icmpv6_hdr *) (pack + sizeof(*ip6h));
if (len < sizeof(*ip6h)) { LOGP(DICMP6, LOGL_NOTICE, "Packet too short: %u bytes\n", len); diff --git a/lib/icmpv6.h b/lib/icmpv6.h index 2469ed0..08bb506 100644 --- a/lib/icmpv6.h +++ b/lib/icmpv6.h @@ -1,109 +1,13 @@ #pragma once
-#include <stdbool.h> - -#include <osmocom/core/msgb.h> -#include <osmocom/core/endian.h> +#include <stdint.h>
#include <osmocom/gtp/gtp.h> #include <osmocom/gtp/pdp.h>
-#define ICMPv6_OPT_TYPE_PREFIX_INFO 0x03 - -#define foreach_icmpv6_opt(icmpv6_pkt, icmpv6_len, opt_hdr) \ - for (opt_hdr = (struct icmpv6_opt_hdr *)(icmpv6_pkt)->options; \ - (uint8_t*)(opt_hdr) + sizeof(struct icmpv6_opt_hdr) <= (((uint8_t*)(icmpv6_pkt)) + (icmpv6_len)); \ - opt_hdr = (struct icmpv6_opt_hdr*)((uint8_t*)(opt_hdr) + (opt_hdr)->len) \ - ) - -struct icmpv6_hdr { - uint8_t type; - uint8_t code; - uint16_t csum; -} __attribute__ ((packed)); - -struct icmpv6_echo_hdr { - struct icmpv6_hdr hdr; - uint16_t ident; /* Identifier */ - uint16_t seq; /* Sequence number */ - uint8_t data[0]; /* Data */ -} __attribute__ ((packed)); - -/* RFC4861 Section 4.1 */ -struct icmpv6_rsol_hdr { - struct icmpv6_hdr hdr; - uint32_t reserved; - uint8_t options[0]; -} __attribute__ ((packed)); - -/* RFC4861 Section 4.2 */ -struct icmpv6_radv_hdr { - struct icmpv6_hdr hdr; - uint8_t cur_ho_limit; -#if OSMO_IS_LITTLE_ENDIAN - uint8_t res:6, - m:1, - o:1; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ - uint8_t o:1, m:1, res:6; -#endif - uint16_t router_lifetime; - uint32_t reachable_time; - uint32_t retrans_timer; - uint8_t options[0]; -} __attribute__ ((packed)); - - -/* RFC4861 Section 4.6 */ -struct icmpv6_opt_hdr { - uint8_t type; - /* length in units of 8 octets, including type+len! */ - uint8_t len; - uint8_t data[0]; -} __attribute__ ((packed)); - -/* RFC4861 Section 4.6.2 */ -struct icmpv6_opt_prefix { - struct icmpv6_opt_hdr hdr; - uint8_t prefix_len; -#if OSMO_IS_LITTLE_ENDIAN - uint8_t res:6, - a:1, - l:1; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ - uint8_t l:1, a:1, res:6; -#endif - uint32_t valid_lifetime; - uint32_t preferred_lifetime; - uint32_t res2; - uint8_t prefix[16]; -} __attribute__ ((packed)); - -/* RFC4861 Section 4.6.4 */ -struct icmpv6_opt_mtu { - struct icmpv6_opt_hdr hdr; - uint16_t reserved; - uint32_t mtu; -} __attribute__ ((packed)); - -uint16_t icmpv6_prepend_ip6hdr(struct msgb *msg, const struct in6_addr *saddr, - const struct in6_addr *daddr); - -struct msgb *icmpv6_construct_rs(const struct in6_addr *saddr); - int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_addr *pdp_prefix, const struct in6_addr *own_ll_addr, uint32_t mtu, const uint8_t *pack, unsigned len); int handle_solicited_node_mcast(const uint8_t *pack, unsigned len); - -struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned len); - - -/* RFC3307 link-local scope multicast address */ -extern const struct in6_addr all_router_mcast_addr; - -extern const uint8_t solicited_node_mcast_addr_prefix[13]; diff --git a/sgsnemu/Makefile.am b/sgsnemu/Makefile.am index 5d88c7f..d28673f 100644 --- a/sgsnemu/Makefile.am +++ b/sgsnemu/Makefile.am @@ -9,9 +9,15 @@ -DSBINDIR='"$(sbindir)"' \ -I$(top_srcdir)/include \ $(LIBOSMOCORE_CFLAGS) \ + $(LIBOSMONETIF_CFLAGS) \ $(NULL)
-sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) +sgsnemu_LDADD = \ + @EXEC_LDADD@ \ + -lgtp -L../gtp ../lib/libmisc.a \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMONETIF_LIBS) \ + $(NULL)
if ENABLE_GTP_KERNEL AM_CFLAGS += \ diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index ee74def..ff2cfc7 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -25,6 +25,8 @@ #include <osmocom/core/msgb.h> #include <osmocom/core/select.h>
+#include <osmocom/netif/icmpv6.h> + #include <ctype.h> #include <netdb.h> #include <signal.h> @@ -178,7 +180,7 @@ } __attribute__ ((packed));
struct ip6_ping { - struct icmpv6_echo_hdr hdr; + struct osmo_icmpv6_echo_hdr hdr; uint8_t data[CREATEPING_MAX]; /* Data */ } __attribute__ ((packed));
@@ -1265,7 +1267,7 @@
static int cb_gtpu_data_ind_ping6(struct pdp_t *pdp, struct ip6_hdr *ip6h, unsigned len) { - const struct icmpv6_echo_hdr *ic6h = (struct icmpv6_echo_hdr *) ((uint8_t*)ip6h + sizeof(*ip6h)); + const struct osmo_icmpv6_echo_hdr *ic6h = (struct osmo_icmpv6_echo_hdr *) ((uint8_t *)ip6h + sizeof(*ip6h)); struct timeval tv; struct timeval tp; int triptime; @@ -1285,7 +1287,7 @@ return 0; }
- if (len < sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr)) { + if (len < sizeof(struct ip6_hdr) + sizeof(struct osmo_icmpv6_echo_hdr)) { LOGP(DSGSN, LOGL_ERROR, "Packet len too small to contain ICMPv6 echo header (%d)\n", len); return 0; } @@ -1305,7 +1307,7 @@ inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)), ntohs(ic6h->seq));
- if (len >= sizeof(struct ip6_hdr) + sizeof(struct icmpv6_echo_hdr) + sizeof(struct timeval)) { + if (len >= sizeof(struct ip6_hdr) + sizeof(struct osmo_icmpv6_echo_hdr) + sizeof(struct timeval)) { gettimeofday(&tv, NULL); memcpy(&tp, ic6h->data, sizeof(struct timeval)); if ((tv.tv_usec -= tp.tv_usec) < 0) { @@ -1441,7 +1443,7 @@
struct msgb *msg = msgb_alloc_headroom(sizeof(struct ip6_ping) + 128,128, "ICMPv6 echo"); OSMO_ASSERT(msg); - pack = (struct ip6_ping *) msgb_put(msg, sizeof(struct icmpv6_echo_hdr) + datasize); + pack = (struct ip6_ping *) msgb_put(msg, sizeof(struct osmo_icmpv6_echo_hdr) + datasize); pack->hdr.hdr.type = 128; pack->hdr.hdr.code = 0; pack->hdr.hdr.csum = 0; /* updated below */ @@ -1457,7 +1459,7 @@ gettimeofday(tp, &tz); }
- pack->hdr.hdr.csum = icmpv6_prepend_ip6hdr(msg, &src->v6, &dst->v6); + pack->hdr.hdr.csum = osmo_icmpv6_prepend_ip6hdr(msg, &src->v6, &dst->v6);
ntransmitted++; return gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg)); @@ -1682,7 +1684,7 @@ return EOF; /* Not a valid IP address */ } SYS_ERR(DSGSN, LOGL_INFO, 0, "Sending ICMPv6 Router Soliciation to GGSN..."); - msg = icmpv6_construct_rs(saddr6); + msg = osmo_icmpv6_construct_rs(saddr6); gtp_data_req(gsn, ctx->pdp, msgb_data(msg), msgb_length(msg)); msgb_free(msg); } @@ -1748,11 +1750,12 @@ } }
-static void handle_router_adv(struct pdp_t *pdp, struct ip6_hdr *ip6h, struct icmpv6_radv_hdr *ra, size_t ra_len) +static void handle_router_adv(struct pdp_t *pdp, struct ip6_hdr *ip6h, + struct osmo_icmpv6_radv_hdr *ra, size_t ra_len) { struct pdp_peer_sgsnemu_ctx* ctx = (struct pdp_peer_sgsnemu_ctx*)pdp->peer[0]; - struct icmpv6_opt_hdr *opt_hdr; - struct icmpv6_opt_prefix *opt_prefix; + struct osmo_icmpv6_opt_hdr *opt_hdr; + struct osmo_icmpv6_opt_prefix *opt_prefix; int rc; sigset_t oldmask; struct in6_addr rm; @@ -1763,7 +1766,7 @@
foreach_icmpv6_opt(ra, ra_len, opt_hdr) { if (opt_hdr->type == ICMPv6_OPT_TYPE_PREFIX_INFO) { - opt_prefix = (struct icmpv6_opt_prefix *)opt_hdr; + opt_prefix = (struct osmo_icmpv6_opt_prefix *)opt_hdr; size_t prefix_len_bytes = (opt_prefix->prefix_len + 7)/8; SYS_ERR(DSGSN, LOGL_INFO, 0, "Parsing OPT Prefix info (prefix_len=%u): %s", opt_prefix->prefix_len, @@ -1821,10 +1824,10 @@ static int cb_gtpu_data_ind(struct pdp_t *pdp, void *pack, unsigned len) { struct iphdr *iph = (struct iphdr *)pack; - struct icmpv6_radv_hdr *ra; + struct osmo_icmpv6_radv_hdr *ra; switch (iph->version) { case 6: - if ((ra = icmpv6_validate_router_adv(pack, len))) { + if ((ra = osmo_icmpv6_validate_router_adv(pack, len))) { size_t ra_len = (uint8_t*)ra - (uint8_t*)pack; handle_router_adv(pdp, (struct ip6_hdr *)pack, ra, ra_len); return 0;