[SMF] Fix router advertisement as per rfc 4861 (#1291)

As per RFC 4861 Router advertisement message
format, Source Address MUST be the link-local address
assigned to the interface from which this message is sent.

Since SMF was not sending it as per RFC, certain
phones were not completing the procedure of stateless
IPv6 address autoconfiguration mentioned in
3GPP TS 23.401 version 15.12.0 Release 15, section 5.3.1.2.2
This commit is contained in:
Supreeth Herle 2021-12-17 07:08:37 +05:30 committed by GitHub
parent 9b40fe25ff
commit 232c387276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 4 deletions

View File

@ -297,6 +297,43 @@ ogs_sockaddr_t *ogs_link_local_addr_by_dev(const char *dev)
return NULL;
}
ogs_sockaddr_t *ogs_link_local_addr_by_addr(const ogs_sockaddr_t *sa)
{
#if defined(HAVE_GETIFADDRS)
struct ifaddrs *iflist, *cur;
int rc;
ogs_sockaddr_t *ifaddr;
ogs_assert(sa);
rc = getifaddrs(&iflist);
if (rc != 0) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "getifaddrs failed");
return NULL;
}
for (cur = iflist; cur != NULL; cur = cur->ifa_next) {
ifaddr = (ogs_sockaddr_t *)cur->ifa_addr;
if (cur->ifa_addr == NULL) /* may happen with ppp interfaces */
continue;
if (cur->ifa_addr->sa_family == AF_INET)
continue;
if (memcmp(&sa->sin6.sin6_addr,
&ifaddr->sin6.sin6_addr, sizeof(struct in6_addr)) == 0) {
freeifaddrs(iflist);
return ogs_link_local_addr_by_dev(cur->ifa_name);
}
}
freeifaddrs(iflist);
#endif
ogs_error("ogs_link_local_addr_by_addr() failed");
return NULL;
}
int ogs_filter_ip_version(ogs_sockaddr_t **addr,
int no_ipv4, int no_ipv6, int prefer_ipv4)
{

View File

@ -89,6 +89,7 @@ int ogs_filteraddrinfo(ogs_sockaddr_t **sa_list, int family);
int ogs_sortaddrinfo(ogs_sockaddr_t **sa_list, int family);
ogs_sockaddr_t *ogs_link_local_addr_by_dev(const char *dev);
ogs_sockaddr_t *ogs_link_local_addr_by_addr(const ogs_sockaddr_t *sa);
int ogs_filter_ip_version(ogs_sockaddr_t **addr,
int no_ipv4, int no_ipv6, int prefer_ipv4);

View File

@ -388,11 +388,15 @@ static bool check_if_router_solicit(ogs_pkbuf_t *pkbuf)
static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst)
{
int rv;
ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_ue_ip_t *ue_ip = NULL;
ogs_pfcp_subnet_t *subnet = NULL;
ogs_sockaddr_t *link_local_addr = NULL;
char ipstr[OGS_ADDRSTRLEN];
ogs_ipsubnet_t src_ipsub;
uint16_t plen = 0;
@ -408,6 +412,15 @@ static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst)
subnet = ue_ip->subnet;
ogs_assert(subnet);
/* Fetch link-local address for router advertisement */
ogs_expect_or_return(ogs_gtp_self()->gtpu_addr6);
link_local_addr = ogs_link_local_addr_by_addr(ogs_gtp_self()->gtpu_addr6);
ogs_expect_or_return(link_local_addr);
OGS_ADDR(link_local_addr, ipstr);
ogs_freeaddrinfo(link_local_addr);
rv = ogs_ipsubnet(&src_ipsub, ipstr, NULL);
ogs_expect_or_return(rv == OGS_OK);
ogs_debug(" Build Router Advertisement");
pkbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN+200);
@ -423,10 +436,6 @@ static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst)
prefix = (struct nd_opt_prefix_info *)
((uint8_t*)advert_h + sizeof *advert_h);
memcpy(src_ipsub.sub, subnet->gw.sub, sizeof(src_ipsub.sub));
src_ipsub.sub[0] =
htobe32((be32toh(src_ipsub.sub[0]) & 0x0000ffff) | 0xfe800000);
advert_h->nd_ra_type = ND_ROUTER_ADVERT;
advert_h->nd_ra_code = 0;
advert_h->nd_ra_curhoplimit = 64;