diff --git a/srsue/hdr/upper/gw.h b/srsue/hdr/upper/gw.h index 8ed3df64e..bd178b640 100644 --- a/srsue/hdr/upper/gw.h +++ b/srsue/hdr/upper/gw.h @@ -27,6 +27,7 @@ #ifndef SRSUE_GW_H #define SRSUE_GW_H +#include #include "srslte/common/buffer_pool.h" #include "srslte/common/log.h" #include "srslte/common/common.h" @@ -35,8 +36,6 @@ #include "srslte/common/threads.h" #include "gw_metrics.h" -#include - namespace srsue { class gw @@ -97,6 +96,8 @@ private: void run_thread(); srslte::error_t init_if(char *err_str); + bool find_ipv6_addr(struct in6_addr *in6_out); + void del_ipv6_addr(struct in6_addr *in6p); // MBSFN int mbsfn_sock_fd; // Sink UDP socket file descriptor diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc index c93310de5..a7e2df161 100644 --- a/srsue/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -33,10 +33,11 @@ #include #include #include -#include #include #include #include +#include +#include namespace srsue { @@ -329,6 +330,12 @@ srslte::error_t gw::init_if(char *err_str) 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) ); + } if_up = true; return(srslte::ERROR_NONE); @@ -443,4 +450,117 @@ void gw::run_thread() gw_log->info("GW IP receiver thread exiting.\n"); } +/********************/ +/* NETLINK Helpers */ +/********************/ +bool gw::find_ipv6_addr(struct in6_addr *in6_out) +{ + int status, rtattrlen, fd = -1; + unsigned int if_index; + struct rtattr *rta, *rtatp; + struct nlmsghdr *nlmp; + struct ifaddrmsg *rtmp; + struct in6_addr *in6p; + char buf[2048]; + struct { + struct nlmsghdr n; + struct ifaddrmsg r; + char buf[1024]; + } req; + + gw_log->debug("Trying to obtain IPv6 addr of %s interface\n", tundevname.c_str()); + + //Get Interface Index + if_index = if_nametoindex(tundevname.c_str()); + if(if_index == 0){ + gw_log->error("Could not find interface index\n"); + goto err_out; + } + + // Open NETLINK socket + fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (fd < 0) { + gw_log->error("Error openning NETLINK socket -- %s\n", strerror(errno)); + goto err_out; + } + + // We use RTM_GETADDR to get the ip address from the kernel + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH; + req.n.nlmsg_type = RTM_GETADDR; + + // AF_INET6 is used to signify the kernel to fetch only ipv6 entires. + req.r.ifa_family = AF_INET6; + + // Fill up all the attributes for the rtnetlink header. + // The lenght is important. 16 signifies we are requesting IPv6 addresses + rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len)); + rta->rta_len = RTA_LENGTH(16); + + // Time to send and recv the message from kernel + status = send(fd, &req, req.n.nlmsg_len, 0); + if (status < 0) { + gw_log->error("Error sending NETLINK message to kernel -- %s", strerror(errno)); + goto err_out; + } + + status = recv(fd, buf, sizeof(buf), 0); + if (status < 0) { + gw_log->error("Error receiving from NETLINK socket\n"); + goto err_out; + } + + if (status == 0) { + printf("Nothing received from NETLINK Socket\n"); + goto err_out; + } + + // Parse the reply + for (nlmp = (struct nlmsghdr *)buf; (size_t)status > sizeof(*nlmp);) { + int len = nlmp->nlmsg_len; + int req_len = len - sizeof(*nlmp); + + if (req_len < 0 || len > status) { + gw_log->error("Error in length of NETLINK message\n"); + goto err_out; + } + + if (!NLMSG_OK(nlmp, status)) { + gw_log->error("NLMSG not OK in NETLINK reply\n"); + goto err_out; + } + + rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp); + rtatp = (struct rtattr *)IFA_RTA(rtmp); + + rtattrlen = IFA_PAYLOAD(nlmp); + for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) { + // We are looking IFA_ADDRESS rt_attribute type. + // For more info on the different types see man(7) rtnetlink. + if (rtatp->rta_type == IFA_ADDRESS) { + in6p = (struct in6_addr *)RTA_DATA(rtatp); + if (if_index == rtmp->ifa_index) { + for (int i = 0; i < 16; i++) { + in6_out->s6_addr16[i] = in6p->s6_addr16[i]; + } + goto out; + } + } + } + status -= NLMSG_ALIGN(len); + nlmp = (struct nlmsghdr *)((char *)nlmp + NLMSG_ALIGN(len)); + } + +err_out: + if (fd > 0) { + close(fd); + } + return false; +out: + close(fd); + return true; +} + +void gw::del_ipv6_addr(struct in6_addr *in6p) {} } // namespace srsue diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 8050906d8..0533f11e6 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -770,7 +770,6 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { nas_log->info("Sending Attach Complete\n"); rrc->write_sdu(lcid, pdu); ctxt.tx_count++; - } else { nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result); state = EMM_STATE_DEREGISTERED; @@ -1173,8 +1172,12 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { } else if (cfg.apn_protocol == "ipv6") { nas_log->console("Setting PDN protocol to IPv6\n"); pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV6; + } else if (cfg.apn_protocol == "ipv4v6") { + nas_log->console("Setting PDN protocol to IPv4v6\n"); + pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4V6; } else { nas_log->warning("Unsupported PDN prtocol. Defaulting to IPv4\n"); + nas_log->console("Unsupported PDN prtocol: %s. Defaulting to IPv4\n", cfg.apn_protocol.c_str()); pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4; }