From 41bec9529fbf41dc5422f0f0b7d65dbd3cb0e47a Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 18 Oct 2024 20:22:54 +0200 Subject: [PATCH] ggsn: Support announcing APN MTU over ICMPv6 RA Related: OS#6298 Related: SYS#7122 Change-Id: I8bb67915dd5f39ad9ffb80e5aaf9af1e7d70c96c --- ggsn/ggsn.c | 2 +- lib/icmpv6.c | 26 ++++++++++++++++++++++++-- lib/icmpv6.h | 8 ++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 4dc0c94..19b0132 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -774,7 +774,7 @@ static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) /* daddr: all-routers multicast addr */ if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr)) return handle_router_mcast(pdp->gsn, pdp, &peer->addr.v6, - &apn->v6_lladdr, pack, len); + &apn->v6_lladdr, apn->cfg.mtu, pack, len); break; case 4: peer = pdp_get_peer_ipv(pdp, false); diff --git a/lib/icmpv6.c b/lib/icmpv6.c index b6994cd..e74fb70 100644 --- a/lib/icmpv6.c +++ b/lib/icmpv6.c @@ -94,11 +94,13 @@ struct msgb *icmpv6_construct_rs(const struct in6_addr *saddr) * \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) + 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); @@ -135,6 +137,25 @@ static struct msgb *icmpv6_construct_ra(const struct in6_addr *saddr, 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); @@ -194,6 +215,7 @@ struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned 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) { const struct ip6_hdr *ip6h = (struct ip6_hdr *)pack; @@ -230,7 +252,7 @@ int handle_router_mcast(struct gsn_t *gsn, struct pdp_t *pdp, /* 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); + msg = 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); diff --git a/lib/icmpv6.h b/lib/icmpv6.h index 5bed5c6..1040600 100644 --- a/lib/icmpv6.h +++ b/lib/icmpv6.h @@ -81,6 +81,13 @@ struct icmpv6_opt_prefix { 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); @@ -89,6 +96,7 @@ 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); struct icmpv6_radv_hdr *icmpv6_validate_router_adv(const uint8_t *pack, unsigned len);