From ac1c30012672028e1bc13eb592e83da791021ccd Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 11 Oct 2018 18:33:03 +0100 Subject: [PATCH] Adding the ability to set the interface local link IPv6 address. --- lib/include/srslte/interfaces/ue_interfaces.h | 1 + srsue/hdr/upper/gw.h | 2 + srsue/hdr/upper/nas.h | 1 + srsue/src/main.cc | 2 +- srsue/src/upper/gw.cc | 83 +++++++++++++++---- srsue/src/upper/nas.cc | 31 ++++++- srsue/test/upper/nas_test.cc | 1 + 7 files changed, 101 insertions(+), 20 deletions(-) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 2e02050c3..c6506cee5 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -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 diff --git a/srsue/hdr/upper/gw.h b/srsue/hdr/upper/gw.h index ed3ae4fbb..8ed3df64e 100644 --- a/srsue/hdr/upper/gw.h +++ b/srsue/hdr/upper/gw.h @@ -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; diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 4d915c2b2..203d3802b 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -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; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 6b6be760d..1ecdca78b 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -86,7 +86,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") ("nas.apn", bpo::value(&args->nas.apn_name)->default_value(""), "Set Access Point Name (APN) for data services") - ("nas.apn_protocol", bpo::value(&args->nas.apn_protocol)->default_value("ipv4"), "Set Access Point Name (APN) protocol for data services") + ("nas.apn_protocol", bpo::value(&args->nas.apn_protocol)->default_value(""), "Set Access Point Name (APN) protocol for data services") ("nas.user", bpo::value(&args->nas.apn_user)->default_value(""), "Username for CHAP authentication") ("nas.pass", bpo::value(&args->nas.apn_pass)->default_value(""), "Password for CHAP authentication") ("nas.force_imsi_attach", bpo::value(&args->nas.force_imsi_attach)->default_value(false), "Whether to always perform an IMSI attach") diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc index 576271b5b..305e4f1f5 100644 --- a/srsue/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -37,6 +37,11 @@ #include #include +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) diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 2b8235801..1fb91ed99 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -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") { diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index eec65c7f9..92865d705 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -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) {} };