Changed Interface between NAS and GW to avoid the GW start function being called twice in IPv4v6 mode.
This commit is contained in:
parent
15cd8fc3b6
commit
5c29dba741
|
@ -36,6 +36,7 @@
|
|||
#include <string>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Setup a thread to receive packets from the TUN device
|
||||
start(GW_THREAD_PRIO);
|
||||
}
|
||||
|
||||
return(srslte::ERROR_NONE);
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue