Adding the ability to set the interface local link IPv6 address.

This commit is contained in:
Pedro Alvarez 2018-10-11 18:33:03 +01:00 committed by Andre Puschmann
parent 25108e2e2b
commit ac1c300126
7 changed files with 101 additions and 20 deletions

View File

@ -105,6 +105,7 @@ 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;
};
// GW interface for RRC

View File

@ -60,6 +60,7 @@ public:
// 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);
// RRC interface
void add_mch_port(uint32_t lcid, uint32_t port);
@ -88,6 +89,7 @@ private:
bool if_up;
uint32_t current_ip_addr;
uint8_t current_if_id[8];
long ul_tput_bytes;
long dl_tput_bytes;

View File

@ -134,6 +134,7 @@ private:
bool auth_request;
uint32_t ip_addr;
uint8_t ipv6_if_id[8];
uint8_t eps_bearer_id;
uint8_t chap_id;

View File

@ -86,7 +86,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
("nas.apn", bpo::value<string>(&args->nas.apn_name)->default_value(""), "Set Access Point Name (APN) for data services")
("nas.apn_protocol", bpo::value<string>(&args->nas.apn_protocol)->default_value("ipv4"), "Set Access Point Name (APN) protocol for data services")
("nas.apn_protocol", bpo::value<string>(&args->nas.apn_protocol)->default_value(""), "Set Access Point Name (APN) protocol for data services")
("nas.user", bpo::value<string>(&args->nas.apn_user)->default_value(""), "Username for CHAP authentication")
("nas.pass", bpo::value<string>(&args->nas.apn_pass)->default_value(""), "Password for CHAP authentication")
("nas.force_imsi_attach", bpo::value<bool>(&args->nas.force_imsi_attach)->default_value(false), "Whether to always perform an IMSI attach")

View File

@ -37,6 +37,11 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
struct in6_ifreq {
struct in6_addr ifr6_addr;
__u32 ifr6_prefixlen;
unsigned int ifr6_ifindex;
};
namespace srsue {
@ -165,29 +170,14 @@ void gw::write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu)
struct in_addr dst_addr;
memcpy(&dst_addr.s_addr, &pdu->msg[16],4);
if(!if_up)
{
if (!if_up) {
gw_log->warning("TUN/TAP not up - dropping gw RX message\n");
}else{
} else {
int n = write(tun_fd, pdu->msg, pdu->N_bytes);
if(n > 0 && (pdu->N_bytes != (uint32_t)n))
{
if(n > 0 && (pdu->N_bytes != (uint32_t) n) ) {
gw_log->warning("DL TUN/TAP write failure\n");
}
}
/*
// Strip IP/UDP header
pdu->msg += 28;
pdu->N_bytes -= 28;
if(mbsfn_sock_fd) {
if(lcid > 0 && lcid < SRSLTE_N_MCH_LCIDS) {
mbsfn_sock_addr.sin_port = htons(mbsfn_ports[lcid]);
if(sendto(mbsfn_sock_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&mbsfn_sock_addr, sizeof(struct sockaddr_in))<0) {
gw_log->error("Failed to send MCH PDU to port %d\n", mbsfn_ports[lcid]);
}
}
}*/
}
pool->deallocate(pdu);
}
@ -241,6 +231,63 @@ srslte::error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str)
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)

View File

@ -653,6 +653,35 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
if (gw->setup_if_addr(ip_addr, 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){
memcpy(ipv6_if_id, act_def_eps_bearer_context_req.pdn_addr.addr, 8);
nas_log->info("Network attach successful. APN: %s, IPv6 interface id: %02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
act_def_eps_bearer_context_req.apn.apn,
act_def_eps_bearer_context_req.pdn_addr.addr[0],
act_def_eps_bearer_context_req.pdn_addr.addr[1],
act_def_eps_bearer_context_req.pdn_addr.addr[2],
act_def_eps_bearer_context_req.pdn_addr.addr[3],
act_def_eps_bearer_context_req.pdn_addr.addr[4],
act_def_eps_bearer_context_req.pdn_addr.addr[5],
act_def_eps_bearer_context_req.pdn_addr.addr[6],
act_def_eps_bearer_context_req.pdn_addr.addr[7]);
nas_log->console("Network attach successful. IPv6 interface Id: %02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
act_def_eps_bearer_context_req.pdn_addr.addr[0],
act_def_eps_bearer_context_req.pdn_addr.addr[1],
act_def_eps_bearer_context_req.pdn_addr.addr[2],
act_def_eps_bearer_context_req.pdn_addr.addr[3],
act_def_eps_bearer_context_req.pdn_addr.addr[4],
act_def_eps_bearer_context_req.pdn_addr.addr[5],
act_def_eps_bearer_context_req.pdn_addr.addr[6],
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)) {
nas_log->error("Failed to set gateway address - %s\n", err_str);
}
pool->deallocate(pdu);
return;
} else {
nas_log->error("Not handling IPV6 or IPV4V6\n");
pool->deallocate(pdu);
@ -1128,7 +1157,7 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
pdn_con_req.apn_present = false;
//Set PDN protocol type
if (cfg.apn_protocol == "ipv4"){
if (cfg.apn_protocol == "ipv4" || cfg.apn_protocol == ""){
nas_log->console("Setting PDN protocol to IPv4\n");
pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4;
} else if (cfg.apn_protocol == "ipv6") {

View File

@ -127,6 +127,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; }
void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) {}
};