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