• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-
2  * Copyright (c) 2009-2010 Brad Penoff
3  * Copyright (c) 2009-2010 Humaira Kamal
4  * Copyright (c) 2011-2012 Irene Ruengeler
5  * Copyright (c) 2011-2012 Michael Tuexen
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 #if defined(INET) || defined(INET6)
32 #include <sys/types.h>
33 #if !defined(__Userspace_os_Windows)
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <unistd.h>
37 #include <pthread.h>
38 #if !defined(__Userspace_os_DragonFly) && !defined(__Userspace_os_FreeBSD) && !defined(__Userspace_os_NetBSD)
39 #include <sys/uio.h>
40 #else
41 #include <user_ip6_var.h>
42 #endif
43 #endif
44 #include <netinet/sctp_os.h>
45 #include <netinet/sctp_var.h>
46 #include <netinet/sctp_pcb.h>
47 #include <netinet/sctp_input.h>
48 #if 0
49 #if defined(__Userspace_os_Linux)
50 #include <linux/netlink.h>
51 #ifdef HAVE_LINUX_IF_ADDR_H
52 #include <linux/if_addr.h>
53 #endif
54 #ifdef HAVE_LINUX_RTNETLINK_H
55 #include <linux/rtnetlink.h>
56 #endif
57 #endif
58 #endif
59 #if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
60 #include <net/route.h>
61 #endif
62 /* local macros and datatypes used to get IP addresses system independently */
63 #if !defined(IP_PKTINFO ) && ! defined(IP_RECVDSTADDR)
64 # error "Can't determine socket option to use to get UDP IP"
65 #endif
66 
67 void recv_thread_destroy(void);
68 #define MAXLEN_MBUF_CHAIN 32 /* What should this value be? */
69 #define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
70 #if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
71 #define NEXT_SA(ap) ap = (struct sockaddr *) \
72 	((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof (uint32_t)) : sizeof(uint32_t)))
73 #endif
74 
75 #if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
76 static void
sctp_get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)77 sctp_get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
78 {
79 	int i;
80 
81 	for (i = 0; i < RTAX_MAX; i++) {
82 		if (addrs & (1 << i)) {
83 			rti_info[i] = sa;
84 			NEXT_SA(sa);
85 		} else {
86 			rti_info[i] = NULL;
87 		}
88 	}
89 }
90 
91 static void
sctp_handle_ifamsg(unsigned char type,unsigned short index,struct sockaddr * sa)92 sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa)
93 {
94 	int rc;
95 	struct ifaddrs *ifa, *ifas;
96 
97 	/* handle only the types we want */
98 	if ((type != RTM_NEWADDR) && (type != RTM_DELADDR)) {
99 		return;
100 	}
101 
102 	rc = getifaddrs(&ifas);
103 	if (rc != 0) {
104 		return;
105 	}
106 	for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
107 		if (index == if_nametoindex(ifa->ifa_name)) {
108 			break;
109 		}
110 	}
111 	if (ifa == NULL) {
112 		freeifaddrs(ifas);
113 		return;
114 	}
115 
116 	/* relay the appropriate address change to the base code */
117 	if (type == RTM_NEWADDR) {
118 		(void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID,
119 		                           NULL,
120 		                           if_nametoindex(ifa->ifa_name),
121 		                           0,
122 		                           ifa->ifa_name,
123 		                           NULL,
124 		                           sa,
125 		                           0,
126 		                           1);
127 	} else {
128 		sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr,
129 		                       if_nametoindex(ifa->ifa_name),
130 		                       ifa->ifa_name);
131 	}
132 	freeifaddrs(ifas);
133 }
134 
135 static void *
recv_function_route(void * arg)136 recv_function_route(void *arg)
137 {
138 	ssize_t ret;
139 	struct ifa_msghdr *ifa;
140 	char rt_buffer[1024];
141 	struct sockaddr *sa, *rti_info[RTAX_MAX];
142 
143 	sctp_userspace_set_threadname("SCTP addr mon");
144 
145 	while (1) {
146 		memset(rt_buffer, 0, sizeof(rt_buffer));
147 		ret = recv(SCTP_BASE_VAR(userspace_route), rt_buffer, sizeof(rt_buffer), 0);
148 
149 		if (ret > 0) {
150 			ifa = (struct ifa_msghdr *) rt_buffer;
151 			if (ifa->ifam_type != RTM_DELADDR && ifa->ifam_type != RTM_NEWADDR) {
152 				continue;
153 			}
154 			sa = (struct sockaddr *) (ifa + 1);
155 			sctp_get_rtaddrs(ifa->ifam_addrs, sa, rti_info);
156 			switch (ifa->ifam_type) {
157 			case RTM_DELADDR:
158 			case RTM_NEWADDR:
159 				sctp_handle_ifamsg(ifa->ifam_type, ifa->ifam_index, rti_info[RTAX_IFA]);
160 				break;
161 			default:
162 				/* ignore this routing event */
163 				break;
164 			}
165 		}
166 		if (ret < 0) {
167 			if (errno == EAGAIN || errno == EINTR) {
168 				continue;
169 			} else {
170 				break;
171 			}
172 		}
173 	}
174 	return (NULL);
175 }
176 #endif
177 
178 #if 0
179 /* This does not yet work on Linux */
180 static void *
181 recv_function_route(void *arg)
182 {
183 	int len;
184 	char buf[4096];
185 	struct iovec iov = { buf, sizeof(buf) };
186 	struct msghdr msg;
187 	struct nlmsghdr *nh;
188 	struct ifaddrmsg *rtmsg;
189 	struct rtattr *rtatp;
190 	struct in_addr *inp;
191 	struct sockaddr_nl sanl;
192 #ifdef INET
193 	struct sockaddr_in *sa;
194 #endif
195 #ifdef INET6
196 	struct sockaddr_in6 *sa6;
197 #endif
198 
199 	for (;;) {
200 		memset(&sanl, 0, sizeof(sanl));
201 		sanl.nl_family = AF_NETLINK;
202 		sanl.nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_IFADDR;
203 		memset(&msg, 0, sizeof(struct msghdr));
204 		msg.msg_name = (void *)&sanl;
205 		msg.msg_namelen = sizeof(sanl);
206 		msg.msg_iov = &iov;
207 		msg.msg_iovlen = 1;
208 		msg.msg_control = NULL;
209 		msg.msg_controllen = 0;
210 
211 		len = recvmsg(SCTP_BASE_VAR(userspace_route), &msg, 0);
212 
213 		if (len < 0) {
214 			if (errno == EAGAIN || errno == EINTR) {
215 				continue;
216 			} else {
217 				break;
218 			}
219 		}
220 		for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
221 			nh = NLMSG_NEXT (nh, len)) {
222 			if (nh->nlmsg_type == NLMSG_DONE)
223 				break;
224 
225 			if (nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) {
226 				rtmsg = (struct ifaddrmsg *)NLMSG_DATA(nh);
227 				rtatp = (struct rtattr *)IFA_RTA(rtmsg);
228 				if (rtatp->rta_type == IFA_ADDRESS) {
229 					inp = (struct in_addr *)RTA_DATA(rtatp);
230 					switch (rtmsg->ifa_family) {
231 #ifdef INET
232 					case AF_INET:
233 						sa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
234 						sa->sin_family = rtmsg->ifa_family;
235 						sa->sin_port = 0;
236 						memcpy(&sa->sin_addr, inp, sizeof(struct in_addr));
237 						sctp_handle_ifamsg(nh->nlmsg_type, rtmsg->ifa_index, (struct sockaddr *)sa);
238 						break;
239 #endif
240 #ifdef INET6
241 					case AF_INET6:
242 						sa6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
243 						sa6->sin6_family = rtmsg->ifa_family;
244 						sa6->sin6_port = 0;
245 						memcpy(&sa6->sin6_addr, inp, sizeof(struct in6_addr));
246 						sctp_handle_ifamsg(nh->nlmsg_type, rtmsg->ifa_index, (struct sockaddr *)sa6);
247 						break;
248 #endif
249 					default:
250 						SCTPDBG(SCTP_DEBUG_USR, "Address family %d not supported.\n", rtmsg->ifa_family);
251 						break;
252 					}
253 				}
254 			}
255 		}
256 	}
257 	return (NULL);
258 }
259 #endif
260 
261 #ifdef INET
262 static void *
recv_function_raw(void * arg)263 recv_function_raw(void *arg)
264 {
265 	struct mbuf **recvmbuf;
266 	struct ip *iphdr;
267 	struct sctphdr *sh;
268 	uint16_t port;
269 	int offset, ecn = 0;
270 	int compute_crc = 1;
271 	struct sctp_chunkhdr *ch;
272 	struct sockaddr_in src, dst;
273 #if !defined(__Userspace_os_Windows)
274 	unsigned int ncounter;
275 	struct msghdr msg;
276 	struct iovec recv_iovec[MAXLEN_MBUF_CHAIN];
277 #else
278 	WSABUF recv_iovec[MAXLEN_MBUF_CHAIN];
279 	int nResult, m_ErrorCode;
280 	DWORD flags;
281 	DWORD ncounter;
282 	struct sockaddr_in from;
283 	int fromlen;
284 #endif
285 	/*Initially the entire set of mbufs is to be allocated.
286 	  to_fill indicates this amount. */
287 	int to_fill = MAXLEN_MBUF_CHAIN;
288 	/* iovlen is the size of each mbuf in the chain */
289 	int i, n;
290 	unsigned int iovlen = MCLBYTES;
291 	int want_ext = (iovlen > MLEN)? 1 : 0;
292 	int want_header = 0;
293 
294 	sctp_userspace_set_threadname("SCTP/IP4 rcv");
295 
296 	memset(&src, 0, sizeof(struct sockaddr_in));
297 	memset(&dst, 0, sizeof(struct sockaddr_in));
298 
299 	recvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
300 
301 	while (1) {
302 		for (i = 0; i < to_fill; i++) {
303 			/* Not getting the packet header. Tests with chain of one run
304 			   as usual without having the packet header.
305 			   Have tried both sending and receiving
306 			 */
307 			recvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
308 #if !defined(__Userspace_os_Windows)
309 			recv_iovec[i].iov_base = (caddr_t)recvmbuf[i]->m_data;
310 			recv_iovec[i].iov_len = iovlen;
311 #else
312 			recv_iovec[i].buf = (caddr_t)recvmbuf[i]->m_data;
313 			recv_iovec[i].len = iovlen;
314 #endif
315 		}
316 		to_fill = 0;
317 #if defined(__Userspace_os_Windows)
318 		flags = 0;
319 		ncounter = 0;
320 		fromlen = sizeof(struct sockaddr_in);
321 		memset(&from, 0, sizeof(struct sockaddr_in));
322 
323 		nResult = WSARecvFrom(SCTP_BASE_VAR(userspace_rawsctp), recv_iovec, MAXLEN_MBUF_CHAIN, &ncounter, &flags, (struct sockaddr *)&from, &fromlen, NULL, NULL);
324 		if (nResult != 0) {
325 			m_ErrorCode = WSAGetLastError();
326 			if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
327 				break;
328 			}
329 			continue;
330 		}
331 		n = ncounter;
332 #else
333 		memset(&msg, 0, sizeof(struct msghdr));
334 		msg.msg_name = NULL;
335 		msg.msg_namelen = 0;
336 		msg.msg_iov = recv_iovec;
337 		msg.msg_iovlen = MAXLEN_MBUF_CHAIN;
338 		msg.msg_control = NULL;
339 		msg.msg_controllen = 0;
340 		ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg, 0);
341 		if (n < 0) {
342 			if (errno == EAGAIN || errno == EINTR) {
343 				continue;
344 			} else {
345 				break;
346 			}
347 		}
348 #endif
349 		SCTP_HEADER_LEN(recvmbuf[0]) = n; /* length of total packet */
350 		SCTP_STAT_INCR(sctps_recvpackets);
351 		SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
352 
353 		if ((unsigned int)n <= iovlen) {
354 			SCTP_BUF_LEN(recvmbuf[0]) = n;
355 			(to_fill)++;
356 		} else {
357 			i = 0;
358 			SCTP_BUF_LEN(recvmbuf[0]) = iovlen;
359 
360 			ncounter -= min(ncounter, iovlen);
361 			(to_fill)++;
362 			do {
363 				recvmbuf[i]->m_next = recvmbuf[i+1];
364 				SCTP_BUF_LEN(recvmbuf[i]->m_next) = min(ncounter, iovlen);
365 				i++;
366 				ncounter -= min(ncounter, iovlen);
367 				(to_fill)++;
368 			} while (ncounter > 0);
369 		}
370 
371 		iphdr = mtod(recvmbuf[0], struct ip *);
372 		sh = (struct sctphdr *)((caddr_t)iphdr + sizeof(struct ip));
373 		ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
374 		offset = sizeof(struct ip) + sizeof(struct sctphdr);
375 
376 		if (iphdr->ip_tos != 0) {
377 			ecn = iphdr->ip_tos & 0x02;
378 		}
379 
380 		dst.sin_family = AF_INET;
381 #ifdef HAVE_SIN_LEN
382 		dst.sin_len = sizeof(struct sockaddr_in);
383 #endif
384 		dst.sin_addr = iphdr->ip_dst;
385 		dst.sin_port = sh->dest_port;
386 
387 		src.sin_family = AF_INET;
388 #ifdef HAVE_SIN_LEN
389 		src.sin_len = sizeof(struct sockaddr_in);
390 #endif
391 		src.sin_addr = iphdr->ip_src;
392 		src.sin_port = sh->src_port;
393 
394 		/* SCTP does not allow broadcasts or multicasts */
395 		if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
396 			m_freem(recvmbuf[0]);
397 			continue;
398 		}
399 		if (SCTP_IS_IT_BROADCAST(dst.sin_addr, recvmbuf[0])) {
400 			m_freem(recvmbuf[0]);
401 			continue;
402 		}
403 
404 		port = 0;
405 
406 		if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
407 		    ((IN4_ISLOOPBACK_ADDRESS(&src.sin_addr) &&
408 		      IN4_ISLOOPBACK_ADDRESS(&dst.sin_addr)) ||
409 		     (src.sin_addr.s_addr == dst.sin_addr.s_addr))) {
410 			compute_crc = 0;
411 			SCTP_STAT_INCR(sctps_recvhwcrc);
412 		} else {
413 			SCTP_STAT_INCR(sctps_recvswcrc);
414 		}
415 		SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
416 		SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset);
417 		sctp_common_input_processing(&recvmbuf[0], sizeof(struct ip), offset, n,
418 		                             (struct sockaddr *)&src,
419 		                             (struct sockaddr *)&dst,
420 		                             sh, ch,
421 		                             compute_crc,
422 		                             ecn,
423 		                             SCTP_DEFAULT_VRFID, port);
424 		if (recvmbuf[0]) {
425 			m_freem(recvmbuf[0]);
426 		}
427 	}
428 	for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) {
429 		m_free(recvmbuf[i]);
430 	}
431 	/* free the array itself */
432 	free(recvmbuf);
433 	SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP4 rcv", __func__);
434 	return (NULL);
435 }
436 #endif
437 
438 #if defined(INET6)
439 static void *
recv_function_raw6(void * arg)440 recv_function_raw6(void *arg)
441 {
442 	struct mbuf **recvmbuf6;
443 #if !defined(__Userspace_os_Windows)
444 	unsigned int ncounter = 0;
445 	struct iovec recv_iovec[MAXLEN_MBUF_CHAIN];
446 	struct msghdr msg;
447 	struct cmsghdr *cmsgptr;
448 	char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
449 #else
450 	WSABUF recv_iovec[MAXLEN_MBUF_CHAIN];
451 	int nResult, m_ErrorCode;
452 	DWORD ncounter = 0;
453 	struct sockaddr_in6 from;
454 	GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
455 	LPFN_WSARECVMSG WSARecvMsg;
456 	WSACMSGHDR *cmsgptr;
457 	WSAMSG msg;
458 	char ControlBuffer[1024];
459 #endif
460 	struct sockaddr_in6 src, dst;
461 	struct sctphdr *sh;
462 	int offset;
463 	struct sctp_chunkhdr *ch;
464 	/*Initially the entire set of mbufs is to be allocated.
465 	  to_fill indicates this amount. */
466 	int to_fill = MAXLEN_MBUF_CHAIN;
467 	/* iovlen is the size of each mbuf in the chain */
468 	int i, n;
469 	int compute_crc = 1;
470 	unsigned int iovlen = MCLBYTES;
471 	int want_ext = (iovlen > MLEN)? 1 : 0;
472 	int want_header = 0;
473 
474 	sctp_userspace_set_threadname("SCTP/IP6 rcv");
475 
476 	recvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
477 
478 	for (;;) {
479 		for (i = 0; i < to_fill; i++) {
480 			/* Not getting the packet header. Tests with chain of one run
481 			   as usual without having the packet header.
482 			   Have tried both sending and receiving
483 			 */
484 			recvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
485 #if !defined(__Userspace_os_Windows)
486 			recv_iovec[i].iov_base = (caddr_t)recvmbuf6[i]->m_data;
487 			recv_iovec[i].iov_len = iovlen;
488 #else
489 			recv_iovec[i].buf = (caddr_t)recvmbuf6[i]->m_data;
490 			recv_iovec[i].len = iovlen;
491 #endif
492 		}
493 		to_fill = 0;
494 #if defined(__Userspace_os_Windows)
495 		ncounter = 0;
496 		memset(&from, 0, sizeof(struct sockaddr_in6));
497 		nResult = WSAIoctl(SCTP_BASE_VAR(userspace_rawsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER,
498 		                   &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
499 		                   &WSARecvMsg, sizeof WSARecvMsg,
500 		                   &ncounter, NULL, NULL);
501 		if (nResult == 0) {
502 			msg.name = (void *)&src;
503 			msg.namelen = sizeof(struct sockaddr_in6);
504 			msg.lpBuffers = recv_iovec;
505 			msg.dwBufferCount = MAXLEN_MBUF_CHAIN;
506 			msg.Control.len = sizeof ControlBuffer;
507 			msg.Control.buf = ControlBuffer;
508 			msg.dwFlags = 0;
509 			nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, &ncounter, NULL, NULL);
510 		}
511 		if (nResult != 0) {
512 			m_ErrorCode = WSAGetLastError();
513 			if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
514 				break;
515 			}
516 			continue;
517 		}
518 		n = ncounter;
519 #else
520 		memset(&msg, 0, sizeof(struct msghdr));
521 		memset(&src, 0, sizeof(struct sockaddr_in6));
522 		memset(&dst, 0, sizeof(struct sockaddr_in6));
523 		memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo)));
524 		msg.msg_name = (void *)&src;
525 		msg.msg_namelen = sizeof(struct sockaddr_in6);
526 		msg.msg_iov = recv_iovec;
527 		msg.msg_iovlen = MAXLEN_MBUF_CHAIN;
528 		msg.msg_control = (void *)cmsgbuf;
529 		msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo));
530 		msg.msg_flags = 0;
531 
532 		ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg, 0);
533 		if (n < 0) {
534 			if (errno == EAGAIN || errno == EINTR) {
535 				continue;
536 			} else {
537 				break;
538 			}
539 		}
540 #endif
541 		SCTP_HEADER_LEN(recvmbuf6[0]) = n; /* length of total packet */
542 		SCTP_STAT_INCR(sctps_recvpackets);
543 		SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
544 
545 		if ((unsigned int)n <= iovlen) {
546 			SCTP_BUF_LEN(recvmbuf6[0]) = n;
547 			(to_fill)++;
548 		} else {
549 			i = 0;
550 			SCTP_BUF_LEN(recvmbuf6[0]) = iovlen;
551 
552 			ncounter -= min(ncounter, iovlen);
553 			(to_fill)++;
554 			do {
555 				recvmbuf6[i]->m_next = recvmbuf6[i+1];
556 				SCTP_BUF_LEN(recvmbuf6[i]->m_next) = min(ncounter, iovlen);
557 				i++;
558 				ncounter -= min(ncounter, iovlen);
559 				(to_fill)++;
560 			} while (ncounter > 0);
561 		}
562 
563 		for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
564 			if ((cmsgptr->cmsg_level == IPPROTO_IPV6) && (cmsgptr->cmsg_type == IPV6_PKTINFO)) {
565 				struct in6_pktinfo * info;
566 
567 				info = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
568 				memcpy((void *)&dst.sin6_addr, (const void *) &(info->ipi6_addr), sizeof(struct in6_addr));
569 				break;
570 			}
571 		}
572 
573 		/* SCTP does not allow broadcasts or multicasts */
574 		if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) {
575 			m_freem(recvmbuf6[0]);
576 			continue;
577 		}
578 
579 		sh = mtod(recvmbuf6[0], struct sctphdr *);
580 		ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
581 		offset = sizeof(struct sctphdr);
582 
583 		dst.sin6_family = AF_INET6;
584 #ifdef HAVE_SIN6_LEN
585 		dst.sin6_len = sizeof(struct sockaddr_in6);
586 #endif
587 		dst.sin6_port = sh->dest_port;
588 
589 		src.sin6_family = AF_INET6;
590 #ifdef HAVE_SIN6_LEN
591 		src.sin6_len = sizeof(struct sockaddr_in6);
592 #endif
593 		src.sin6_port = sh->src_port;
594 		if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
595 		    (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) {
596 			compute_crc = 0;
597 			SCTP_STAT_INCR(sctps_recvhwcrc);
598 		} else {
599 			SCTP_STAT_INCR(sctps_recvswcrc);
600 		}
601 		SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
602 		SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset);
603 		sctp_common_input_processing(&recvmbuf6[0], 0, offset, n,
604 		                             (struct sockaddr *)&src,
605 		                             (struct sockaddr *)&dst,
606 		                             sh, ch,
607 		                             compute_crc,
608 		                             0,
609 		                             SCTP_DEFAULT_VRFID, 0);
610 		if (recvmbuf6[0]) {
611 			m_freem(recvmbuf6[0]);
612 		}
613 	}
614 	for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) {
615 		m_free(recvmbuf6[i]);
616 	}
617 	/* free the array itself */
618 	free(recvmbuf6);
619 	SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/IP6 rcv", __func__);
620 	return (NULL);
621 }
622 #endif
623 
624 #ifdef INET
625 static void *
recv_function_udp(void * arg)626 recv_function_udp(void *arg)
627 {
628 	struct mbuf **udprecvmbuf;
629 	/*Initially the entire set of mbufs is to be allocated.
630 	  to_fill indicates this amount. */
631 	int to_fill = MAXLEN_MBUF_CHAIN;
632 	/* iovlen is the size of each mbuf in the chain */
633 	int i, n, offset;
634 	unsigned int iovlen = MCLBYTES;
635 	int want_ext = (iovlen > MLEN)? 1 : 0;
636 	int want_header = 0;
637 	struct sctphdr *sh;
638 	uint16_t port;
639 	struct sctp_chunkhdr *ch;
640 	struct sockaddr_in src, dst;
641 #if defined(IP_PKTINFO)
642 	char cmsgbuf[CMSG_SPACE(sizeof(struct in_pktinfo))];
643 #else
644 	char cmsgbuf[CMSG_SPACE(sizeof(struct in_addr))];
645 #endif
646 	int compute_crc = 1;
647 #if !defined(__Userspace_os_Windows)
648 	unsigned int ncounter;
649 	struct iovec iov[MAXLEN_MBUF_CHAIN];
650 	struct msghdr msg;
651 	struct cmsghdr *cmsgptr;
652 #else
653 	GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
654 	LPFN_WSARECVMSG WSARecvMsg;
655 	char ControlBuffer[1024];
656 	WSABUF iov[MAXLEN_MBUF_CHAIN];
657 	WSAMSG msg;
658 	int nResult, m_ErrorCode;
659 	WSACMSGHDR *cmsgptr;
660 	DWORD ncounter;
661 #endif
662 
663 	sctp_userspace_set_threadname("SCTP/UDP/IP4 rcv");
664 
665 	udprecvmbuf = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
666 
667 	while (1) {
668 		for (i = 0; i < to_fill; i++) {
669 			/* Not getting the packet header. Tests with chain of one run
670 			   as usual without having the packet header.
671 			   Have tried both sending and receiving
672 			 */
673 			udprecvmbuf[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
674 #if !defined(__Userspace_os_Windows)
675 			iov[i].iov_base = (caddr_t)udprecvmbuf[i]->m_data;
676 			iov[i].iov_len = iovlen;
677 #else
678 			iov[i].buf = (caddr_t)udprecvmbuf[i]->m_data;
679 			iov[i].len = iovlen;
680 #endif
681 		}
682 		to_fill = 0;
683 #if !defined(__Userspace_os_Windows)
684 		memset(&msg, 0, sizeof(struct msghdr));
685 #else
686 		memset(&msg, 0, sizeof(WSAMSG));
687 #endif
688 		memset(&src, 0, sizeof(struct sockaddr_in));
689 		memset(&dst, 0, sizeof(struct sockaddr_in));
690 		memset(cmsgbuf, 0, sizeof(cmsgbuf));
691 
692 #if !defined(__Userspace_os_Windows)
693 		msg.msg_name = (void *)&src;
694 		msg.msg_namelen = sizeof(struct sockaddr_in);
695 		msg.msg_iov = iov;
696 		msg.msg_iovlen = MAXLEN_MBUF_CHAIN;
697 		msg.msg_control = (void *)cmsgbuf;
698 		msg.msg_controllen = sizeof(cmsgbuf);
699 		msg.msg_flags = 0;
700 
701 		ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, 0);
702 		if (n < 0) {
703 			if (errno == EAGAIN || errno == EINTR) {
704 				continue;
705 			} else {
706 				break;
707 			}
708 		}
709 #else
710 		nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp), SIO_GET_EXTENSION_FUNCTION_POINTER,
711 		 &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
712 		 &WSARecvMsg, sizeof WSARecvMsg,
713 		 &ncounter, NULL, NULL);
714 		if (nResult == 0) {
715 			msg.name = (void *)&src;
716 			msg.namelen = sizeof(struct sockaddr_in);
717 			msg.lpBuffers = iov;
718 			msg.dwBufferCount = MAXLEN_MBUF_CHAIN;
719 			msg.Control.len = sizeof ControlBuffer;
720 			msg.Control.buf = ControlBuffer;
721 			msg.dwFlags = 0;
722 			nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_udpsctp), &msg, &ncounter, NULL, NULL);
723 		}
724 		if (nResult != 0) {
725 			m_ErrorCode = WSAGetLastError();
726 			if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
727 				break;
728 			}
729 			continue;
730 		}
731 		n = ncounter;
732 #endif
733 		SCTP_HEADER_LEN(udprecvmbuf[0]) = n; /* length of total packet */
734 		SCTP_STAT_INCR(sctps_recvpackets);
735 		SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
736 
737 		if ((unsigned int)n <= iovlen) {
738 			SCTP_BUF_LEN(udprecvmbuf[0]) = n;
739 			(to_fill)++;
740 		} else {
741 			i = 0;
742 			SCTP_BUF_LEN(udprecvmbuf[0]) = iovlen;
743 
744 			ncounter -= min(ncounter, iovlen);
745 			(to_fill)++;
746 			do {
747 				udprecvmbuf[i]->m_next = udprecvmbuf[i+1];
748 				SCTP_BUF_LEN(udprecvmbuf[i]->m_next) = min(ncounter, iovlen);
749 				i++;
750 				ncounter -= min(ncounter, iovlen);
751 				(to_fill)++;
752 			} while (ncounter > 0);
753 		}
754 
755 		for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
756 #if defined(IP_PKTINFO)
757 			if ((cmsgptr->cmsg_level == IPPROTO_IP) && (cmsgptr->cmsg_type == IP_PKTINFO)) {
758 				struct in_pktinfo *info;
759 
760 				dst.sin_family = AF_INET;
761 #ifdef HAVE_SIN_LEN
762 				dst.sin_len = sizeof(struct sockaddr_in);
763 #endif
764 				info = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
765 				memcpy((void *)&dst.sin_addr, (const void *)&(info->ipi_addr), sizeof(struct in_addr));
766 				break;
767 			}
768 #else
769 			if ((cmsgptr->cmsg_level == IPPROTO_IP) && (cmsgptr->cmsg_type == IP_RECVDSTADDR)) {
770 				struct in_addr *addr;
771 
772 				dst.sin_family = AF_INET;
773 #ifdef HAVE_SIN_LEN
774 				dst.sin_len = sizeof(struct sockaddr_in);
775 #endif
776 				addr = (struct in_addr *)CMSG_DATA(cmsgptr);
777 				memcpy((void *)&dst.sin_addr, (const void *)addr, sizeof(struct in_addr));
778 				break;
779 			}
780 #endif
781 		}
782 
783 		/* SCTP does not allow broadcasts or multicasts */
784 		if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
785 			m_freem(udprecvmbuf[0]);
786 			continue;
787 		}
788 		if (SCTP_IS_IT_BROADCAST(dst.sin_addr, udprecvmbuf[0])) {
789 			m_freem(udprecvmbuf[0]);
790 			continue;
791 		}
792 
793 		/*offset = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);*/
794 		sh = mtod(udprecvmbuf[0], struct sctphdr *);
795 		ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
796 		offset = sizeof(struct sctphdr);
797 		port = src.sin_port;
798 		src.sin_port = sh->src_port;
799 		dst.sin_port = sh->dest_port;
800 		if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
801 		    (src.sin_addr.s_addr == dst.sin_addr.s_addr)) {
802 			compute_crc = 0;
803 			SCTP_STAT_INCR(sctps_recvhwcrc);
804 		} else {
805 			SCTP_STAT_INCR(sctps_recvswcrc);
806 		}
807 		SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
808 		SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset);
809 		sctp_common_input_processing(&udprecvmbuf[0], 0, offset, n,
810 		                             (struct sockaddr *)&src,
811 		                             (struct sockaddr *)&dst,
812 		                             sh, ch,
813 		                             compute_crc,
814 		                             0,
815 		                             SCTP_DEFAULT_VRFID, port);
816 		if (udprecvmbuf[0]) {
817 			m_freem(udprecvmbuf[0]);
818 		}
819 	}
820 	for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) {
821 		m_free(udprecvmbuf[i]);
822 	}
823 	/* free the array itself */
824 	free(udprecvmbuf);
825 	SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP4 rcv", __func__);
826 	return (NULL);
827 }
828 #endif
829 
830 #if defined(INET6)
831 static void *
recv_function_udp6(void * arg)832 recv_function_udp6(void *arg)
833 {
834 	struct mbuf **udprecvmbuf6;
835 	/*Initially the entire set of mbufs is to be allocated.
836 	  to_fill indicates this amount. */
837 	int to_fill = MAXLEN_MBUF_CHAIN;
838 	/* iovlen is the size of each mbuf in the chain */
839 	int i, n, offset;
840 	unsigned int iovlen = MCLBYTES;
841 	int want_ext = (iovlen > MLEN)? 1 : 0;
842 	int want_header = 0;
843 	struct sockaddr_in6 src, dst;
844 	struct sctphdr *sh;
845 	uint16_t port;
846 	struct sctp_chunkhdr *ch;
847 	char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
848 	int compute_crc = 1;
849 #if !defined(__Userspace_os_Windows)
850 	struct iovec iov[MAXLEN_MBUF_CHAIN];
851 	struct msghdr msg;
852 	struct cmsghdr *cmsgptr;
853 	unsigned int ncounter;
854 #else
855 	GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
856 	LPFN_WSARECVMSG WSARecvMsg;
857 	char ControlBuffer[1024];
858 	WSABUF iov[MAXLEN_MBUF_CHAIN];
859 	WSAMSG msg;
860 	int nResult, m_ErrorCode;
861 	WSACMSGHDR *cmsgptr;
862 	DWORD ncounter;
863 #endif
864 
865 	sctp_userspace_set_threadname("SCTP/UDP/IP6 rcv");
866 
867 	udprecvmbuf6 = malloc(sizeof(struct mbuf *) * MAXLEN_MBUF_CHAIN);
868 	while (1) {
869 		for (i = 0; i < to_fill; i++) {
870 			/* Not getting the packet header. Tests with chain of one run
871 			   as usual without having the packet header.
872 			   Have tried both sending and receiving
873 			 */
874 			udprecvmbuf6[i] = sctp_get_mbuf_for_msg(iovlen, want_header, M_NOWAIT, want_ext, MT_DATA);
875 #if !defined(__Userspace_os_Windows)
876 			iov[i].iov_base = (caddr_t)udprecvmbuf6[i]->m_data;
877 			iov[i].iov_len = iovlen;
878 #else
879 			iov[i].buf = (caddr_t)udprecvmbuf6[i]->m_data;
880 			iov[i].len = iovlen;
881 #endif
882 		}
883 		to_fill = 0;
884 
885 #if !defined(__Userspace_os_Windows)
886 		memset(&msg, 0, sizeof(struct msghdr));
887 #else
888 		memset(&msg, 0, sizeof(WSAMSG));
889 #endif
890 		memset(&src, 0, sizeof(struct sockaddr_in6));
891 		memset(&dst, 0, sizeof(struct sockaddr_in6));
892 		memset(cmsgbuf, 0, CMSG_SPACE(sizeof (struct in6_pktinfo)));
893 
894 #if !defined(__Userspace_os_Windows)
895 		msg.msg_name = (void *)&src;
896 		msg.msg_namelen = sizeof(struct sockaddr_in6);
897 		msg.msg_iov = iov;
898 		msg.msg_iovlen = MAXLEN_MBUF_CHAIN;
899 		msg.msg_control = (void *)cmsgbuf;
900 		msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof (struct in6_pktinfo));
901 		msg.msg_flags = 0;
902 
903 		ncounter = n = recvmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, 0);
904 		if (n < 0) {
905 			if (errno == EAGAIN || errno == EINTR) {
906 				continue;
907 			} else {
908 				break;
909 			}
910 		}
911 #else
912 		nResult = WSAIoctl(SCTP_BASE_VAR(userspace_udpsctp6), SIO_GET_EXTENSION_FUNCTION_POINTER,
913 		                   &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
914 		                   &WSARecvMsg, sizeof WSARecvMsg,
915 		                   &ncounter, NULL, NULL);
916 		if (nResult == SOCKET_ERROR) {
917 			m_ErrorCode = WSAGetLastError();
918 			WSARecvMsg = NULL;
919 		}
920 		if (nResult == 0) {
921 			msg.name = (void *)&src;
922 			msg.namelen = sizeof(struct sockaddr_in6);
923 			msg.lpBuffers = iov;
924 			msg.dwBufferCount = MAXLEN_MBUF_CHAIN;
925 			msg.Control.len = sizeof ControlBuffer;
926 			msg.Control.buf = ControlBuffer;
927 			msg.dwFlags = 0;
928 			nResult = WSARecvMsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg, &ncounter, NULL, NULL);
929 		}
930 		if (nResult != 0) {
931 			m_ErrorCode = WSAGetLastError();
932 			if ((m_ErrorCode == WSAENOTSOCK) || (m_ErrorCode == WSAEINTR)) {
933 				break;
934 			}
935 			continue;
936 		}
937 		n = ncounter;
938 #endif
939 		SCTP_HEADER_LEN(udprecvmbuf6[0]) = n; /* length of total packet */
940 		SCTP_STAT_INCR(sctps_recvpackets);
941 		SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
942 
943 		if ((unsigned int)n <= iovlen) {
944 			SCTP_BUF_LEN(udprecvmbuf6[0]) = n;
945 			(to_fill)++;
946 		} else {
947 			i = 0;
948 			SCTP_BUF_LEN(udprecvmbuf6[0]) = iovlen;
949 
950 			ncounter -= min(ncounter, iovlen);
951 			(to_fill)++;
952 			do {
953 				udprecvmbuf6[i]->m_next = udprecvmbuf6[i+1];
954 				SCTP_BUF_LEN(udprecvmbuf6[i]->m_next) = min(ncounter, iovlen);
955 				i++;
956 				ncounter -= min(ncounter, iovlen);
957 				(to_fill)++;
958 			} while (ncounter > 0);
959 		}
960 
961 		for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
962 			if ((cmsgptr->cmsg_level == IPPROTO_IPV6) && (cmsgptr->cmsg_type == IPV6_PKTINFO)) {
963 				struct in6_pktinfo *info;
964 
965 				dst.sin6_family = AF_INET6;
966 #ifdef HAVE_SIN6_LEN
967 				dst.sin6_len = sizeof(struct sockaddr_in6);
968 #endif
969 				info = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
970 				/*dst.sin6_port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));*/
971 				memcpy((void *)&dst.sin6_addr, (const void *)&(info->ipi6_addr), sizeof(struct in6_addr));
972 			}
973 		}
974 
975 		/* SCTP does not allow broadcasts or multicasts */
976 		if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) {
977 			m_freem(udprecvmbuf6[0]);
978 			continue;
979 		}
980 
981 		sh = mtod(udprecvmbuf6[0], struct sctphdr *);
982 		ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
983 		offset = sizeof(struct sctphdr);
984 
985 		port = src.sin6_port;
986 		src.sin6_port = sh->src_port;
987 		dst.sin6_port = sh->dest_port;
988 		if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
989 		    (memcmp(&src.sin6_addr, &dst.sin6_addr, sizeof(struct in6_addr)) == 0)) {
990 			compute_crc = 0;
991 			SCTP_STAT_INCR(sctps_recvhwcrc);
992 		} else {
993 			SCTP_STAT_INCR(sctps_recvswcrc);
994 		}
995 		SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n);
996 		SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", (int)sizeof(struct sctphdr));
997 		sctp_common_input_processing(&udprecvmbuf6[0], 0, offset, n,
998 		                             (struct sockaddr *)&src,
999 		                             (struct sockaddr *)&dst,
1000 		                             sh, ch,
1001 		                             compute_crc,
1002 		                             0,
1003 		                             SCTP_DEFAULT_VRFID, port);
1004 		if (udprecvmbuf6[0]) {
1005 			m_freem(udprecvmbuf6[0]);
1006 		}
1007 	}
1008 	for (i = 0; i < MAXLEN_MBUF_CHAIN; i++) {
1009 		m_free(udprecvmbuf6[i]);
1010 	}
1011 	/* free the array itself */
1012 	free(udprecvmbuf6);
1013 	SCTPDBG(SCTP_DEBUG_USR, "%s: Exiting SCTP/UDP/IP6 rcv", __func__);
1014 	return (NULL);
1015 }
1016 #endif
1017 
1018 #if defined (__Userspace_os_Windows)
1019 static void
setReceiveBufferSize(SOCKET sfd,int new_size)1020 setReceiveBufferSize(SOCKET sfd, int new_size)
1021 #else
1022 static void
1023 setReceiveBufferSize(int sfd, int new_size)
1024 #endif
1025 {
1026 	int ch = new_size;
1027 
1028 	if (setsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)&ch, sizeof(ch)) < 0) {
1029 #if defined (__Userspace_os_Windows)
1030 		SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", WSAGetLastError());
1031 #else
1032 		SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", errno);
1033 #endif
1034 	}
1035 	return;
1036 }
1037 
1038 #if defined (__Userspace_os_Windows)
1039 static void
setSendBufferSize(SOCKET sfd,int new_size)1040 setSendBufferSize(SOCKET sfd, int new_size)
1041 #else
1042 static void
1043 setSendBufferSize(int sfd, int new_size)
1044 #endif
1045 {
1046 	int ch = new_size;
1047 
1048 	if (setsockopt (sfd, SOL_SOCKET, SO_SNDBUF, (void*)&ch, sizeof(ch)) < 0) {
1049 #if defined (__Userspace_os_Windows)
1050 		SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", WSAGetLastError());
1051 #else
1052 		SCTPDBG(SCTP_DEBUG_USR, "Can't set send-buffers size (errno = %d).\n", errno);
1053 #endif
1054 	}
1055 	return;
1056 }
1057 
1058 #define SOCKET_TIMEOUT 100 /* in ms */
1059 void
recv_thread_init(void)1060 recv_thread_init(void)
1061 {
1062 #if defined(INET)
1063 	struct sockaddr_in addr_ipv4;
1064 	const int hdrincl = 1;
1065 #endif
1066 #if defined(INET6)
1067 	struct sockaddr_in6 addr_ipv6;
1068 #endif
1069 #if defined(INET) || defined(INET6)
1070 	const int on = 1;
1071 #endif
1072 #if !defined(__Userspace_os_Windows)
1073 	struct timeval timeout;
1074 
1075 	memset(&timeout, 0, sizeof(struct timeval));
1076 	timeout.tv_sec  = (SOCKET_TIMEOUT / 1000);
1077 	timeout.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
1078 #else
1079 	unsigned int timeout = SOCKET_TIMEOUT; /* Timeout in milliseconds */
1080 #endif
1081 #if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
1082 	if (SCTP_BASE_VAR(userspace_route) == -1) {
1083 		if ((SCTP_BASE_VAR(userspace_route) = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
1084 			SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d).\n", errno);
1085 		}
1086 #if 0
1087 		struct sockaddr_nl sanl;
1088 
1089 		if ((SCTP_BASE_VAR(userspace_route) = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
1090 			SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d.\n", errno);
1091 		}
1092 		memset(&sanl, 0, sizeof(sanl));
1093 		sanl.nl_family = AF_NETLINK;
1094 		sanl.nl_groups = 0;
1095 #ifdef INET
1096 		sanl.nl_groups |= RTMGRP_IPV4_IFADDR;
1097 #endif
1098 #ifdef INET6
1099 		sanl.nl_groups |= RTMGRP_IPV6_IFADDR;
1100 #endif
1101 		if (bind(SCTP_BASE_VAR(userspace_route), (struct sockaddr *) &sanl, sizeof(sanl)) < 0) {
1102 			SCTPDBG(SCTP_DEBUG_USR, "Can't bind routing socket (errno = %d).\n", errno);
1103 			close(SCTP_BASE_VAR(userspace_route));
1104 			SCTP_BASE_VAR(userspace_route) = -1;
1105 		}
1106 #endif
1107 		if (SCTP_BASE_VAR(userspace_route) != -1) {
1108 			if (setsockopt(SCTP_BASE_VAR(userspace_route), SOL_SOCKET, SO_RCVTIMEO,(const void*)&timeout, sizeof(struct timeval)) < 0) {
1109 				SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on routing socket (errno = %d).\n", errno);
1110 #if defined(__Userspace_os_Windows)
1111 				closesocket(SCTP_BASE_VAR(userspace_route));
1112 #else
1113 				close(SCTP_BASE_VAR(userspace_route));
1114 #endif
1115 				SCTP_BASE_VAR(userspace_route) = -1;
1116 			}
1117 		}
1118 	}
1119 #endif
1120 #if defined(INET)
1121 	if (SCTP_BASE_VAR(userspace_rawsctp) == -1) {
1122 		if ((SCTP_BASE_VAR(userspace_rawsctp) = socket(AF_INET, SOCK_RAW, IPPROTO_SCTP)) == -1) {
1123 #if defined(__Userspace_os_Windows)
1124 			SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", WSAGetLastError());
1125 #else
1126 			SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", errno);
1127 #endif
1128 		} else {
1129 			/* complete setting up the raw SCTP socket */
1130 			if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), IPPROTO_IP, IP_HDRINCL,(const void*)&hdrincl, sizeof(int)) < 0) {
1131 #if defined(__Userspace_os_Windows)
1132 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_HDRINCL (errno = %d).\n", WSAGetLastError());
1133 				closesocket(SCTP_BASE_VAR(userspace_rawsctp));
1134 #else
1135 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_HDRINCL (errno = %d).\n", errno);
1136 				close(SCTP_BASE_VAR(userspace_rawsctp));
1137 #endif
1138 				SCTP_BASE_VAR(userspace_rawsctp) = -1;
1139 			} else if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
1140 #if defined(__Userspace_os_Windows)
1141 				SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError());
1142 				closesocket(SCTP_BASE_VAR(userspace_rawsctp));
1143 #else
1144 				SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv4 (errno = %d).\n", errno);
1145 				close(SCTP_BASE_VAR(userspace_rawsctp));
1146 #endif
1147 				SCTP_BASE_VAR(userspace_rawsctp) = -1;
1148 			} else {
1149 				memset((void *)&addr_ipv4, 0, sizeof(struct sockaddr_in));
1150 #ifdef HAVE_SIN_LEN
1151 				addr_ipv4.sin_len         = sizeof(struct sockaddr_in);
1152 #endif
1153 				addr_ipv4.sin_family      = AF_INET;
1154 				addr_ipv4.sin_port        = htons(0);
1155 				addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
1156 				if (bind(SCTP_BASE_VAR(userspace_rawsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) {
1157 #if defined(__Userspace_os_Windows)
1158 					SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv4 (errno = %d).\n", WSAGetLastError());
1159 					closesocket(SCTP_BASE_VAR(userspace_rawsctp));
1160 #else
1161 					SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv4 (errno = %d).\n", errno);
1162 					close(SCTP_BASE_VAR(userspace_rawsctp));
1163 #endif
1164 					SCTP_BASE_VAR(userspace_rawsctp) = -1;
1165 				} else {
1166 					setReceiveBufferSize(SCTP_BASE_VAR(userspace_rawsctp), SB_RAW); /* 128K */
1167 					setSendBufferSize(SCTP_BASE_VAR(userspace_rawsctp), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */
1168 				}
1169 			}
1170 		}
1171 	}
1172 	if (SCTP_BASE_VAR(userspace_udpsctp) == -1) {
1173 		if ((SCTP_BASE_VAR(userspace_udpsctp) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
1174 #if defined(__Userspace_os_Windows)
1175 			SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
1176 #else
1177 			SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", errno);
1178 #endif
1179 		} else {
1180 #if defined(IP_PKTINFO)
1181 			if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), IPPROTO_IP, IP_PKTINFO, (const void *)&on, (int)sizeof(int)) < 0) {
1182 #else
1183 			if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), IPPROTO_IP, IP_RECVDSTADDR, (const void *)&on, (int)sizeof(int)) < 0) {
1184 #endif
1185 #if defined(__Userspace_os_Windows)
1186 #if defined(IP_PKTINFO)
1187 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_PKTINFO on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
1188 #else
1189 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_RECVDSTADDR on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
1190 #endif
1191 				closesocket(SCTP_BASE_VAR(userspace_udpsctp));
1192 #else
1193 #if defined(IP_PKTINFO)
1194 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_PKTINFO on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno);
1195 #else
1196 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IP_RECVDSTADDR on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno);
1197 #endif
1198 				close(SCTP_BASE_VAR(userspace_udpsctp));
1199 #endif
1200 				SCTP_BASE_VAR(userspace_udpsctp) = -1;
1201 			} else if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
1202 #if defined(__Userspace_os_Windows)
1203 				SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
1204 				closesocket(SCTP_BASE_VAR(userspace_udpsctp));
1205 #else
1206 				SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv4 (errno = %d).\n", errno);
1207 				close(SCTP_BASE_VAR(userspace_udpsctp));
1208 #endif
1209 				SCTP_BASE_VAR(userspace_udpsctp) = -1;
1210 			} else {
1211 				memset((void *)&addr_ipv4, 0, sizeof(struct sockaddr_in));
1212 #ifdef HAVE_SIN_LEN
1213 				addr_ipv4.sin_len         = sizeof(struct sockaddr_in);
1214 #endif
1215 				addr_ipv4.sin_family      = AF_INET;
1216 				addr_ipv4.sin_port        = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
1217 				addr_ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
1218 				if (bind(SCTP_BASE_VAR(userspace_udpsctp), (const struct sockaddr *)&addr_ipv4, sizeof(struct sockaddr_in)) < 0) {
1219 #if defined(__Userspace_os_Windows)
1220 					SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError());
1221 					closesocket(SCTP_BASE_VAR(userspace_udpsctp));
1222 #else
1223 					SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv4 (errno = %d).\n", errno);
1224 					close(SCTP_BASE_VAR(userspace_udpsctp));
1225 #endif
1226 					SCTP_BASE_VAR(userspace_udpsctp) = -1;
1227 				} else {
1228 					setReceiveBufferSize(SCTP_BASE_VAR(userspace_udpsctp), SB_RAW); /* 128K */
1229 					setSendBufferSize(SCTP_BASE_VAR(userspace_udpsctp), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */
1230 				}
1231 			}
1232 		}
1233 	}
1234 #endif
1235 #if defined(INET6)
1236 	if (SCTP_BASE_VAR(userspace_rawsctp6) == -1) {
1237 		if ((SCTP_BASE_VAR(userspace_rawsctp6) = socket(AF_INET6, SOCK_RAW, IPPROTO_SCTP)) == -1) {
1238 #if defined(__Userspace_os_Windows)
1239 			SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
1240 #else
1241 			SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", errno);
1242 #endif
1243 		} else {
1244 			/* complete setting up the raw SCTP socket */
1245 #if defined(IPV6_RECVPKTINFO)
1246 			if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, sizeof(on)) < 0) {
1247 #if defined(__Userspace_os_Windows)
1248 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
1249 				closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
1250 #else
1251 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/IPv6 (errno = %d).\n", errno);
1252 				close(SCTP_BASE_VAR(userspace_rawsctp6));
1253 #endif
1254 				SCTP_BASE_VAR(userspace_rawsctp6) = -1;
1255 			} else {
1256 #else
1257 			if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_PKTINFO,(const void*)&on, sizeof(on)) < 0) {
1258 #if defined(__Userspace_os_Windows)
1259 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
1260 				closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
1261 #else
1262 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/IPv6 (errno = %d).\n", errno);
1263 				close(SCTP_BASE_VAR(userspace_rawsctp6));
1264 #endif
1265 				SCTP_BASE_VAR(userspace_rawsctp6) = -1;
1266 			} else {
1267 #endif
1268 				if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&on, (socklen_t)sizeof(on)) < 0) {
1269 #if defined(__Userspace_os_Windows)
1270 					SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
1271 #else
1272 					SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/IPv6 (errno = %d).\n", errno);
1273 #endif
1274 				}
1275 				if (setsockopt(SCTP_BASE_VAR(userspace_rawsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
1276 #if defined(__Userspace_os_Windows)
1277 					SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
1278 					closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
1279 #else
1280 					SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/IPv6 (errno = %d).\n", errno);
1281 					close(SCTP_BASE_VAR(userspace_rawsctp6));
1282 #endif
1283 					SCTP_BASE_VAR(userspace_rawsctp6) = -1;
1284 				} else {
1285 					memset((void *)&addr_ipv6, 0, sizeof(struct sockaddr_in6));
1286 #ifdef HAVE_SIN6_LEN
1287 					addr_ipv6.sin6_len         = sizeof(struct sockaddr_in6);
1288 #endif
1289 					addr_ipv6.sin6_family      = AF_INET6;
1290 					addr_ipv6.sin6_port        = htons(0);
1291 					addr_ipv6.sin6_addr        = in6addr_any;
1292 					if (bind(SCTP_BASE_VAR(userspace_rawsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) {
1293 #if defined(__Userspace_os_Windows)
1294 						SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError());
1295 						closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
1296 #else
1297 						SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/IPv6 (errno = %d).\n", errno);
1298 						close(SCTP_BASE_VAR(userspace_rawsctp6));
1299 #endif
1300 						SCTP_BASE_VAR(userspace_rawsctp6) = -1;
1301 					} else {
1302 						setReceiveBufferSize(SCTP_BASE_VAR(userspace_rawsctp6), SB_RAW); /* 128K */
1303 						setSendBufferSize(SCTP_BASE_VAR(userspace_rawsctp6), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */
1304 					}
1305 				}
1306 			}
1307 		}
1308 	}
1309 	if (SCTP_BASE_VAR(userspace_udpsctp6) == -1) {
1310 		if ((SCTP_BASE_VAR(userspace_udpsctp6) = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
1311 #if defined(__Userspace_os_Windows)
1312 			SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
1313 #else
1314 			SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
1315 #endif
1316 		}
1317 #if defined(IPV6_RECVPKTINFO)
1318 		if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void *)&on, (int)sizeof(int)) < 0) {
1319 #if defined(__Userspace_os_Windows)
1320 			SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
1321 			closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
1322 #else
1323 			SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_RECVPKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
1324 			close(SCTP_BASE_VAR(userspace_udpsctp6));
1325 #endif
1326 			SCTP_BASE_VAR(userspace_udpsctp6) = -1;
1327 		} else {
1328 #else
1329 		if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_PKTINFO, (const void *)&on, (int)sizeof(int)) < 0) {
1330 #if defined(__Userspace_os_Windows)
1331 			SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
1332 			closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
1333 #else
1334 			SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_PKTINFO on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
1335 			close(SCTP_BASE_VAR(userspace_udpsctp6));
1336 #endif
1337 			SCTP_BASE_VAR(userspace_udpsctp6) = -1;
1338 		} else {
1339 #endif
1340 			if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, (socklen_t)sizeof(on)) < 0) {
1341 #if defined(__Userspace_os_Windows)
1342 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
1343 #else
1344 				SCTPDBG(SCTP_DEBUG_USR, "Can't set IPV6_V6ONLY on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
1345 #endif
1346 			}
1347 			if (setsockopt(SCTP_BASE_VAR(userspace_udpsctp6), SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)) < 0) {
1348 #if defined(__Userspace_os_Windows)
1349 				SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
1350 				closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
1351 #else
1352 				SCTPDBG(SCTP_DEBUG_USR, "Can't set timeout on socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
1353 				close(SCTP_BASE_VAR(userspace_udpsctp6));
1354 #endif
1355 				SCTP_BASE_VAR(userspace_udpsctp6) = -1;
1356 			} else {
1357 				memset((void *)&addr_ipv6, 0, sizeof(struct sockaddr_in6));
1358 #ifdef HAVE_SIN6_LEN
1359 				addr_ipv6.sin6_len         = sizeof(struct sockaddr_in6);
1360 #endif
1361 				addr_ipv6.sin6_family      = AF_INET6;
1362 				addr_ipv6.sin6_port        = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
1363 				addr_ipv6.sin6_addr        = in6addr_any;
1364 				if (bind(SCTP_BASE_VAR(userspace_udpsctp6), (const struct sockaddr *)&addr_ipv6, sizeof(struct sockaddr_in6)) < 0) {
1365 #if defined(__Userspace_os_Windows)
1366 					SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError());
1367 					closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
1368 #else
1369 					SCTPDBG(SCTP_DEBUG_USR, "Can't bind socket for SCTP/UDP/IPv6 (errno = %d).\n", errno);
1370 					close(SCTP_BASE_VAR(userspace_udpsctp6));
1371 #endif
1372 					SCTP_BASE_VAR(userspace_udpsctp6) = -1;
1373 				} else {
1374 					setReceiveBufferSize(SCTP_BASE_VAR(userspace_udpsctp6), SB_RAW); /* 128K */
1375 					setSendBufferSize(SCTP_BASE_VAR(userspace_udpsctp6), SB_RAW); /* 128K Is this setting net.inet.raw.maxdgram value? Should it be set to 64K? */
1376 				}
1377 			}
1378 		}
1379 	}
1380 #endif
1381 #if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
1382 #if defined(INET) || defined(INET6)
1383 	if (SCTP_BASE_VAR(userspace_route) != -1) {
1384 		int rc;
1385 
1386 		if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadroute), &recv_function_route))) {
1387 			SCTPDBG(SCTP_DEBUG_USR, "Can't start routing thread (%d).\n", rc);
1388 			close(SCTP_BASE_VAR(userspace_route));
1389 			SCTP_BASE_VAR(userspace_route) = -1;
1390 		}
1391 	}
1392 #endif
1393 #endif
1394 #if defined(INET)
1395 	if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
1396 		int rc;
1397 
1398 		if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw), &recv_function_raw))) {
1399 			SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv4 recv thread (%d).\n", rc);
1400 #if defined(__Userspace_os_Windows)
1401 			closesocket(SCTP_BASE_VAR(userspace_rawsctp));
1402 #else
1403 			close(SCTP_BASE_VAR(userspace_rawsctp));
1404 #endif
1405 			SCTP_BASE_VAR(userspace_rawsctp) = -1;
1406 		}
1407 	}
1408 	if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
1409 		int rc;
1410 
1411 		if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp), &recv_function_udp))) {
1412 			SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv4 recv thread (%d).\n", rc);
1413 #if defined(__Userspace_os_Windows)
1414 			closesocket(SCTP_BASE_VAR(userspace_udpsctp));
1415 #else
1416 			close(SCTP_BASE_VAR(userspace_udpsctp));
1417 #endif
1418 			SCTP_BASE_VAR(userspace_udpsctp) = -1;
1419 		}
1420 	}
1421 #endif
1422 #if defined(INET6)
1423 	if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
1424 		int rc;
1425 
1426 		if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadraw6), &recv_function_raw6))) {
1427 			SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/IPv6 recv thread (%d).\n", rc);
1428 #if defined(__Userspace_os_Windows)
1429 			closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
1430 #else
1431 			close(SCTP_BASE_VAR(userspace_rawsctp6));
1432 #endif
1433 			SCTP_BASE_VAR(userspace_rawsctp6) = -1;
1434 		}
1435 	}
1436 	if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
1437 		int rc;
1438 
1439 		if ((rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(recvthreadudp6), &recv_function_udp6))) {
1440 			SCTPDBG(SCTP_DEBUG_USR, "Can't start SCTP/UDP/IPv6 recv thread (%d).\n", rc);
1441 #if defined(__Userspace_os_Windows)
1442 			closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
1443 #else
1444 			close(SCTP_BASE_VAR(userspace_udpsctp6));
1445 #endif
1446 			SCTP_BASE_VAR(userspace_udpsctp6) = -1;
1447 		}
1448 	}
1449 #endif
1450 }
1451 
1452 void
1453 recv_thread_destroy(void)
1454 {
1455 #if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD)
1456 #if defined(INET) || defined(INET6)
1457 	if (SCTP_BASE_VAR(userspace_route) != -1) {
1458 		close(SCTP_BASE_VAR(userspace_route));
1459 		pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL);
1460 	}
1461 #endif
1462 #endif
1463 #if defined(INET)
1464 	if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
1465 #if defined(__Userspace_os_Windows)
1466 		closesocket(SCTP_BASE_VAR(userspace_rawsctp));
1467 		SCTP_BASE_VAR(userspace_rawsctp) = -1;
1468 		WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE);
1469 		CloseHandle(SCTP_BASE_VAR(recvthreadraw));
1470 #else
1471 		close(SCTP_BASE_VAR(userspace_rawsctp));
1472 		SCTP_BASE_VAR(userspace_rawsctp) = -1;
1473 		pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL);
1474 #endif
1475 	}
1476 	if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
1477 #if defined(__Userspace_os_Windows)
1478 		closesocket(SCTP_BASE_VAR(userspace_udpsctp));
1479 		SCTP_BASE_VAR(userspace_udpsctp) = -1;
1480 		WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE);
1481 		CloseHandle(SCTP_BASE_VAR(recvthreadudp));
1482 #else
1483 		close(SCTP_BASE_VAR(userspace_udpsctp));
1484 		SCTP_BASE_VAR(userspace_udpsctp) = -1;
1485 		pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL);
1486 #endif
1487 	}
1488 #endif
1489 #if defined(INET6)
1490 	if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
1491 #if defined(__Userspace_os_Windows)
1492 		closesocket(SCTP_BASE_VAR(userspace_rawsctp6));
1493 		SCTP_BASE_VAR(userspace_rawsctp6) = -1;
1494 		WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE);
1495 		CloseHandle(SCTP_BASE_VAR(recvthreadraw6));
1496 #else
1497 		close(SCTP_BASE_VAR(userspace_rawsctp6));
1498 		SCTP_BASE_VAR(userspace_rawsctp6) = -1;
1499 		pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL);
1500 #endif
1501 	}
1502 	if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
1503 #if defined(__Userspace_os_Windows)
1504 		SCTP_BASE_VAR(userspace_udpsctp6) = -1;
1505 		closesocket(SCTP_BASE_VAR(userspace_udpsctp6));
1506 		WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE);
1507 		CloseHandle(SCTP_BASE_VAR(recvthreadudp6));
1508 #else
1509 		close(SCTP_BASE_VAR(userspace_udpsctp6));
1510 		SCTP_BASE_VAR(userspace_udpsctp6) = -1;
1511 		pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL);
1512 #endif
1513 	}
1514 #endif
1515 }
1516 #else
1517 int foo;
1518 #endif
1519