|
|
|
@ -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);
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|