mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-17 22:06:41 +00:00
f4538e24b6
There are problems with global shared state and no API stability guarantees, and we can't rely on distros shipping the fixes we need. Both firefox and Chrome bundle their own copies too. Imported from https://github.com/sctplab/usrsctp, commit 547d3b46c64876c0336b9eef297fda58dbe1adaf Date: Thu Jul 23 21:49:32 2020 +0200 Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/870 Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1465>
1521 lines
48 KiB
C
1521 lines
48 KiB
C
/*-
|
|
* 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(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__)
|
|
#include <net/route.h>
|
|
#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)
|
|
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;
|
|
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg, 0);
|
|
if (n < 0) {
|
|
if (errno == EAGAIN || errno == EINTR) {
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#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);
|
|
}
|
|
|
|
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 ip) + sizeof(struct sctphdr);
|
|
|
|
if (iphdr->ip_tos != 0) {
|
|
ecn = iphdr->ip_tos & 0x02;
|
|
}
|
|
|
|
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)
|
|
unsigned int ncounter = 0;
|
|
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;
|
|
|
|
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, 0);
|
|
if (n < 0) {
|
|
if (errno == EAGAIN || errno == EINTR) {
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#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;
|
|
}
|
|
|
|
sh = mtod(recvmbuf6[0], struct sctphdr *);
|
|
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
|
|
offset = sizeof(struct sctphdr);
|
|
|
|
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)
|
|
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;
|
|
|
|
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, 0);
|
|
if (n < 0) {
|
|
if (errno == EAGAIN || errno == EINTR) {
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#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);*/
|
|
sh = mtod(udprecvmbuf[0], struct sctphdr *);
|
|
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
|
|
offset = sizeof(struct sctphdr);
|
|
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;
|
|
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;
|
|
|
|
ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, 0);
|
|
if (n < 0) {
|
|
if (errno == EAGAIN || errno == EINTR) {
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#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;
|
|
}
|
|
|
|
sh = mtod(udprecvmbuf6[0], struct sctphdr *);
|
|
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
|
|
offset = sizeof(struct sctphdr);
|
|
|
|
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) {
|
|
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) {
|
|
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
|