diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index c6506cee5..51821f641 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -36,6 +36,7 @@ #include #include "srslte/asn1/liblte_rrc.h" +#include "srslte/asn1/liblte_mme.h" #include "srslte/common/interfaces_common.h" #include "srslte/common/common.h" #include "srslte/common/security.h" @@ -104,8 +105,7 @@ public: class gw_interface_nas { public: - virtual srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str) = 0; - virtual srslte::error_t setup_if_addr6(uint8_t *ipv6_if_id, char *err_str) = 0; + virtual srslte::error_t setup_if_addr(uint8_t pdn_type, uint32_t ip_addr, uint8_t *ipv6_if_id, char *err_str) = 0; }; // GW interface for RRC diff --git a/srsue/hdr/upper/gw.h b/srsue/hdr/upper/gw.h index bd178b640..7ab51b962 100644 --- a/srsue/hdr/upper/gw.h +++ b/srsue/hdr/upper/gw.h @@ -58,8 +58,7 @@ public: void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu); // NAS interface - srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str); - srslte::error_t setup_if_addr6(uint8_t *ipv6_if_id, char *err_str); + srslte::error_t setup_if_addr(uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_addr, char *err_str); // RRC interface void add_mch_port(uint32_t lcid, uint32_t port); @@ -96,6 +95,8 @@ private: void run_thread(); srslte::error_t init_if(char *err_str); + srslte::error_t setup_if_addr4(uint32_t ip_addr, char *err_str); + srslte::error_t setup_if_addr6(uint8_t *ipv6_if_id, char *err_str); bool find_ipv6_addr(struct in6_addr *in6_out); void del_ipv6_addr(struct in6_addr *in6p); diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc index b6a620462..f121e5bea 100644 --- a/srsue/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -181,168 +181,27 @@ void gw::write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu) /******************************************************************************* NAS interface *******************************************************************************/ -srslte::error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) +srslte::error_t gw::setup_if_addr(uint8_t pdn_type, uint32_t ip_addr, uint8_t *ipv6_if_addr, char *err_str) { - if (ip_addr != current_ip_addr) { - if(!if_up) - { - if(init_if(err_str)) - { - gw_log->error("init_if failed\n"); - return(srslte::ERROR_CANT_START); - } - } - - // Setup the IP address - sock = socket(AF_INET, SOCK_DGRAM, 0); - ifr.ifr_addr.sa_family = AF_INET; - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr); - if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set socket address: %s\n", err_str); - close(tun_fd); - return(srslte::ERROR_CANT_START); + srslte::error_t err; + if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV4 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){ + err = setup_if_addr4(ip_addr, err_str); + if(err!= srslte::ERROR_NONE){ + return err; } - ifr.ifr_netmask.sa_family = AF_INET; - const char *mask = "255.255.255.0"; - if (!default_netmask) { - mask = netmask.c_str(); - } - ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr(mask); - if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set socket netmask: %s\n", err_str); - close(tun_fd); - return(srslte::ERROR_CANT_START); - } - - current_ip_addr = ip_addr; - - // Setup a thread to receive packets from the TUN device - start(GW_THREAD_PRIO); } - - return(srslte::ERROR_NONE); -} - -srslte::error_t gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str) -{ - struct sockaddr_in6 sai; - struct in6_ifreq ifr6; - bool match = true; - - for (int i=0; i<8; i++){ - if(ipv6_if_id[i] != current_if_id[i]){ - match = false; - break; - } - } - - if (!match) { - if (!if_up) { - if( init_if(err_str) ) { - gw_log->error("init_if failed\n"); - return(srslte::ERROR_CANT_START); - } - } - - // Setup the IP address - sock = socket(AF_INET6, SOCK_DGRAM, 0); - ifr.ifr_addr.sa_family = AF_INET6; - - if(inet_pton(AF_INET6, "fe80::", (void *)&sai.sin6_addr) <= 0) { - gw_log->error("Bad address\n"); - return srslte::ERROR_CANT_START; - } - - memcpy(&sai.sin6_addr.s6_addr[8], ipv6_if_id, 8); - if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) { - perror("SIOGIFINDEX"); - return srslte::ERROR_CANT_START; - } - ifr6.ifr6_ifindex = ifr.ifr_ifindex; - ifr6.ifr6_prefixlen = 64; - memcpy((char *) &ifr6.ifr6_addr, (char *) &sai.sin6_addr, - sizeof(struct in6_addr)); - - if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) { - err_str = strerror(errno); - gw_log->error("Could not set IPv6 Link local address. Error %s\n", err_str); - return srslte::ERROR_CANT_START; - } - - for (int i=0; i<8; i++){ - current_if_id[i] = ipv6_if_id[i]; + if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV6 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){ + err = setup_if_addr6(ipv6_if_addr, err_str); + if(err!= srslte::ERROR_NONE){ + return err; } - - // Setup a thread to receive packets from the TUN device - start(GW_THREAD_PRIO); } - - return(srslte::ERROR_NONE); + + // Setup a thread to receive packets from the TUN device + start(GW_THREAD_PRIO); + return srslte::ERROR_NONE; } -srslte::error_t gw::init_if(char *err_str) -{ - if(if_up) - { - return(srslte::ERROR_ALREADY_STARTED); - } - - // Construct the TUN device - tun_fd = open("/dev/net/tun", O_RDWR); - gw_log->info("TUN file descriptor = %d\n", tun_fd); - if(0 > tun_fd) - { - err_str = strerror(errno); - gw_log->debug("Failed to open TUN device: %s\n", err_str); - return(srslte::ERROR_CANT_START); - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - strncpy(ifr.ifr_ifrn.ifrn_name, tundevname.c_str(), std::min(tundevname.length(), (size_t)(IFNAMSIZ-1))); - ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0; - if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set TUN device name: %s\n", err_str); - close(tun_fd); - return(srslte::ERROR_CANT_START); - } - - // Bring up the interface - sock = socket(AF_INET, SOCK_DGRAM, 0); - if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to bring up socket: %s\n", err_str); - close(tun_fd); - return(srslte::ERROR_CANT_START); - } - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set socket flags: %s\n", err_str); - close(tun_fd); - return(srslte::ERROR_CANT_START); - } - - // Delete link-local IPv6 address. - struct in6_addr in6p; - char addr_str[INET6_ADDRSTRLEN]; - if(find_ipv6_addr(&in6p)){ - gw_log->debug("Found link-local IPv6 address: %s\n",inet_ntop(AF_INET6, &in6p, addr_str,INET6_ADDRSTRLEN) ); - del_ipv6_addr(&in6p); - } else { - gw_log->warning("Could not find link-local IPv6 address.\n"); - } - if_up = true; - - return(srslte::ERROR_NONE); -} /******************************************************************************* @@ -355,8 +214,6 @@ void gw::add_mch_port(uint32_t lcid, uint32_t port) } } - - /********************/ /* GW Receive */ /********************/ @@ -453,9 +310,156 @@ void gw::run_thread() gw_log->info("GW IP receiver thread exiting.\n"); } -/********************/ -/* NETLINK Helpers */ -/********************/ +/**************************/ +/* TUN Interface Helpers */ +/**************************/ +srslte::error_t gw::init_if(char *err_str) +{ + if (if_up) { + return (srslte::ERROR_ALREADY_STARTED); + } + + // Construct the TUN device + tun_fd = open("/dev/net/tun", O_RDWR); + gw_log->info("TUN file descriptor = %d\n", tun_fd); + if (0 > tun_fd) { + err_str = strerror(errno); + gw_log->debug("Failed to open TUN device: %s\n", err_str); + return (srslte::ERROR_CANT_START); + } + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr.ifr_ifrn.ifrn_name, tundevname.c_str(), std::min(tundevname.length(), (size_t)(IFNAMSIZ-1))); + ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0; + if (0 > ioctl(tun_fd, TUNSETIFF, &ifr)) { + err_str = strerror(errno); + gw_log->debug("Failed to set TUN device name: %s\n", err_str); + close(tun_fd); + return (srslte::ERROR_CANT_START); + } + + // Bring up the interface + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) { + err_str = strerror(errno); + gw_log->debug("Failed to bring up socket: %s\n", err_str); + close(tun_fd); + return (srslte::ERROR_CANT_START); + } + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) { + err_str = strerror(errno); + gw_log->debug("Failed to set socket flags: %s\n", err_str); + close(tun_fd); + return (srslte::ERROR_CANT_START); + } + + // Delete link-local IPv6 address. + struct in6_addr in6p; + char addr_str[INET6_ADDRSTRLEN]; + if(find_ipv6_addr(&in6p)){ + gw_log->debug("Found link-local IPv6 address: %s\n",inet_ntop(AF_INET6, &in6p, addr_str,INET6_ADDRSTRLEN) ); + del_ipv6_addr(&in6p); + } else { + gw_log->warning("Could not find link-local IPv6 address.\n"); + } + if_up = true; + + return(srslte::ERROR_NONE); +} + +srslte::error_t gw::setup_if_addr4(uint32_t ip_addr, char *err_str) +{ + if (ip_addr != current_ip_addr) { + if (!if_up) { + if (init_if(err_str)) { + gw_log->error("init_if failed\n"); + return (srslte::ERROR_CANT_START); + } + } + + // Setup the IP address + sock = socket(AF_INET, SOCK_DGRAM, 0); + ifr.ifr_addr.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr); + if (0 > ioctl(sock, SIOCSIFADDR, &ifr)) { + err_str = strerror(errno); + gw_log->debug("Failed to set socket address: %s\n", err_str); + close(tun_fd); + return (srslte::ERROR_CANT_START); + } + ifr.ifr_netmask.sa_family = AF_INET; + const char *mask = "255.255.255.0"; + if (!default_netmask) { + mask = netmask.c_str(); + } + ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr(mask); + if (0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) { + err_str = strerror(errno); + gw_log->debug("Failed to set socket netmask: %s\n", err_str); + close(tun_fd); + return (srslte::ERROR_CANT_START); + } + current_ip_addr = ip_addr; + } + return(srslte::ERROR_NONE); +} + +srslte::error_t gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str) +{ + struct sockaddr_in6 sai; + struct in6_ifreq ifr6; + bool match = true; + + for (int i=0; i<8; i++){ + if(ipv6_if_id[i] != current_if_id[i]){ + match = false; + break; + } + } + + if (!match) { + if (!if_up) { + if( init_if(err_str) ) { + gw_log->error("init_if failed\n"); + return(srslte::ERROR_CANT_START); + } + } + + // Setup the IP address + sock = socket(AF_INET6, SOCK_DGRAM, 0); + ifr.ifr_addr.sa_family = AF_INET6; + + if(inet_pton(AF_INET6, "fe80::", (void *)&sai.sin6_addr) <= 0) { + gw_log->error("Bad address\n"); + return srslte::ERROR_CANT_START; + } + + memcpy(&sai.sin6_addr.s6_addr[8], ipv6_if_id, 8); + if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) { + perror("SIOGIFINDEX"); + return srslte::ERROR_CANT_START; + } + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = 64; + memcpy((char *) &ifr6.ifr6_addr, (char *) &sai.sin6_addr, + sizeof(struct in6_addr)); + + if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) { + err_str = strerror(errno); + gw_log->error("Could not set IPv6 Link local address. Error %s\n", err_str); + return srslte::ERROR_CANT_START; + } + + for (int i=0; i<8; i++){ + current_if_id[i] = ipv6_if_id[i]; + } + } + + return(srslte::ERROR_NONE); +} + bool gw::find_ipv6_addr(struct in6_addr *in6_out) { int status, rtattrlen, fd = -1; diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 0304ab5e4..658a8a920 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -662,7 +662,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { // Setup GW char *err_str = NULL; - if (gw->setup_if_addr(ip_addr, err_str)) { + if (gw->setup_if_addr(LIBLTE_MME_PDN_TYPE_IPV4, ip_addr, NULL, err_str)) { nas_log->error("Failed to set gateway address - %s\n", err_str); } } else if (LIBLTE_MME_PDN_TYPE_IPV6 == act_def_eps_bearer_context_req.pdn_addr.pdn_type){ @@ -689,7 +689,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { act_def_eps_bearer_context_req.pdn_addr.addr[7]); // Setup GW char *err_str = NULL; - if (gw->setup_if_addr6(ipv6_if_id, err_str)) { + if (gw->setup_if_addr(LIBLTE_MME_PDN_TYPE_IPV6, 0, ipv6_if_id, err_str)) { nas_log->error("Failed to set gateway address - %s\n", err_str); } } else if (LIBLTE_MME_PDN_TYPE_IPV4V6 == act_def_eps_bearer_context_req.pdn_addr.pdn_type){ @@ -734,10 +734,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { act_def_eps_bearer_context_req.pdn_addr.addr[11]); char *err_str = NULL; - if (gw->setup_if_addr(ip_addr, err_str)) { - nas_log->error("Failed to set gateway address - %s\n", err_str); - } - if (gw->setup_if_addr6(ipv6_if_id, err_str)) { + if (gw->setup_if_addr(LIBLTE_MME_PDN_TYPE_IPV4V6, ip_addr, ipv6_if_id, err_str)) { nas_log->error("Failed to set gateway address - %s\n", err_str); } } else { diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index 92865d705..486f0a739 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -126,8 +126,7 @@ private: class gw_dummy : public gw_interface_nas, public gw_interface_pdcp { - error_t setup_if_addr(uint32_t ip_addr, char *err_str) { return ERROR_NONE; } - error_t setup_if_addr6(uint8_t *ipv6_if_id, char *err_str) { return ERROR_NONE; } + error_t setup_if_addr(uint8_t pdn_type, uint32_t ip_addr, uint8_t *ipv6_if_id, char *err_str) { return ERROR_NONE; } void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {} void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) {} };