diff options
Diffstat (limited to 'netwerk/sctp/src/user_recv_thread.c')
-rw-r--r-- | netwerk/sctp/src/user_recv_thread.c | 1566 |
1 files changed, 1566 insertions, 0 deletions
diff --git a/netwerk/sctp/src/user_recv_thread.c b/netwerk/sctp/src/user_recv_thread.c new file mode 100644 index 0000000000..66be13d749 --- /dev/null +++ b/netwerk/sctp/src/user_recv_thread.c @@ -0,0 +1,1566 @@ +/*- + * Copyright (c) 2009-2010 Brad Penoff + * Copyright (c) 2009-2010 Humaira Kamal + * Copyright (c) 2011-2012 Irene Ruengeler + * Copyright (c) 2011-2012 Michael Tuexen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#if defined(INET) || defined(INET6) +#include <sys/types.h> +#if !defined(_WIN32) +#include <sys/socket.h> +#include <netinet/in.h> +#include <unistd.h> +#include <pthread.h> +#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#include <sys/uio.h> +#else +#include <user_ip6_var.h> +#endif +#endif +#include <netinet/sctp_os.h> +#include <netinet/sctp_var.h> +#include <netinet/sctp_pcb.h> +#include <netinet/sctp_input.h> +#if 0 +#if defined(__linux__) +#include <linux/netlink.h> +#ifdef HAVE_LINUX_IF_ADDR_H +#include <linux/if_addr.h> +#endif +#ifdef HAVE_LINUX_RTNETLINK_H +#include <linux/rtnetlink.h> +#endif +#endif +#endif +#if defined(HAVE_NET_ROUTE_H) +# include <net/route.h> +#elif defined(__APPLE__) +/* Apple SDKs for iOS, tvOS, watchOS, etc. don't ship this header */ +# define RTM_NEWADDR 0xc +# define RTM_DELADDR 0xd +# define RTAX_IFA 5 +# define RTAX_MAX 8 +#endif +/* local macros and datatypes used to get IP addresses system independently */ +#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) +# error "Can't determine socket option to use to get UDP IP" +#endif + +void recv_thread_destroy(void); + +#define MAXLEN_MBUF_CHAIN 128 + +#define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) + +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) +#define NEXT_SA(ap) ap = (struct sockaddr *) \ + ((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof (uint32_t)) : sizeof(uint32_t))) +#endif + +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) +static void +sctp_get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) +{ + int i; + + for (i = 0; i < RTAX_MAX; i++) { + if (addrs & (1 << i)) { + rti_info[i] = sa; + NEXT_SA(sa); + } else { + rti_info[i] = NULL; + } + } +} + +static void +sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa) +{ + int rc; + struct ifaddrs *ifa, *ifas; + + /* handle only the types we want */ + if ((type != RTM_NEWADDR) && (type != RTM_DELADDR)) { + return; + } + + rc = getifaddrs(&ifas); + if (rc != 0) { + return; + } + for (ifa = ifas; ifa; ifa = ifa->ifa_next) { + if (index == if_nametoindex(ifa->ifa_name)) { + break; + } + } + if (ifa == NULL) { + freeifaddrs(ifas); + return; + } + + /* relay the appropriate address change to the base code */ + if (type == RTM_NEWADDR) { + (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, + NULL, + if_nametoindex(ifa->ifa_name), + 0, + ifa->ifa_name, + NULL, + sa, + 0, + 1); + } else { + sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, + if_nametoindex(ifa->ifa_name), + ifa->ifa_name); + } + freeifaddrs(ifas); +} + +static void * +recv_function_route(void *arg) +{ + ssize_t ret; + struct ifa_msghdr *ifa; + char rt_buffer[1024]; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + + sctp_userspace_set_threadname("SCTP addr mon"); + + while (1) { + memset(rt_buffer, 0, sizeof(rt_buffer)); + ret = recv(SCTP_BASE_VAR(userspace_route), rt_buffer, sizeof(rt_buffer), 0); + + if (ret > 0) { + ifa = (struct ifa_msghdr *) rt_buffer; + if (ifa->ifam_type != RTM_DELADDR && ifa->ifam_type != RTM_NEWADDR) { + continue; + } + sa = (struct sockaddr *) (ifa + 1); + sctp_get_rtaddrs(ifa->ifam_addrs, sa, rti_info); + switch (ifa->ifam_type) { + case RTM_DELADDR: + case RTM_NEWADDR: + sctp_handle_ifamsg(ifa->ifam_type, ifa->ifam_index, rti_info[RTAX_IFA]); + break; + default: + /* ignore this routing event */ + break; + } + } + if (ret < 0) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + break; + } + } + } + return (NULL); +} +#endif + +#if 0 +/* This does not yet work on Linux */ +static void * +recv_function_route(void *arg) +{ + int len; + char buf[4096]; + struct iovec iov = { buf, sizeof(buf) }; + struct msghdr msg; + struct nlmsghdr *nh; + struct ifaddrmsg *rtmsg; + struct rtattr *rtatp; + struct in_addr *inp; + struct sockaddr_nl sanl; +#ifdef INET + struct sockaddr_in *sa; +#endif +#ifdef INET6 + struct sockaddr_in6 *sa6; +#endif + + for (;;) { + memset(&sanl, 0, sizeof(sanl)); + sanl.nl_family = AF_NETLINK; + sanl.nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR; + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = (void *)&sanl; + msg.msg_namelen = sizeof(sanl); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + + len = recvmsg(SCTP_BASE_VAR(userspace_route), &msg, 0); + + if (len < 0) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + break; + } + } + for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len); + nh = NLMSG_NEXT (nh, len)) { + if (nh->nlmsg_type == NLMSG_DONE) + break; + + if (nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) { + rtmsg = (struct ifaddrmsg *)NLMSG_DATA(nh); + rtatp = (struct rtattr *)IFA_RTA(rtmsg); + if (rtatp->rta_type == IFA_ADDRESS) { + inp = (struct in_addr *)RTA_DATA(rtatp); + switch (rtmsg->ifa_family) { +#ifdef INET + case AF_INET: + sa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in)); + sa->sin_family = rtmsg->ifa_family; + sa->sin_port = 0; + memcpy(&sa->sin_addr, inp, sizeof(struct in_addr)); + sctp_handle_ifamsg(nh->nlmsg_type, rtmsg->ifa_index, (struct sockaddr *)sa); + break; +#endif +#ifdef INET6 + case AF_INET6: + sa6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6)); + sa6->sin6_family = rtmsg->ifa_family; + sa6->sin6_port = 0; + memcpy(&sa6->sin6_addr, inp, sizeof(struct in6_addr)); + sctp_handle_ifamsg(nh->nlmsg_type, rtmsg->ifa_index, (struct sockaddr *)sa6); + break; +#endif + default: + SCTPDBG(SCTP_DEBUG_USR, "Address family %d not supported.\n", rtmsg->ifa_family); + break; + } + } + } + } + } + return (NULL); +} +#endif + +#ifdef INET +static void * +recv_function_raw(void *arg) +{ + struct mbuf **recvmbuf; + struct ip *iphdr; + struct sctphdr *sh; + uint16_t port; + int offset, ecn = 0; + int compute_crc = 1; + struct sctp_chunkhdr *ch; + struct sockaddr_in src, dst; +#if !defined(_WIN32) + ssize_t res; + unsigned int ncounter; + struct msghdr msg; + struct iovec recv_iovec[MAXLEN_MBUF_CHAIN]; +#else + WSABUF recv_iovec[MAXLEN_MBUF_CHAIN]; + int nResult, m_ErrorCode; + DWORD flags; + DWORD ncounter; + struct sockaddr_in from; + int fromlen; +#endif + /*Initially the entire set of mbufs is to be allocated. + to_fill indicates this amount. */ + int to_fill = MAXLEN_MBUF_CHAIN; + /* iovlen is the size of each mbuf in the chain */ + int i, n; + unsigned int iovlen = MCLBYTES; + int want_ext = (iovlen > MLEN)? 1 : 0; + int want_header = 0; + + sctp_userspace_set_threadname("SCTP/IP4 rcv"); + + memset(&src, 0, sizeof(struct sockaddr_in)); + memset(&dst, 0, sizeof(struct sockaddr_in)); + + recvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); + + while (1) { + for (i = 0; i < to_fill; i++) { + /* Not getting the packet header. Tests with chain of one run + as usual without having the packet header. + Have tried both sending and receiving + */ + recvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); +#if !defined(_WIN32) + recv_iovec[i].iov_base = (caddr_t)recvmbuf[i]->m_data; + recv_iovec[i].iov_len = iovlen; +#else + recv_iovec[i].buf = (caddr_t)recvmbuf[i]->m_data; + recv_iovec[i].len = iovlen; +#endif + } + to_fill = 0; +#if defined(_WIN32) + flags = 0; + ncounter = 0; + fromlen = sizeof(struct sockaddr_in); + memset(&from, 0, sizeof(struct sockaddr_in)); + + nResult = WSARecvFrom(SCTP_BASE_VAR(userspace_rawsctp), recv_iovec, MAXLEN_MBUF_CHAIN, &ncounter, &flags, (struct sockaddr *)&from, &fromlen, NULL, NULL); + if (nResult != 0) { + m_ErrorCode = WSAGetLastError(); + if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { + break; + } + continue; + } + n = ncounter; +#else + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = recv_iovec; + msg.msg_iovlen = MAXLEN_MBUF_CHAIN; + msg.msg_control = NULL; + msg.msg_controllen = 0; + res = recvmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg, 0); + if (res < 0) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + break; + } + } + ncounter = (unsigned int)res; + n = (int)res; +#endif + SCTP_HEADER_LEN(recvmbuf[0]) = n; /* length of total packet */ + SCTP_STAT_INCR(sctps_recvpackets); + SCTP_STAT_INCR_COUNTER64(sctps_inpackets); + + if ((unsigned int)n <= iovlen) { + SCTP_BUF_LEN(recvmbuf[0]) = n; + (to_fill)++; + } else { + i = 0; + SCTP_BUF_LEN(recvmbuf[0]) = iovlen; + + ncounter -= min(ncounter, iovlen); + (to_fill)++; + do { + recvmbuf[i]->m_next = recvmbuf[i+1]; + SCTP_BUF_LEN(recvmbuf[i]->m_next) = min(ncounter, iovlen); + i++; + ncounter -= min(ncounter, iovlen); + (to_fill)++; + } while (ncounter > 0); + } + + offset = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + if (SCTP_BUF_LEN(recvmbuf[0]) < offset) { + if ((recvmbuf[0] = m_pullup(recvmbuf[0], offset)) == NULL) { + SCTP_STAT_INCR(sctps_hdrops); + continue; + } + } + iphdr = mtod(recvmbuf[0], struct ip *); + sh = (struct sctphdr *)((caddr_t)iphdr + sizeof(struct ip)); + ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); + offset -= sizeof(struct sctp_chunkhdr); + + if (iphdr->ip_tos != 0) { + ecn = iphdr->ip_tos & 0x03; + } + + dst.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); +#endif + dst.sin_addr = iphdr->ip_dst; + dst.sin_port = sh->dest_port; + + src.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + src.sin_len = sizeof(struct sockaddr_in); +#endif + src.sin_addr = iphdr->ip_src; + src.sin_port = sh->src_port; + + /* SCTP does not allow broadcasts or multicasts */ + if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { + m_freem(recvmbuf[0]); + continue; + } + if (SCTP_IS_IT_BROADCAST(dst.sin_addr, recvmbuf[0])) { + m_freem(recvmbuf[0]); + continue; + } + + port = 0; + + if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + ((IN4_ISLOOPBACK_ADDRESS(&src.sin_addr) && + IN4_ISLOOPBACK_ADDRESS(&dst.sin_addr)) || + (src.sin_addr.s_addr == dst.sin_addr.s_addr))) { + compute_crc = 0; + SCTP_STAT_INCR(sctps_recvhwcrc); + } else { + SCTP_STAT_INCR(sctps_recvswcrc); + } + SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); + SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset); + sctp_common_input_processing(&recvmbuf[0], sizeof(struct ip), offset, n, + (struct sockaddr *)&src, + (struct sockaddr *)&dst, + sh, ch, + compute_crc, + ecn, + SCTP_DEFAULT_VRFID, port); + if (recvmbuf[0]) { + m_freem(recvmbuf[0]); + } + } + for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { + m_free(recvmbuf[i]); + } + /* free the array itself */ + free(recvmbuf); + SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP4 rcv\n", __func__); + return (NULL); +} +#endif + +#if defined(INET6) +static void * +recv_function_raw6(void *arg) +{ + struct mbuf **recvmbuf6; +#if !defined(_WIN32) + ssize_t res; + unsigned int ncounter; + struct iovec recv_iovec[MAXLEN_MBUF_CHAIN]; + struct msghdr msg; + struct cmsghdr *cmsgptr; + char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; +#else + WSABUF recv_iovec[MAXLEN_MBUF_CHAIN]; + int nResult, m_ErrorCode; + DWORD ncounter = 0; + struct sockaddr_in6 from; + GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; + LPFN_WSARECVMSG WSARecvMsg; + WSACMSGHDR *cmsgptr; + WSAMSG msg; + char ControlBuffer[1024]; +#endif + struct sockaddr_in6 src, dst; + struct sctphdr *sh; + int offset; + struct sctp_chunkhdr *ch; + /*Initially the entire set of mbufs is to be allocated. + to_fill indicates this amount. */ + int to_fill = MAXLEN_MBUF_CHAIN; + /* iovlen is the size of each mbuf in the chain */ + int i, n; + int compute_crc = 1; + unsigned int iovlen = MCLBYTES; + int want_ext = (iovlen > MLEN)? 1 : 0; + int want_header = 0; + + sctp_userspace_set_threadname("SCTP/IP6 rcv"); + + recvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); + + for (;;) { + for (i = 0; i < to_fill; i++) { + /* Not getting the packet header. Tests with chain of one run + as usual without having the packet header. + Have tried both sending and receiving + */ + recvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); +#if !defined(_WIN32) + recv_iovec[i].iov_base = (caddr_t)recvmbuf6[i]->m_data; + recv_iovec[i].iov_len = iovlen; +#else + recv_iovec[i].buf = (caddr_t)recvmbuf6[i]->m_data; + recv_iovec[i].len = iovlen; +#endif + } + to_fill = 0; +#if defined(_WIN32) + ncounter = 0; + memset(&from, 0, sizeof(struct sockaddr_in6)); + nResult = WSAIoctl(SCTP_BASE_VAR(userspace_rawsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, + &WSARecvMsg, sizeof WSARecvMsg, + &ncounter, NULL, NULL); + if (nResult == 0) { + msg.name = (void *)&src; + msg.namelen = sizeof(struct sockaddr_in6); + msg.lpBuffers = recv_iovec; + msg.dwBufferCount = MAXLEN_MBUF_CHAIN; + msg.Control.len = sizeof ControlBuffer; + msg.Control.buf = ControlBuffer; + msg.dwFlags = 0; + nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, &ncounter, NULL, NULL); + } + if (nResult != 0) { + m_ErrorCode = WSAGetLastError(); + if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { + break; + } + continue; + } + n = ncounter; +#else + memset(&msg, 0, sizeof(struct msghdr)); + memset(&src, 0, sizeof(struct sockaddr_in6)); + memset(&dst, 0, sizeof(struct sockaddr_in6)); + memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo))); + msg.msg_name = (void *)&src; + msg.msg_namelen = sizeof(struct sockaddr_in6); + msg.msg_iov = recv_iovec; + msg.msg_iovlen = MAXLEN_MBUF_CHAIN; + msg.msg_control = (void *)cmsgbuf; + msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo)); + msg.msg_flags = 0; + res = recvmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, 0); + if (res < 0) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + break; + } + } + ncounter = (unsigned int)res; + n = (int)res; +#endif + SCTP_HEADER_LEN(recvmbuf6[0]) = n; /* length of total packet */ + SCTP_STAT_INCR(sctps_recvpackets); + SCTP_STAT_INCR_COUNTER64(sctps_inpackets); + + if ((unsigned int)n <= iovlen) { + SCTP_BUF_LEN(recvmbuf6[0]) = n; + (to_fill)++; + } else { + i = 0; + SCTP_BUF_LEN(recvmbuf6[0]) = iovlen; + + ncounter -= min(ncounter, iovlen); + (to_fill)++; + do { + recvmbuf6[i]->m_next = recvmbuf6[i+1]; + SCTP_BUF_LEN(recvmbuf6[i]->m_next) = min(ncounter, iovlen); + i++; + ncounter -= min(ncounter, iovlen); + (to_fill)++; + } while (ncounter > 0); + } + + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { + if ((cmsgptr->cmsg_level == IPPROTO_IPV6) && (cmsgptr->cmsg_type == IPV6_PKTINFO)) { + struct in6_pktinfo * info; + + info = (struct in6_pktinfo *)CMSG_DATA(cmsgptr); + memcpy((void *)&dst.sin6_addr, (const void *) &(info->ipi6_addr), sizeof(struct in6_addr)); + break; + } + } + + /* SCTP does not allow broadcasts or multicasts */ + if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) { + m_freem(recvmbuf6[0]); + continue; + } + + offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + if (SCTP_BUF_LEN(recvmbuf6[0]) < offset) { + if ((recvmbuf6[0] = m_pullup(recvmbuf6[0], offset)) == NULL) { + SCTP_STAT_INCR(sctps_hdrops); + continue; + } + } + sh = mtod(recvmbuf6[0], struct sctphdr *); + ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); + offset -= sizeof(struct sctp_chunkhdr); + + dst.sin6_family = AF_INET6; +#ifdef HAVE_SIN6_LEN + dst.sin6_len = sizeof(struct sockaddr_in6); +#endif + dst.sin6_port = sh->dest_port; + + src.sin6_family = AF_INET6; +#ifdef HAVE_SIN6_LEN + src.sin6_len = sizeof(struct sockaddr_in6); +#endif + src.sin6_port = sh->src_port; + if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) { + compute_crc = 0; + SCTP_STAT_INCR(sctps_recvhwcrc); + } else { + SCTP_STAT_INCR(sctps_recvswcrc); + } + SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); + SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset); + sctp_common_input_processing(&recvmbuf6[0], 0, offset, n, + (struct sockaddr *)&src, + (struct sockaddr *)&dst, + sh, ch, + compute_crc, + 0, + SCTP_DEFAULT_VRFID, 0); + if (recvmbuf6[0]) { + m_freem(recvmbuf6[0]); + } + } + for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { + m_free(recvmbuf6[i]); + } + /* free the array itself */ + free(recvmbuf6); + SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP6 rcv\n", __func__); + return (NULL); +} +#endif + +#ifdef INET +static void * +recv_function_udp(void *arg) +{ + struct mbuf **udprecvmbuf; + /*Initially the entire set of mbufs is to be allocated. + to_fill indicates this amount. */ + int to_fill = MAXLEN_MBUF_CHAIN; + /* iovlen is the size of each mbuf in the chain */ + int i, n, offset; + unsigned int iovlen = MCLBYTES; + int want_ext = (iovlen > MLEN)? 1 : 0; + int want_header = 0; + struct sctphdr *sh; + uint16_t port; + struct sctp_chunkhdr *ch; + struct sockaddr_in src, dst; +#if defined(IP_PKTINFO) + char cmsgbuf[CMSG_SPACE(sizeof(struct in_pktinfo))]; +#else + char cmsgbuf[CMSG_SPACE(sizeof(struct in_addr))]; +#endif + int compute_crc = 1; +#if !defined(_WIN32) + ssize_t res; + unsigned int ncounter; + struct iovec iov[MAXLEN_MBUF_CHAIN]; + struct msghdr msg; + struct cmsghdr *cmsgptr; +#else + GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; + LPFN_WSARECVMSG WSARecvMsg; + char ControlBuffer[1024]; + WSABUF iov[MAXLEN_MBUF_CHAIN]; + WSAMSG msg; + int nResult, m_ErrorCode; + WSACMSGHDR *cmsgptr; + DWORD ncounter; +#endif + + sctp_userspace_set_threadname("SCTP/UDP/IP4 rcv"); + + udprecvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); + + while (1) { + for (i = 0; i < to_fill; i++) { + /* Not getting the packet header. Tests with chain of one run + as usual without having the packet header. + Have tried both sending and receiving + */ + udprecvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); +#if !defined(_WIN32) + iov[i].iov_base = (caddr_t)udprecvmbuf[i]->m_data; + iov[i].iov_len = iovlen; +#else + iov[i].buf = (caddr_t)udprecvmbuf[i]->m_data; + iov[i].len = iovlen; +#endif + } + to_fill = 0; +#if !defined(_WIN32) + memset(&msg, 0, sizeof(struct msghdr)); +#else + memset(&msg, 0, sizeof(WSAMSG)); +#endif + memset(&src, 0, sizeof(struct sockaddr_in)); + memset(&dst, 0, sizeof(struct sockaddr_in)); + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + +#if !defined(_WIN32) + msg.msg_name = (void *)&src; + msg.msg_namelen = sizeof(struct sockaddr_in); + msg.msg_iov = iov; + msg.msg_iovlen = MAXLEN_MBUF_CHAIN; + msg.msg_control = (void *)cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + msg.msg_flags = 0; + + res = recvmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, 0); + if (res < 0) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + break; + } + } + ncounter = (unsigned int)res; + n = (int)res; +#else + nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp), SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, + &WSARecvMsg, sizeof WSARecvMsg, + &ncounter, NULL, NULL); + if (nResult == 0) { + msg.name = (void *)&src; + msg.namelen = sizeof(struct sockaddr_in); + msg.lpBuffers = iov; + msg.dwBufferCount = MAXLEN_MBUF_CHAIN; + msg.Control.len = sizeof ControlBuffer; + msg.Control.buf = ControlBuffer; + msg.dwFlags = 0; + nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, &ncounter, NULL, NULL); + } + if (nResult != 0) { + m_ErrorCode = WSAGetLastError(); + if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { + break; + } + continue; + } + n = ncounter; +#endif + SCTP_HEADER_LEN(udprecvmbuf[0]) = n; /* length of total packet */ + SCTP_STAT_INCR(sctps_recvpackets); + SCTP_STAT_INCR_COUNTER64(sctps_inpackets); + + if ((unsigned int)n <= iovlen) { + SCTP_BUF_LEN(udprecvmbuf[0]) = n; + (to_fill)++; + } else { + i = 0; + SCTP_BUF_LEN(udprecvmbuf[0]) = iovlen; + + ncounter -= min(ncounter, iovlen); + (to_fill)++; + do { + udprecvmbuf[i]->m_next = udprecvmbuf[i+1]; + SCTP_BUF_LEN(udprecvmbuf[i]->m_next) = min(ncounter, iovlen); + i++; + ncounter -= min(ncounter, iovlen); + (to_fill)++; + } while (ncounter > 0); + } + + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { +#if defined(IP_PKTINFO) + if ((cmsgptr->cmsg_level == IPPROTO_IP) && (cmsgptr->cmsg_type == IP_PKTINFO)) { + struct in_pktinfo *info; + + dst.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); +#endif + info = (struct in_pktinfo *)CMSG_DATA(cmsgptr); + memcpy((void *)&dst.sin_addr, (const void *)&(info->ipi_addr), sizeof(struct in_addr)); + break; + } +#else + if ((cmsgptr->cmsg_level == IPPROTO_IP) && (cmsgptr->cmsg_type == IP_RECVDSTADDR)) { + struct in_addr *addr; + + dst.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); +#endif + addr = (struct in_addr *)CMSG_DATA(cmsgptr); + memcpy((void *)&dst.sin_addr, (const void *)addr, sizeof(struct in_addr)); + break; + } +#endif + } + + /* SCTP does not allow broadcasts or multicasts */ + if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { + m_freem(udprecvmbuf[0]); + continue; + } + if (SCTP_IS_IT_BROADCAST(dst.sin_addr, udprecvmbuf[0])) { + m_freem(udprecvmbuf[0]); + continue; + } + + offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + if (SCTP_BUF_LEN(udprecvmbuf[0]) < offset) { + if ((udprecvmbuf[0] = m_pullup(udprecvmbuf[0], offset)) == NULL) { + SCTP_STAT_INCR(sctps_hdrops); + continue; + } + } + sh = mtod(udprecvmbuf[0], struct sctphdr *); + ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); + offset -= sizeof(struct sctp_chunkhdr); + + port = src.sin_port; + src.sin_port = sh->src_port; + dst.sin_port = sh->dest_port; + if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (src.sin_addr.s_addr == dst.sin_addr.s_addr)) { + compute_crc = 0; + SCTP_STAT_INCR(sctps_recvhwcrc); + } else { + SCTP_STAT_INCR(sctps_recvswcrc); + } + SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); + SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset); + sctp_common_input_processing(&udprecvmbuf[0], 0, offset, n, + (struct sockaddr *)&src, + (struct sockaddr *)&dst, + sh, ch, + compute_crc, + 0, + SCTP_DEFAULT_VRFID, port); + if (udprecvmbuf[0]) { + m_freem(udprecvmbuf[0]); + } + } + for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { + m_free(udprecvmbuf[i]); + } + /* free the array itself */ + free(udprecvmbuf); + SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP4 rcv\n", __func__); + return (NULL); +} +#endif + +#if defined(INET6) +static void * +recv_function_udp6(void *arg) +{ + struct mbuf **udprecvmbuf6; + /*Initially the entire set of mbufs is to be allocated. + to_fill indicates this amount. */ + int to_fill = MAXLEN_MBUF_CHAIN; + /* iovlen is the size of each mbuf in the chain */ + int i, n, offset; + unsigned int iovlen = MCLBYTES; + int want_ext = (iovlen > MLEN)? 1 : 0; + int want_header = 0; + struct sockaddr_in6 src, dst; + struct sctphdr *sh; + uint16_t port; + struct sctp_chunkhdr *ch; + char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; + int compute_crc = 1; +#if !defined(_WIN32) + struct iovec iov[MAXLEN_MBUF_CHAIN]; + struct msghdr msg; + struct cmsghdr *cmsgptr; + ssize_t res; + unsigned int ncounter; +#else + GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; + LPFN_WSARECVMSG WSARecvMsg; + char ControlBuffer[1024]; + WSABUF iov[MAXLEN_MBUF_CHAIN]; + WSAMSG msg; + int nResult, m_ErrorCode; + WSACMSGHDR *cmsgptr; + DWORD ncounter; +#endif + + sctp_userspace_set_threadname("SCTP/UDP/IP6 rcv"); + + udprecvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN); + while (1) { + for (i = 0; i < to_fill; i++) { + /* Not getting the packet header. Tests with chain of one run + as usual without having the packet header. + Have tried both sending and receiving + */ + udprecvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA); +#if !defined(_WIN32) + iov[i].iov_base = (caddr_t)udprecvmbuf6[i]->m_data; + iov[i].iov_len = iovlen; +#else + iov[i].buf = (caddr_t)udprecvmbuf6[i]->m_data; + iov[i].len = iovlen; +#endif + } + to_fill = 0; + +#if !defined(_WIN32) + memset(&msg, 0, sizeof(struct msghdr)); +#else + memset(&msg, 0, sizeof(WSAMSG)); +#endif + memset(&src, 0, sizeof(struct sockaddr_in6)); + memset(&dst, 0, sizeof(struct sockaddr_in6)); + memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo))); + +#if !defined(_WIN32) + msg.msg_name = (void *)&src; + msg.msg_namelen = sizeof(struct sockaddr_in6); + msg.msg_iov = iov; + msg.msg_iovlen = MAXLEN_MBUF_CHAIN; + msg.msg_control = (void *)cmsgbuf; + msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo)); + msg.msg_flags = 0; + + res = recvmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, 0); + if (res < 0) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + break; + } + } + ncounter = (unsigned int)res; + n = (int)res; +#else + nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID, + &WSARecvMsg, sizeof WSARecvMsg, + &ncounter, NULL, NULL); + if (nResult == SOCKET_ERROR) { + m_ErrorCode = WSAGetLastError(); + WSARecvMsg = NULL; + } + if (nResult == 0) { + msg.name = (void *)&src; + msg.namelen = sizeof(struct sockaddr_in6); + msg.lpBuffers = iov; + msg.dwBufferCount = MAXLEN_MBUF_CHAIN; + msg.Control.len = sizeof ControlBuffer; + msg.Control.buf = ControlBuffer; + msg.dwFlags = 0; + nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, &ncounter, NULL, NULL); + } + if (nResult != 0) { + m_ErrorCode = WSAGetLastError(); + if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) { + break; + } + continue; + } + n = ncounter; +#endif + SCTP_HEADER_LEN(udprecvmbuf6[0]) = n; /* length of total packet */ + SCTP_STAT_INCR(sctps_recvpackets); + SCTP_STAT_INCR_COUNTER64(sctps_inpackets); + + if ((unsigned int)n <= iovlen) { + SCTP_BUF_LEN(udprecvmbuf6[0]) = n; + (to_fill)++; + } else { + i = 0; + SCTP_BUF_LEN(udprecvmbuf6[0]) = iovlen; + + ncounter -= min(ncounter, iovlen); + (to_fill)++; + do { + udprecvmbuf6[i]->m_next = udprecvmbuf6[i+1]; + SCTP_BUF_LEN(udprecvmbuf6[i]->m_next) = min(ncounter, iovlen); + i++; + ncounter -= min(ncounter, iovlen); + (to_fill)++; + } while (ncounter > 0); + } + + for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { + if ((cmsgptr->cmsg_level == IPPROTO_IPV6) && (cmsgptr->cmsg_type == IPV6_PKTINFO)) { + struct in6_pktinfo *info; + + dst.sin6_family = AF_INET6; +#ifdef HAVE_SIN6_LEN + dst.sin6_len = sizeof(struct sockaddr_in6); +#endif + info = (struct in6_pktinfo *)CMSG_DATA(cmsgptr); + /*dst.sin6_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));*/ + memcpy((void *)&dst.sin6_addr, (const void *)&(info->ipi6_addr), sizeof(struct in6_addr)); + } + } + + /* SCTP does not allow broadcasts or multicasts */ + if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) { + m_freem(udprecvmbuf6[0]); + continue; + } + + offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + if (SCTP_BUF_LEN(udprecvmbuf6[0]) < offset) { + if ((udprecvmbuf6[0] = m_pullup(udprecvmbuf6[0], offset)) == NULL) { + SCTP_STAT_INCR(sctps_hdrops); + continue; + } + } + sh = mtod(udprecvmbuf6[0], struct sctphdr *); + ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); + offset -= sizeof(struct sctp_chunkhdr); + + port = src.sin6_port; + src.sin6_port = sh->src_port; + dst.sin6_port = sh->dest_port; + if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) { + compute_crc = 0; + SCTP_STAT_INCR(sctps_recvhwcrc); + } else { + SCTP_STAT_INCR(sctps_recvswcrc); + } + SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); + SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", (int)sizeof(struct sctphdr)); + sctp_common_input_processing(&udprecvmbuf6[0], 0, offset, n, + (struct sockaddr *)&src, + (struct sockaddr *)&dst, + sh, ch, + compute_crc, + 0, + SCTP_DEFAULT_VRFID, port); + if (udprecvmbuf6[0]) { + m_freem(udprecvmbuf6[0]); + } + } + for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) { + m_free(udprecvmbuf6[i]); + } + /* free the array itself */ + free(udprecvmbuf6); + SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP6 rcv\n", __func__); + return (NULL); +} +#endif + +#if defined(_WIN32) +static void +setReceiveBufferSize(SOCKET sfd, int new_size) +#else +static void +setReceiveBufferSize(int sfd, int new_size) +#endif +{ + int ch = new_size; + + if (setsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)&ch, sizeof(ch)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", errno); +#endif + } + return; +} + +#if defined(_WIN32) +static void +setSendBufferSize(SOCKET sfd, int new_size) +#else +static void +setSendBufferSize(int sfd, int new_size) +#endif +{ + int ch = new_size; + + if (setsockopt (sfd, SOL_SOCKET, SO_SNDBUF, (void*)&ch, sizeof(ch)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", errno); +#endif + } + return; +} + +#define SOCKET_TIMEOUT 100 /* in ms */ +void +recv_thread_init(void) +{ +#if defined(INET) + struct sockaddr_in addr_ipv4; + const int hdrincl = 1; +#endif +#if defined(INET6) + struct sockaddr_in6 addr_ipv6; +#endif +#if defined(INET) || defined(INET6) + const int on = 1; +#endif +#if !defined(_WIN32) + struct timeval timeout; + + memset(&timeout, 0, sizeof(struct timeval)); + timeout.tv_sec = (SOCKET_TIMEOUT / 1000); + timeout.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000; +#else + unsigned int timeout = SOCKET_TIMEOUT; /* Timeout in milliseconds */ +#endif +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) + if (SCTP_BASE_VAR(userspace_route) == -1) { + if ((SCTP_BASE_VAR(userspace_route) = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { + SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d).\n", errno); + } +#if 0 + struct sockaddr_nl sanl; + + if ((SCTP_BASE_VAR(userspace_route) = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) { + SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d.\n", errno); + } + memset(&sanl, 0, sizeof(sanl)); + sanl.nl_family = AF_NETLINK; + sanl.nl_groups = 0; +#ifdef INET + sanl.nl_groups |= RTMGRP_IPV4_IFADDR; +#endif +#ifdef INET6 + sanl.nl_groups |= RTMGRP_IPV6_IFADDR; +#endif + if (bind(SCTP_BASE_VAR(userspace_route), (struct sockaddr *) &sanl, sizeof(sanl)) < 0) { + SCTPDBG(SCTP_DEBUG_USR, "Can't bind routing socket (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_route)); + SCTP_BASE_VAR(userspace_route) = -1; + } +#endif + if (SCTP_BASE_VAR(userspace_route) != -1) { + if (setsockopt(SCTP_BASE_VAR(userspace_route), SOL_SOCKET, SO_RCVTIMEO,(const void*)&timeout, sizeof(struct timeval)) < 0) { + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on routing socket (errno = %d).\n", errno); +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_route)); +#else + close(SCTP_BASE_VAR(userspace_route)); +#endif + SCTP_BASE_VAR(userspace_route) = -1; + } + } + } +#endif +#if defined(INET) + if (SCTP_BASE_VAR(userspace_rawsctp) == -1) { + if ((SCTP_BASE_VAR(userspace_rawsctp) = socket(AF_INET, SOCK_RAW, IPPROTO_SCTP)) == -1) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", errno); +#endif + } else { + /* complete setting up the raw SCTP socket */ + if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), IPPROTO_IP, IP_HDRINCL,(const void*)&hdrincl, sizeof(int)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_HDRINCL (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_rawsctp)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_HDRINCL (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_rawsctp)); +#endif + SCTP_BASE_VAR(userspace_rawsctp) = -1; + } else if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_rawsctp)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv4 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_rawsctp)); +#endif + SCTP_BASE_VAR(userspace_rawsctp) = -1; + } else { + memset((void *)&addr_ipv4, 0, sizeof(struct sockaddr_in)); +#ifdef HAVE_SIN_LEN + addr_ipv4.sin_len = sizeof(struct sockaddr_in); +#endif + addr_ipv4.sin_family = AF_INET; + addr_ipv4.sin_port = htons(0); + addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(SCTP_BASE_VAR(userspace_rawsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_rawsctp)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv4 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_rawsctp)); +#endif + SCTP_BASE_VAR(userspace_rawsctp) = -1; + } else { + setReceiveBufferSize(SCTP_BASE_VAR(userspace_rawsctp), SB_RAW); /* 128K */ + setSendBufferSize(SCTP_BASE_VAR(userspace_rawsctp), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ + } + } + } + } + if ((SCTP_BASE_VAR(userspace_udpsctp) == -1) && (SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) != 0)) { + if ((SCTP_BASE_VAR(userspace_udpsctp) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); +#endif + } else { +#if defined(IP_PKTINFO) + if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), IPPROTO_IP, IP_PKTINFO, (const void *)&on, (int)sizeof(int)) < 0) { +#else + if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), IPPROTO_IP, IP_RECVDSTADDR, (const void *)&on, (int)sizeof(int)) < 0) { +#endif +#if defined(_WIN32) +#if defined(IP_PKTINFO) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_PKTINFO on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_RECVDSTADDR on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); +#endif + closesocket(SCTP_BASE_VAR(userspace_udpsctp)); +#else +#if defined(IP_PKTINFO) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_PKTINFO on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_RECVDSTADDR on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); +#endif + close(SCTP_BASE_VAR(userspace_udpsctp)); +#endif + SCTP_BASE_VAR(userspace_udpsctp) = -1; + } else if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_udpsctp)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_udpsctp)); +#endif + SCTP_BASE_VAR(userspace_udpsctp) = -1; + } else { + memset((void *)&addr_ipv4, 0, sizeof(struct sockaddr_in)); +#ifdef HAVE_SIN_LEN + addr_ipv4.sin_len = sizeof(struct sockaddr_in); +#endif + addr_ipv4.sin_family = AF_INET; + addr_ipv4.sin_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); + addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(SCTP_BASE_VAR(userspace_udpsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_udpsctp)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv4 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_udpsctp)); +#endif + SCTP_BASE_VAR(userspace_udpsctp) = -1; + } else { + setReceiveBufferSize(SCTP_BASE_VAR(userspace_udpsctp), SB_RAW); /* 128K */ + setSendBufferSize(SCTP_BASE_VAR(userspace_udpsctp), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ + } + } + } + } +#endif +#if defined(INET6) + if (SCTP_BASE_VAR(userspace_rawsctp6) == -1) { + if ((SCTP_BASE_VAR(userspace_rawsctp6) = socket(AF_INET6, SOCK_RAW, IPPROTO_SCTP)) == -1) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", errno); +#endif + } else { + /* complete setting up the raw SCTP socket */ +#if defined(IPV6_RECVPKTINFO) + if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, sizeof(on)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_rawsctp6)); +#endif + SCTP_BASE_VAR(userspace_rawsctp6) = -1; + } else { +#else + if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_PKTINFO,(const void*)&on, sizeof(on)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_rawsctp6)); +#endif + SCTP_BASE_VAR(userspace_rawsctp6) = -1; + } else { +#endif + if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&on, (socklen_t)sizeof(on)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", errno); +#endif + } + if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_rawsctp6)); +#endif + SCTP_BASE_VAR(userspace_rawsctp6) = -1; + } else { + memset((void *)&addr_ipv6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr_ipv6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr_ipv6.sin6_family = AF_INET6; + addr_ipv6.sin6_port = htons(0); + addr_ipv6.sin6_addr = in6addr_any; + if (bind(SCTP_BASE_VAR(userspace_rawsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_rawsctp6)); +#endif + SCTP_BASE_VAR(userspace_rawsctp6) = -1; + } else { + setReceiveBufferSize(SCTP_BASE_VAR(userspace_rawsctp6), SB_RAW); /* 128K */ + setSendBufferSize(SCTP_BASE_VAR(userspace_rawsctp6), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ + } + } + } + } + } + if ((SCTP_BASE_VAR(userspace_udpsctp6) == -1) && (SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) != 0)) { + if ((SCTP_BASE_VAR(userspace_udpsctp6) = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); +#endif + } +#if defined(IPV6_RECVPKTINFO) + if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, (int)sizeof(int)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_udpsctp6)); +#endif + SCTP_BASE_VAR(userspace_udpsctp6) = -1; + } else { +#else + if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_PKTINFO, (const void *)&on, (int)sizeof(int)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_udpsctp6)); +#endif + SCTP_BASE_VAR(userspace_udpsctp6) = -1; + } else { +#endif + if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, (socklen_t)sizeof(on)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); +#endif + } + if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_udpsctp6)); +#endif + SCTP_BASE_VAR(userspace_udpsctp6) = -1; + } else { + memset((void *)&addr_ipv6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr_ipv6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr_ipv6.sin6_family = AF_INET6; + addr_ipv6.sin6_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); + addr_ipv6.sin6_addr = in6addr_any; + if (bind(SCTP_BASE_VAR(userspace_udpsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) { +#if defined(_WIN32) + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); + closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); +#else + SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv6 (errno = %d).\n", errno); + close(SCTP_BASE_VAR(userspace_udpsctp6)); +#endif + SCTP_BASE_VAR(userspace_udpsctp6) = -1; + } else { + setReceiveBufferSize(SCTP_BASE_VAR(userspace_udpsctp6), SB_RAW); /* 128K */ + setSendBufferSize(SCTP_BASE_VAR(userspace_udpsctp6), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */ + } + } + } + } +#endif +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) +#if defined(INET) || defined(INET6) + if (SCTP_BASE_VAR(userspace_route) != -1) { + int rc; + + if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadroute), &recv_function_route))) { + SCTPDBG(SCTP_DEBUG_USR, "Can't start routing thread (%d).\n", rc); + close(SCTP_BASE_VAR(userspace_route)); + SCTP_BASE_VAR(userspace_route) = -1; + } + } +#endif +#endif +#if defined(INET) + if (SCTP_BASE_VAR(userspace_rawsctp) != -1) { + int rc; + + if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw), &recv_function_raw))) { + SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv4 recv thread (%d).\n", rc); +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_rawsctp)); +#else + close(SCTP_BASE_VAR(userspace_rawsctp)); +#endif + SCTP_BASE_VAR(userspace_rawsctp) = -1; + } + } + if (SCTP_BASE_VAR(userspace_udpsctp) != -1) { + int rc; + + if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp), &recv_function_udp))) { + SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv4 recv thread (%d).\n", rc); +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_udpsctp)); +#else + close(SCTP_BASE_VAR(userspace_udpsctp)); +#endif + SCTP_BASE_VAR(userspace_udpsctp) = -1; + } + } +#endif +#if defined(INET6) + if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) { + int rc; + + if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw6), &recv_function_raw6))) { + SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv6 recv thread (%d).\n", rc); +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); +#else + close(SCTP_BASE_VAR(userspace_rawsctp6)); +#endif + SCTP_BASE_VAR(userspace_rawsctp6) = -1; + } + } + if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) { + int rc; + + if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp6), &recv_function_udp6))) { + SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv6 recv thread (%d).\n", rc); +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); +#else + close(SCTP_BASE_VAR(userspace_udpsctp6)); +#endif + SCTP_BASE_VAR(userspace_udpsctp6) = -1; + } + } +#endif +} + +void +recv_thread_destroy(void) +{ +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) +#if defined(INET) || defined(INET6) + if (SCTP_BASE_VAR(userspace_route) != -1) { + close(SCTP_BASE_VAR(userspace_route)); + pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL); + } +#endif +#endif +#if defined(INET) + if (SCTP_BASE_VAR(userspace_rawsctp) != -1) { +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_rawsctp)); + SCTP_BASE_VAR(userspace_rawsctp) = -1; + WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE); + CloseHandle(SCTP_BASE_VAR(recvthreadraw)); +#else + close(SCTP_BASE_VAR(userspace_rawsctp)); + SCTP_BASE_VAR(userspace_rawsctp) = -1; + pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL); +#endif + } + if (SCTP_BASE_VAR(userspace_udpsctp) != -1) { +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_udpsctp)); + SCTP_BASE_VAR(userspace_udpsctp) = -1; + WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE); + CloseHandle(SCTP_BASE_VAR(recvthreadudp)); +#else + close(SCTP_BASE_VAR(userspace_udpsctp)); + SCTP_BASE_VAR(userspace_udpsctp) = -1; + pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL); +#endif + } +#endif +#if defined(INET6) + if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) { +#if defined(_WIN32) + closesocket(SCTP_BASE_VAR(userspace_rawsctp6)); + SCTP_BASE_VAR(userspace_rawsctp6) = -1; + WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE); + CloseHandle(SCTP_BASE_VAR(recvthreadraw6)); +#else + close(SCTP_BASE_VAR(userspace_rawsctp6)); + SCTP_BASE_VAR(userspace_rawsctp6) = -1; + pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL); +#endif + } + if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) { +#if defined(_WIN32) + SCTP_BASE_VAR(userspace_udpsctp6) = -1; + closesocket(SCTP_BASE_VAR(userspace_udpsctp6)); + WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE); + CloseHandle(SCTP_BASE_VAR(recvthreadudp6)); +#else + close(SCTP_BASE_VAR(userspace_udpsctp6)); + SCTP_BASE_VAR(userspace_udpsctp6) = -1; + pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL); +#endif + } +#endif +} +#else +int foo; +#endif |