From ae5702d014c2f26f0d7e6f6f77393b25475d3831 Mon Sep 17 00:00:00 2001 From: Robert Schmidt <robert.schmidt@openairinterface.org> Date: Mon, 15 Jul 2024 15:49:21 +0200 Subject: [PATCH] nas_config(): change API to handle both IPv4 and IPv6 Implement handling of IPv4 and IPv6 (on the same interface) in nas_config(). --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 10 +-- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 4 +- openair2/RRC/LTE/rrc_UE.c | 2 +- openair2/RRC/LTE/rrc_eNB.c | 2 +- openair2/RRC/NAS/nas_config.c | 71 +++++++++++++++---- openair2/RRC/NAS/nas_config.h | 6 +- .../ESM/MSG/PduSessionEstablishmentAccept.c | 2 +- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 4 +- 8 files changed, 72 insertions(+), 29 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 3a64bbf68ef..122bd147942 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -2300,22 +2300,22 @@ uint64_t pdcp_module_init( uint64_t pdcp_optmask, int id) { int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF) ? MAX_MOBILES_PER_ENB : 1; netlink_init_tun("oaitun_ue", num_if, id); if (IS_SOFTMODEM_NOS1) - nas_config(1, "10.0.1.2", "oaitun_ue"); + nas_config(1, "10.0.1.2", NULL, "oaitun_ue"); netlink_init_mbms_tun("oaitun_uem", id + 1); - nas_config(1, "10.0.2.2", "oaitun_uem"); + nas_config(1, "10.0.2.2", NULL, "oaitun_uem"); LOG_I(PDCP, "UE pdcp will use tun interface\n"); } else if (ENB_NAS_USE_TUN) { netlink_init_tun("oaitun_enb", 1, 0); - nas_config(1, "10.0.1.1", "oaitun_enb"); + nas_config(1, "10.0.1.1", NULL, "oaitun_enb"); if (pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT) { netlink_init_mbms_tun("oaitun_enm", 1); - nas_config(1, "10.0.2.1", "oaitun_enm"); + nas_config(1, "10.0.2.1", NULL, "oaitun_enm"); LOG_I(PDCP, "ENB pdcp will use mbms tun interface\n"); } LOG_I(PDCP, "ENB pdcp will use tun interface\n"); } else if (pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT) { netlink_init_mbms_tun("oaitun_enm", 0); - nas_config(1, "10.0.2.1", "oaitun_enm"); + nas_config(1, "10.0.2.1", NULL, "oaitun_enm"); LOG_I(PDCP, "ENB pdcp will use mbms tun interface\n"); } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 5146cf3cee8..051999ad9d3 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -618,7 +618,7 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id) netlink_init_tun(ifprefix, num_if, id); if (IS_SOFTMODEM_NOS1) { const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3"; - nas_config(1, ip, ifprefix); + nas_config(1, ip, NULL, ifprefix); set_qfi_pduid(7, 10); } LOG_I(PDCP, "UE pdcp will use tun interface\n"); @@ -626,7 +626,7 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id) } else if (ENB_NAS_USE_TUN) { char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; netlink_init_tun(ifprefix, 1, id); - nas_config(1, "10.0.1.1", ifprefix); + nas_config(1, "10.0.1.1", NULL, ifprefix); LOG_I(PDCP, "ENB pdcp will use tun interface\n"); start_pdcp_tun_enb(); } diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index d125892d83b..1d1de490bb3 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -771,7 +771,7 @@ rrc_ue_establish_drb( "10.0.%d.%d", UE_NAS_USE_TUN ? 1 : (ip_addr_offset3 + ue_mod_idP + 1), ip_addr_offset4 + ue_mod_idP + 1); - oip_ifup = nas_config(ip_addr_offset3 + ue_mod_idP + 1, ip, "oaitun_oip"); + oip_ifup = nas_config(ip_addr_offset3 + ue_mod_idP + 1, ip, NULL, "oaitun_oip"); if (oip_ifup == 0 && (!UE_NAS_USE_TUN)) { // interface is up --> send a config the DRB LOG_I(OIP,"[UE %d] Config the ue net interface %d to send/receive pkt on DRB %ld to/from the protocol stack\n", diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index cda6ac20130..1b42985bde2 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -5257,7 +5257,7 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP->module_id); char ip[20]; snprintf(ip, sizeof(ip), "10.0.%d.%d", ctxt_pP->module_id + 1, ctxt_pP->module_id + 1); - oip_ifup = nas_config(ctxt_pP->module_id, ip, "oaitun_oai"); + oip_ifup = nas_config(ctxt_pP->module_id, ip, NULL, "oaitun_oai"); if (oip_ifup == 0) { // interface is up --> send a config the DRB module_id_t ue_module_id; diff --git a/openair2/RRC/NAS/nas_config.c b/openair2/RRC/NAS/nas_config.c index 5a437febf16..f744c065c5a 100644 --- a/openair2/RRC/NAS/nas_config.c +++ b/openair2/RRC/NAS/nas_config.c @@ -26,6 +26,7 @@ #include <net/if.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <linux/ipv6.h> #include "nas_config.h" #include "common/utils/LOG/log.h" @@ -40,17 +41,42 @@ * (set flags) * \return true on success, false otherwise */ -static bool setInterfaceParameter(int sock_fd, const char *ifn, const char *if_addr, int operation) +static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const char *if_addr, int operation) { + DevAssert(af == AF_INET || af == AF_INET6); struct ifreq ifr = {0}; strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name)); + struct in6_ifreq ifr6 = {0}; + + void *ioctl_opt = NULL; + if (af == AF_INET) { + struct sockaddr_in addr = {.sin_family = AF_INET}; + int ret = inet_pton(af, if_addr, &addr.sin_addr); + if (ret != 1) { + LOG_E(OIP, "inet_pton(): cannot convert %s to IPv4 network address\n", if_addr); + return false; + } + memcpy(&ifr.ifr_ifru.ifru_addr,&addr,sizeof(struct sockaddr_in)); + ioctl_opt = 𝔦 + } else { + struct sockaddr_in6 addr6 = {.sin6_family = AF_INET6}; + int ret = inet_pton(af, if_addr, &addr6.sin6_addr); + if (ret != 1) { + LOG_E(OIP, "inet_pton(): cannot convert %s to IPv6 network address\n", if_addr); + return false; + } + memcpy(&ifr6.ifr6_addr, &addr6.sin6_addr, sizeof(struct in6_addr)); + // we need to get the if index to put it into ifr6 + if (ioctl(sock_fd, SIOGIFINDEX, &ifr) < 0) { + LOG_E(OIP, "ioctl() failed: errno %d, %s\n", errno, strerror(errno)); + return false; + } + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = 64; + ioctl_opt = &ifr6; + } - struct sockaddr_in addr = {.sin_family = AF_INET}; - inet_aton(if_addr, &addr.sin_addr); - //inet_pton(AF_INET6 or AF_INET) - memcpy(&ifr.ifr_ifru.ifru_addr,&addr,sizeof(struct sockaddr_in)); - - bool success = ioctl(sock_fd,operation,&ifr) == 0; + bool success = ioctl(sock_fd, operation, ioctl_opt) == 0; if (!success) LOG_E(OIP, "Setting operation %d for %s: ioctl call failed: %d, %s\n", operation, ifn, errno, strerror(errno)); return success; @@ -80,11 +106,13 @@ static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_ } // non blocking full configuration of the interface (address, and the two lest octets of the address) -bool nas_config(int interface_id, const char *ip, const char *ifpref) +bool nas_config(int interface_id, const char *ipv4, const char *ipv6, const char *ifpref) { char interfaceName[IFNAMSIZ]; snprintf(interfaceName, sizeof(interfaceName), "%s%d", ifpref, interface_id); + AssertFatal(ipv4 != NULL || ipv6 != NULL, "need to have IP address, but none given\n"); + int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) { LOG_E(UTIL, "Failed creating socket for interface management: %d, %s\n", errno, strerror(errno)); @@ -92,18 +120,33 @@ bool nas_config(int interface_id, const char *ip, const char *ifpref) } change_interface_state(sock_fd, interfaceName, INTERFACE_DOWN); - bool success = setInterfaceParameter(sock_fd, interfaceName, ip, SIOCSIFADDR); - // set the machine network mask - if (success) - success = setInterfaceParameter(sock_fd, interfaceName, "255.255.255.0", SIOCSIFNETMASK); + bool success = true; + if (ipv4 != NULL) + success = setInterfaceParameter(sock_fd, interfaceName, AF_INET, ipv4, SIOCSIFADDR); + // set the machine network mask for IPv4 + if (success && ipv4 != NULL) + success = setInterfaceParameter(sock_fd, interfaceName, AF_INET, "255.255.255.0", SIOCSIFNETMASK); + + if (ipv6 != NULL) { + // for setting the IPv6 address, we need an IPv6 socket. For setting IPv4, + // we need an IPv4 socket. So do all operations using IPv4 socket, except + // for setting the IPv6 + int sock_fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock_fd < 0) { + LOG_E(UTIL, "Failed creating socket for interface management: %d, %s\n", errno, strerror(errno)); + success = false; + } + success = success && setInterfaceParameter(sock_fd, interfaceName, AF_INET6, ipv6, SIOCSIFADDR); + close(sock_fd); + } if (success) success = change_interface_state(sock_fd, interfaceName, INTERFACE_UP); if (success) - LOG_I(OIP, "Interface %s successfully configured, ip address %s\n", interfaceName, ip); + LOG_I(OIP, "Interface %s successfully configured, IPv4 %s, IPv6 %s\n", interfaceName, ipv4, ipv6); else - LOG_E(OIP, "Interface %s couldn't be configured (ip address %s)\n", interfaceName, ip); + LOG_E(OIP, "Interface %s couldn't be configured (IPv4 %s, IPv6 %s)\n", interfaceName, ipv4, ipv6); close(sock_fd); return success; diff --git a/openair2/RRC/NAS/nas_config.h b/openair2/RRC/NAS/nas_config.h index 0db23c2946f..f937b6ccf54 100644 --- a/openair2/RRC/NAS/nas_config.h +++ b/openair2/RRC/NAS/nas_config.h @@ -23,7 +23,6 @@ #define NAS_CONFIG_H_ #include <stdbool.h> -#include <netinet/in.h> /*! \fn int nas_config(char*, int, int) * \brief This function initializes the nasmesh interface using the basic values, @@ -31,14 +30,15 @@ * ones * \param[in] interface_id number of this interface, prepended after interface * name - * \param[in] ip IPv4 address of this interface as a string + * \param[in] ipv4 IPv4 address of this interface as a string + * \param[in] ipv6 IPv6 address of this interface as a string * \param[in] ifprefix interface name prefix to which an interface number will * be appended * \return true on success, otherwise false * \note * @ingroup _nas */ -bool nas_config(int interface_id, const char *ip, const char *ifprefix); +bool nas_config(int interface_id, const char *ipv4, const char *ipv6, const char *ifprefix); /*! * \brief Setup a IPv4 rule in table (interface_id - 1 + 10000) and route to diff --git a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c index 46b77efcb19..4a307039c93 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c @@ -118,7 +118,7 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_ addr->pdu_addr_oct2, addr->pdu_addr_oct3, addr->pdu_addr_oct4); - nas_config(1, ip, "oaitun_ue"); + nas_config(1, ip, NULL, "oaitun_ue"); setup_ue_ipv4_route(1, ip, "oaitun_ue"); LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received UE IP: %s\n", ip); } else { diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index b40229ef0dd..53575244fda 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -845,7 +845,7 @@ void decodeDownlinkNASTransport(as_nas_info_t *initialNasMsg, uint8_t * pdu_buff char ip[20]; sprintf(ip, "%d.%d.%d.%d", *(ip_p), *(ip_p + 1), *(ip_p + 2), *(ip_p + 3)); LOG_A(NAS, "Received PDU Session Establishment Accept\n"); - nas_config(1, ip, "oaitun_ue"); + nas_config(1, ip, NULL, "oaitun_ue"); setup_ue_ipv4_route(1, ip, "oaitun_ue"); } else { LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type); @@ -1432,7 +1432,7 @@ void *nas_nrue(void *args_p) char ip[20]; snprintf(ip, sizeof(ip), "%d.%d.%d.%d", *(ip_p), *(ip_p + 1), *(ip_p + 2), *(ip_p + 3)); LOG_I(NAS, "Received PDU Session Establishment Accept, UE IP: %s\n", ip); - nas_config(1, ip, "oaitun_ue"); + nas_config(1, ip, NULL, "oaitun_ue"); setup_ue_ipv4_route(1, ip, "oaitun_ue"); break; } -- GitLab