diff --git a/lib/core/ogs-sockaddr.c b/lib/core/ogs-sockaddr.c index 28c007d64..b44031100 100644 --- a/lib/core/ogs-sockaddr.c +++ b/lib/core/ogs-sockaddr.c @@ -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) { diff --git a/lib/core/ogs-sockaddr.h b/lib/core/ogs-sockaddr.h index 65523a801..f0b40a081 100644 --- a/lib/core/ogs-sockaddr.h +++ b/lib/core/ogs-sockaddr.h @@ -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); diff --git a/src/smf/gtp-path.c b/src/smf/gtp-path.c index 862690a32..19e5b1901 100644 --- a/src/smf/gtp-path.c +++ b/src/smf/gtp-path.c @@ -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;