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