forked from acouzens/open5gs
[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:
parent
9b40fe25ff
commit
232c387276
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue