ggsn: Support announcing APN MTU over ICMPv6 RA

Related: OS#6298
Related: SYS#7122
Change-Id: I8bb67915dd5f39ad9ffb80e5aaf9af1e7d70c96c
This commit is contained in:
Pau Espin Pedrol
2024-10-18 20:22:54 +02:00
parent 6041554cef
commit 41bec9529f
3 changed files with 33 additions and 3 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);