diff --git a/openair-cn/SCTP/sctp_eNB_task.c b/openair-cn/SCTP/sctp_eNB_task.c index 4bab71d50b313e40675c01ca5be02418e16ba350..4455d0208efc604278d40db4f557133d5acdc500 100644 --- a/openair-cn/SCTP/sctp_eNB_task.c +++ b/openair-cn/SCTP/sctp_eNB_task.c @@ -35,6 +35,11 @@ #include <sys/types.h> #include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <ifaddrs.h> +#include <sys/ioctl.h> +#include <net/if.h> #include <netinet/in.h> #include <netinet/sctp.h> @@ -120,14 +125,19 @@ void sctp_handle_new_association_req( const task_id_t requestor, const sctp_new_association_req_t * const sctp_new_association_req_p) { - int sd; - int32_t assoc_id; + int sd; + int32_t assoc_id; - struct sctp_event_subscribe events; + struct sctp_event_subscribe events; - struct sctp_cnx_list_elm_s *sctp_cnx = NULL; - enum sctp_connection_type_e connection_type = SCTP_TYPE_CLIENT; + struct sctp_cnx_list_elm_s *sctp_cnx = NULL; + enum sctp_connection_type_e connection_type = SCTP_TYPE_CLIENT; + struct ifreq ifr; + struct ifaddrs *ifaddr, *ifa; + int family, s; + struct in_addr in; + struct in6_addr in6; /* Prepare a new SCTP association as requested by upper layer and try to connect * to remote host. */ @@ -162,6 +172,63 @@ void sctp_handle_new_association_req( return; } + // Bind to device ... or we could bind to address also + if (getifaddrs(&ifaddr) == -1) { + SCTP_ERROR("getifaddrs failed: %s\n", strerror(errno)); + close(sd); + } + /* Walk through linked list, maintaining head pointer so we + can free list later */ + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + family = ifa->ifa_addr->sa_family; + + /* For an AF_INET* interface address, display the address */ + if (sctp_new_association_req_p->local_address.ipv4 && family == AF_INET) { + // compare address + s = inet_aton(sctp_new_association_req_p->local_address.ipv4_address, + &in); + if (s > 0 ) { + if (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr == in.s_addr) { + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), ifa->ifa_name); + if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) { + SCTP_ERROR("Setsockopt SOL_SOCKET failed: %s\n", + strerror(errno)); + } else { + SCTP_DEBUG("Setsockopt SOL_SOCKET socket bound to : %s\n", + ifa->ifa_name); + } + break; + } + } + } else if (sctp_new_association_req_p->local_address.ipv6 && family == AF_INET6) { + // compare address + s = inet_pton(AF_INET6, + sctp_new_association_req_p->local_address.ipv6_address, + &in6); + if (s == 1 ) { + if (memcmp(&((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr, + &in6, sizeof(in6)) == 0) { + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), ifa->ifa_name); + if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) { + SCTP_ERROR("Setsockopt SOL_SOCKET failed: %s\n", + strerror(errno)); + } else { + SCTP_DEBUG("Setsockopt SOL_SOCKET socket bound to : %s\n", + ifa->ifa_name); + } + break; + } + } + } + } + + freeifaddrs(ifaddr); + /* Mark the socket as non-blocking */ if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0) { SCTP_ERROR("fcntl F_SETFL O_NONBLOCK failed: %s\n",