aboutsummaryrefslogtreecommitdiffstats
path: root/ggsn
diff options
context:
space:
mode:
Diffstat (limited to 'ggsn')
-rw-r--r--ggsn/ggsn.c41
-rw-r--r--ggsn/icmpv6.c15
-rw-r--r--ggsn/icmpv6.h4
3 files changed, 47 insertions, 13 deletions
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 3e095f0..7954d5e 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -425,6 +425,30 @@ static bool pco_contains_proto(struct ul255_t *pco, uint16_t prot)
return false;
}
+/*! Get the peer of pdp based on IP version used.
+ * \param[in] pdp PDP context to select the peer from.
+ * \param[in] v4v6 IP version to select. Valid values are 4 and 6.
+ * \returns The selected peer matching the given IP version. NULL if not present.
+ */
+static struct ippoolm_t *pdp_get_peer_ipv(struct pdp_t *pdp, bool is_ipv6) {
+ uint8_t len1, len2, i;
+
+ if (is_ipv6) {
+ len1 = 8;
+ len2 = 16;
+ } else {
+ len1 = sizeof(struct in_addr);
+ len2 = len1;
+ }
+
+ for (i = 0; i < 2; i++) {
+ struct ippoolm_t * ippool = pdp->peer[i];
+ if (ippool && (ippool->addr.len == len1 || ippool->addr.len == len2))
+ return ippool;
+ }
+ return NULL;
+}
+
/* determine if PDP context has IPv6 support */
static bool pdp_has_v4(struct pdp_t *pdp)
{
@@ -712,6 +736,7 @@ static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
struct tun_t *tun = (struct tun_t *)pdp->ipif;
struct apn_ctx *apn = tun->priv;
+ struct ippoolm_t *peer;
OSMO_ASSERT(tun);
OSMO_ASSERT(apn);
@@ -720,11 +745,25 @@ static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
switch (iph->version) {
case 6:
+ peer = pdp_get_peer_ipv(pdp, true);
+ if (!peer) {
+ LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv6 with unassigned EUA: %s\n",
+ osmo_hexdump(pack, len));
+ return -1;
+ }
+
/* 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);
+ return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6,
+ &apn->v6_lladdr, pack, len);
break;
case 4:
+ peer = pdp_get_peer_ipv(pdp, false);
+ if (!peer) {
+ LOGPPDP(LOGL_ERROR, pdp, "Packet from MS IPv4 with unassigned EUA: %s\n",
+ osmo_hexdump(pack, len));
+ return -1;
+ }
break;
default:
LOGPPDP(LOGL_ERROR, pdp, "Packet from MS is neither IPv4 nor IPv6: %s\n",
diff --git a/ggsn/icmpv6.c b/ggsn/icmpv6.c
index 6564a54..b7b97eb 100644
--- a/ggsn/icmpv6.c
+++ b/ggsn/icmpv6.c
@@ -180,22 +180,15 @@ static bool icmpv6_validate_router_solicit(const uint8_t *pack, unsigned len)
}
/* 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 *own_ll_addr,
+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,
const uint8_t *pack, unsigned len)
{
- struct ippoolm_t *member;
const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
const struct icmpv6_hdr *ic6h = (struct icmpv6_hdr *) (pack + sizeof(*ip6h));
struct msgb *msg;
- OSMO_ASSERT(pdp);
-
- member = pdp->peer[0];
- OSMO_ASSERT(member);
- if (member->addr.len == sizeof(struct in_addr)) /* ipv4v6 context */
- member = pdp->peer[1];
- OSMO_ASSERT(member);
-
if (len < sizeof(*ip6h)) {
LOGP(DICMP6, LOGL_NOTICE, "Packet too short: %u bytes\n", len);
return -1;
@@ -226,7 +219,7 @@ int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_a
/* 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, &member->addr.v6);
+ msg = icmpv6_construct_ra(own_ll_addr, &ip6h->ip6_src, pdp_prefix);
/* Send the constructed RA to the MS */
gtp_data_req(gsn, pdp, msgb_data(msg), msgb_length(msg));
msgb_free(msg);
diff --git a/ggsn/icmpv6.h b/ggsn/icmpv6.h
index b6eec63..bf91e27 100644
--- a/ggsn/icmpv6.h
+++ b/ggsn/icmpv6.h
@@ -3,5 +3,7 @@
#include "../gtp/gtp.h"
#include "../gtp/pdp.h"
-int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, const struct in6_addr *own_ll_addr,
+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,
const uint8_t *pack, unsigned len);