Line data Source code
1 : /*-
2 : * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3 : * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4 : * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are met:
8 : *
9 : * a) Redistributions of source code must retain the above copyright notice,
10 : * this list of conditions and the following disclaimer.
11 : *
12 : * b) Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in
14 : * the documentation and/or other materials provided with the distribution.
15 : *
16 : * c) Neither the name of Cisco Systems, Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived
18 : * from this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 : * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 : * THE POSSIBILITY OF SUCH DAMAGE.
31 : */
32 :
33 : #ifdef __FreeBSD__
34 : #include <sys/cdefs.h>
35 : __FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 280459 2015-03-24 21:12:45Z tuexen $");
36 : #endif
37 :
38 : #include <netinet/sctp_os.h>
39 : #ifdef __FreeBSD__
40 : #include <sys/proc.h>
41 : #endif
42 : #include <netinet/sctp_pcb.h>
43 : #include <netinet/sctp_header.h>
44 : #include <netinet/sctp_var.h>
45 : #ifdef INET6
46 : #include <netinet6/sctp6_var.h>
47 : #endif
48 : #include <netinet/sctp_sysctl.h>
49 : #include <netinet/sctp_output.h>
50 : #include <netinet/sctp_uio.h>
51 : #include <netinet/sctp_asconf.h>
52 : #include <netinet/sctputil.h>
53 : #include <netinet/sctp_indata.h>
54 : #include <netinet/sctp_timer.h>
55 : #include <netinet/sctp_auth.h>
56 : #include <netinet/sctp_bsd_addr.h>
57 : #if defined(__Userspace__)
58 : #include <netinet/sctp_callout.h>
59 : #else
60 : #include <netinet/udp.h>
61 : #endif
62 :
63 : #if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
64 : #include <netinet/sctp_peeloff.h>
65 : #endif /* HAVE_SCTP_PEELOFF_SOCKOPT */
66 :
67 : #if defined(__APPLE__)
68 : #define APPLE_FILE_NO 7
69 : #endif
70 :
71 : extern struct sctp_cc_functions sctp_cc_functions[];
72 : extern struct sctp_ss_functions sctp_ss_functions[];
73 :
74 : void
75 : #if defined(__Userspace__)
76 0 : sctp_init(uint16_t port,
77 : int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
78 : void (*debug_printf)(const char *format, ...))
79 : #elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
80 : sctp_init(struct protosw *pp SCTP_UNUSED, struct domain *dp SCTP_UNUSED)
81 : #else
82 : sctp_init(void)
83 : #endif
84 : {
85 : #if !defined(__Panda__) && !defined(__Userspace__)
86 : u_long sb_max_adj;
87 :
88 : #endif
89 : #if defined(__Userspace__)
90 : #if defined(__Userspace_os_Windows)
91 : #if defined(INET) || defined(INET6)
92 : WSADATA wsaData;
93 :
94 : if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
95 : SCTP_PRINTF("WSAStartup failed\n");
96 : exit (-1);
97 : }
98 : #endif
99 : InitializeConditionVariable(&accept_cond);
100 : InitializeCriticalSection(&accept_mtx);
101 : #else
102 0 : pthread_cond_init(&accept_cond, NULL);
103 0 : pthread_mutex_init(&accept_mtx, NULL);
104 : #endif
105 : #endif
106 : /* Initialize and modify the sysctled variables */
107 0 : sctp_init_sysctls();
108 : #if defined(__Userspace__)
109 : #if defined(__Userspace_os_Windows) || defined(__Userspace_os_NaCl)
110 : srand((unsigned int)time(NULL));
111 : #else
112 0 : srandom(getpid()); /* so inp->sctp_ep.random_numbers are truly random... */
113 : #endif
114 : #endif
115 : #if defined(__Panda__)
116 : sctp_sendspace = SB_MAX;
117 : sctp_recvspace = SB_MAX;
118 :
119 : #elif defined(__Userspace__)
120 0 : SCTP_BASE_SYSCTL(sctp_sendspace) = SB_MAX;
121 0 : SCTP_BASE_SYSCTL(sctp_recvspace) = SB_RAW;
122 0 : SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = port;
123 : #else
124 : #if !defined(__APPLE__)
125 : if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
126 : SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8);
127 : #endif
128 : /*
129 : * Allow a user to take no more than 1/2 the number of clusters or
130 : * the SB_MAX whichever is smaller for the send window.
131 : */
132 : #if defined(__APPLE__)
133 : sb_max_adj = (u_long)((u_quad_t) (sb_max) * MCLBYTES / (MSIZE + MCLBYTES));
134 : #else
135 : sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
136 : #endif
137 : #if defined(__APPLE__)
138 : SCTP_BASE_SYSCTL(sctp_sendspace) = sb_max_adj;
139 : #else
140 : SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj,
141 : (((uint32_t)nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
142 : #endif
143 : /*
144 : * Now for the recv window, should we take the same amount? or
145 : * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
146 : * now I will just copy.
147 : */
148 : SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace);
149 : #endif
150 0 : SCTP_BASE_VAR(first_time) = 0;
151 0 : SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
152 : #if defined(__Userspace__)
153 : #if !defined(__Userspace_os_Windows)
154 : #if defined(INET) || defined(INET6)
155 : SCTP_BASE_VAR(userspace_route) = -1;
156 : #endif
157 : #endif
158 : #ifdef INET
159 : SCTP_BASE_VAR(userspace_rawsctp) = -1;
160 : SCTP_BASE_VAR(userspace_udpsctp) = -1;
161 : #endif
162 : #ifdef INET6
163 : SCTP_BASE_VAR(userspace_rawsctp6) = -1;
164 : SCTP_BASE_VAR(userspace_udpsctp6) = -1;
165 : #endif
166 0 : SCTP_BASE_VAR(timer_thread_should_exit) = 0;
167 0 : SCTP_BASE_VAR(conn_output) = conn_output;
168 0 : SCTP_BASE_VAR(debug_printf) = debug_printf;
169 : #endif
170 0 : sctp_pcb_init();
171 : #if defined(__Userspace__)
172 0 : sctp_start_timer();
173 : #endif
174 : #if defined(SCTP_PACKET_LOGGING)
175 : SCTP_BASE_VAR(packet_log_writers) = 0;
176 : SCTP_BASE_VAR(packet_log_end) = 0;
177 : bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE);
178 : #endif
179 : #if defined(__APPLE__)
180 : SCTP_BASE_VAR(sctp_main_timer_ticks) = 0;
181 : sctp_start_main_timer();
182 : timeout(sctp_delayed_startup, NULL, 1);
183 : #endif
184 0 : }
185 :
186 : void
187 0 : sctp_finish(void)
188 : {
189 : #if defined(__APPLE__)
190 : untimeout(sctp_delayed_startup, NULL);
191 : sctp_over_udp_stop();
192 : sctp_address_monitor_stop();
193 : sctp_stop_main_timer();
194 : #endif
195 : #if defined(__Userspace__)
196 : #if defined(INET) || defined(INET6)
197 : recv_thread_destroy();
198 : #endif
199 : #if !defined(__Userspace_os_Windows)
200 : #if defined(INET) || defined(INET6)
201 : if (SCTP_BASE_VAR(userspace_route) != -1) {
202 : pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL);
203 : }
204 : #endif
205 : #endif
206 : #ifdef INET
207 : if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
208 : #if defined(__Userspace_os_Windows)
209 : WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE);
210 : CloseHandle(SCTP_BASE_VAR(recvthreadraw));
211 : #else
212 : pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL);
213 : #endif
214 : }
215 : if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
216 : #if defined(__Userspace_os_Windows)
217 : WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE);
218 : CloseHandle(SCTP_BASE_VAR(recvthreadudp));
219 : #else
220 : pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL);
221 : #endif
222 : }
223 : #endif
224 : #ifdef INET6
225 : if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
226 : #if defined(__Userspace_os_Windows)
227 : WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE);
228 : CloseHandle(SCTP_BASE_VAR(recvthreadraw6));
229 : #else
230 : pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL);
231 : #endif
232 : }
233 : if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
234 : #if defined(__Userspace_os_Windows)
235 : WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE);
236 : CloseHandle(SCTP_BASE_VAR(recvthreadudp6));
237 : #else
238 : pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL);
239 : #endif
240 : }
241 : #endif
242 0 : SCTP_BASE_VAR(timer_thread_should_exit) = 1;
243 : #if defined(__Userspace_os_Windows)
244 : WaitForSingleObject(SCTP_BASE_VAR(timer_thread), INFINITE);
245 : CloseHandle(SCTP_BASE_VAR(timer_thread));
246 : #else
247 0 : pthread_join(SCTP_BASE_VAR(timer_thread), NULL);
248 : #endif
249 : #endif
250 0 : sctp_pcb_finish();
251 : #if defined(__Userspace__)
252 : #if defined(__Userspace_os_Windows)
253 : DeleteConditionVariable(&accept_cond);
254 : DeleteCriticalSection(&accept_mtx);
255 : #else
256 0 : pthread_cond_destroy(&accept_cond);
257 0 : pthread_mutex_destroy(&accept_mtx);
258 : #endif
259 : #endif
260 : #if defined(__Windows__)
261 : sctp_finish_sysctls();
262 : #if defined(INET) || defined(INET6)
263 : WSACleanup();
264 : #endif
265 : #endif
266 0 : }
267 :
268 :
269 :
270 : void
271 0 : sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
272 : {
273 : struct sctp_tmit_chunk *chk;
274 : uint16_t overhead;
275 :
276 : /* Adjust that too */
277 0 : stcb->asoc.smallest_mtu = nxtsz;
278 : /* now off to subtract IP_DF flag if needed */
279 0 : overhead = IP_HDR_SIZE;
280 0 : if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
281 0 : overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
282 : }
283 0 : TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
284 0 : if ((chk->send_size + overhead) > nxtsz) {
285 0 : chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
286 : }
287 : }
288 0 : TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
289 0 : if ((chk->send_size + overhead) > nxtsz) {
290 : /*
291 : * For this guy we also mark for immediate resend
292 : * since we sent to big of chunk
293 : */
294 0 : chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
295 0 : if (chk->sent < SCTP_DATAGRAM_RESEND) {
296 0 : sctp_flight_size_decrease(chk);
297 0 : sctp_total_flight_decrease(stcb, chk);
298 0 : chk->sent = SCTP_DATAGRAM_RESEND;
299 0 : sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
300 0 : chk->rec.data.doing_fast_retransmit = 0;
301 0 : if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
302 0 : sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
303 0 : chk->whoTo->flight_size,
304 0 : chk->book_size,
305 0 : (uintptr_t)chk->whoTo,
306 : chk->rec.data.TSN_seq);
307 : }
308 : /* Clear any time so NO RTT is being done */
309 0 : chk->do_rtt = 0;
310 : }
311 : }
312 : }
313 0 : }
314 :
315 : #ifdef INET
316 : #if !defined(__Userspace__)
317 : #if defined(__Panda__) || defined(__Windows__)
318 : void
319 : #else
320 : static void
321 : #endif
322 : sctp_notify_mbuf(struct sctp_inpcb *inp,
323 : struct sctp_tcb *stcb,
324 : struct sctp_nets *net,
325 : struct ip *ip,
326 : struct sctphdr *sh)
327 : {
328 : struct icmp *icmph;
329 : int totsz, tmr_stopped = 0;
330 : uint16_t nxtsz;
331 :
332 : /* protection */
333 : if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
334 : (ip == NULL) || (sh == NULL)) {
335 : if (stcb != NULL) {
336 : SCTP_TCB_UNLOCK(stcb);
337 : }
338 : return;
339 : }
340 : /* First job is to verify the vtag matches what I would send */
341 : if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
342 : SCTP_TCB_UNLOCK(stcb);
343 : return;
344 : }
345 : icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
346 : sizeof(struct ip)));
347 : if (icmph->icmp_type != ICMP_UNREACH) {
348 : /* We only care about unreachable */
349 : SCTP_TCB_UNLOCK(stcb);
350 : return;
351 : }
352 : if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
353 : /* not a unreachable message due to frag. */
354 : SCTP_TCB_UNLOCK(stcb);
355 : return;
356 : }
357 : #if defined(__FreeBSD__) && __FreeBSD_version >= 1000000
358 : totsz = ntohs(ip->ip_len);
359 : #else
360 : totsz = ip->ip_len;
361 : #endif
362 :
363 : nxtsz = ntohs(icmph->icmp_nextmtu);
364 : if (nxtsz == 0) {
365 : /*
366 : * old type router that does not tell us what the next size
367 : * mtu is. Rats we will have to guess (in a educated fashion
368 : * of course)
369 : */
370 : nxtsz = sctp_get_prev_mtu(totsz);
371 : }
372 : /* Stop any PMTU timer */
373 : if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
374 : tmr_stopped = 1;
375 : sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
376 : SCTP_FROM_SCTP_USRREQ+SCTP_LOC_1);
377 : }
378 : /* Adjust destination size limit */
379 : if (net->mtu > nxtsz) {
380 : net->mtu = nxtsz;
381 : if (net->port) {
382 : net->mtu -= sizeof(struct udphdr);
383 : }
384 : }
385 : /* now what about the ep? */
386 : if (stcb->asoc.smallest_mtu > nxtsz) {
387 : sctp_pathmtu_adjustment(stcb, nxtsz);
388 : }
389 : if (tmr_stopped)
390 : sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
391 :
392 : SCTP_TCB_UNLOCK(stcb);
393 : }
394 :
395 : void
396 : sctp_notify(struct sctp_inpcb *inp,
397 : struct ip *ip,
398 : struct sctphdr *sh,
399 : struct sockaddr *to,
400 : struct sctp_tcb *stcb,
401 : struct sctp_nets *net)
402 : {
403 : #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
404 : struct socket *so;
405 :
406 : #endif
407 : struct icmp *icmph;
408 :
409 : /* protection */
410 : if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
411 : (sh == NULL) || (to == NULL)) {
412 : if (stcb)
413 : SCTP_TCB_UNLOCK(stcb);
414 : return;
415 : }
416 : /* First job is to verify the vtag matches what I would send */
417 : if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
418 : SCTP_TCB_UNLOCK(stcb);
419 : return;
420 : }
421 :
422 : icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
423 : sizeof(struct ip)));
424 : if (icmph->icmp_type != ICMP_UNREACH) {
425 : /* We only care about unreachable */
426 : SCTP_TCB_UNLOCK(stcb);
427 : return;
428 : }
429 : if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
430 : (icmph->icmp_code == ICMP_UNREACH_HOST) ||
431 : (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
432 : (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
433 : (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
434 : (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
435 : (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
436 : #if defined(__Panda__)
437 : (icmph->icmp_code == ICMP_UNREACH_ADMIN)) {
438 : #elif defined(__Userspace_os_NetBSD)
439 : (icmph->icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) {
440 : #else
441 : (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
442 : #endif
443 :
444 : /*
445 : * Hmm reachablity problems we must examine closely. If its
446 : * not reachable, we may have lost a network. Or if there is
447 : * NO protocol at the other end named SCTP. well we consider
448 : * it a OOTB abort.
449 : */
450 : if (net->dest_state & SCTP_ADDR_REACHABLE) {
451 : /* Ok that destination is NOT reachable */
452 : net->dest_state &= ~SCTP_ADDR_REACHABLE;
453 : net->dest_state &= ~SCTP_ADDR_PF;
454 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
455 : stcb, 0,
456 : (void *)net, SCTP_SO_NOT_LOCKED);
457 : }
458 : SCTP_TCB_UNLOCK(stcb);
459 : } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
460 : (icmph->icmp_code == ICMP_UNREACH_PORT)) {
461 : /*
462 : * Here the peer is either playing tricks on us,
463 : * including an address that belongs to someone who
464 : * does not support SCTP OR was a userland
465 : * implementation that shutdown and now is dead. In
466 : * either case treat it like a OOTB abort with no
467 : * TCB
468 : */
469 : sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
470 : #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
471 : so = SCTP_INP_SO(inp);
472 : atomic_add_int(&stcb->asoc.refcnt, 1);
473 : SCTP_TCB_UNLOCK(stcb);
474 : SCTP_SOCKET_LOCK(so, 1);
475 : SCTP_TCB_LOCK(stcb);
476 : atomic_subtract_int(&stcb->asoc.refcnt, 1);
477 : #endif
478 : (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_2);
479 : #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
480 : SCTP_SOCKET_UNLOCK(so, 1);
481 : /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/
482 : #endif
483 : /* no need to unlock here, since the TCB is gone */
484 : } else {
485 : SCTP_TCB_UNLOCK(stcb);
486 : }
487 : }
488 : #endif
489 : #endif
490 :
491 : #ifdef INET
492 : #if !defined(__Panda__) && !defined(__Userspace__)
493 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
494 : void
495 : #else
496 : void *
497 : #endif
498 : sctp_ctlinput(cmd, sa, vip)
499 : int cmd;
500 : struct sockaddr *sa;
501 : void *vip;
502 : {
503 : struct ip *ip = vip;
504 : struct sctphdr *sh;
505 : uint32_t vrf_id;
506 : /* FIX, for non-bsd is this right? */
507 : vrf_id = SCTP_DEFAULT_VRFID;
508 : if (sa->sa_family != AF_INET ||
509 : ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
510 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
511 : return;
512 : #else
513 : return (NULL);
514 : #endif
515 : }
516 : if (PRC_IS_REDIRECT(cmd)) {
517 : ip = 0;
518 : } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
519 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
520 : return;
521 : #else
522 : return (NULL);
523 : #endif
524 : }
525 : if (ip) {
526 : struct sctp_inpcb *inp = NULL;
527 : struct sctp_tcb *stcb = NULL;
528 : struct sctp_nets *net = NULL;
529 : struct sockaddr_in to, from;
530 :
531 : sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
532 : bzero(&to, sizeof(to));
533 : bzero(&from, sizeof(from));
534 : from.sin_family = to.sin_family = AF_INET;
535 : #ifdef HAVE_SIN_LEN
536 : from.sin_len = to.sin_len = sizeof(to);
537 : #endif
538 : from.sin_port = sh->src_port;
539 : from.sin_addr = ip->ip_src;
540 : to.sin_port = sh->dest_port;
541 : to.sin_addr = ip->ip_dst;
542 :
543 : /*
544 : * 'to' holds the dest of the packet that failed to be sent.
545 : * 'from' holds our local endpoint address. Thus we reverse
546 : * the to and the from in the lookup.
547 : */
548 : stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to,
549 : (struct sockaddr *)&from,
550 : &inp, &net, 1, vrf_id);
551 : if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
552 : if (cmd != PRC_MSGSIZE) {
553 : sctp_notify(inp, ip, sh,
554 : (struct sockaddr *)&to, stcb,
555 : net);
556 : } else {
557 : /* handle possible ICMP size messages */
558 : sctp_notify_mbuf(inp, stcb, net, ip, sh);
559 : }
560 : } else {
561 : #if defined(__FreeBSD__) && __FreeBSD_version < 500000
562 : /*
563 : * XXX must be fixed for 5.x and higher, leave for
564 : * 4.x
565 : */
566 : if (PRC_IS_REDIRECT(cmd) && inp) {
567 : in_rtchange((struct inpcb *)inp,
568 : inetctlerrmap[cmd]);
569 : }
570 : #endif
571 : if ((stcb == NULL) && (inp != NULL)) {
572 : /* reduce ref-count */
573 : SCTP_INP_WLOCK(inp);
574 : SCTP_INP_DECR_REF(inp);
575 : SCTP_INP_WUNLOCK(inp);
576 : }
577 : if (stcb) {
578 : SCTP_TCB_UNLOCK(stcb);
579 : }
580 : }
581 : }
582 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
583 : return;
584 : #else
585 : return (NULL);
586 : #endif
587 : }
588 : #endif
589 : #endif
590 :
591 : #if defined(__FreeBSD__)
592 : static int
593 : sctp_getcred(SYSCTL_HANDLER_ARGS)
594 : {
595 : struct xucred xuc;
596 : struct sockaddr_in addrs[2];
597 : struct sctp_inpcb *inp;
598 : struct sctp_nets *net;
599 : struct sctp_tcb *stcb;
600 : int error;
601 : uint32_t vrf_id;
602 :
603 : /* FIX, for non-bsd is this right? */
604 : vrf_id = SCTP_DEFAULT_VRFID;
605 :
606 : #if __FreeBSD_version > 602000
607 : error = priv_check(req->td, PRIV_NETINET_GETCRED);
608 :
609 : #elif __FreeBSD_version >= 500000
610 : error = suser(req->td);
611 : #else
612 : error = suser(req->p);
613 : #endif
614 : if (error)
615 : return (error);
616 :
617 : error = SYSCTL_IN(req, addrs, sizeof(addrs));
618 : if (error)
619 : return (error);
620 :
621 : stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]),
622 : sintosa(&addrs[0]),
623 : &inp, &net, 1, vrf_id);
624 : if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
625 : if ((inp != NULL) && (stcb == NULL)) {
626 : /* reduce ref-count */
627 : SCTP_INP_WLOCK(inp);
628 : SCTP_INP_DECR_REF(inp);
629 : goto cred_can_cont;
630 : }
631 :
632 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
633 : error = ENOENT;
634 : goto out;
635 : }
636 : SCTP_TCB_UNLOCK(stcb);
637 : /* We use the write lock here, only
638 : * since in the error leg we need it.
639 : * If we used RLOCK, then we would have
640 : * to wlock/decr/unlock/rlock. Which
641 : * in theory could create a hole. Better
642 : * to use higher wlock.
643 : */
644 : SCTP_INP_WLOCK(inp);
645 : cred_can_cont:
646 : error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
647 : if (error) {
648 : SCTP_INP_WUNLOCK(inp);
649 : goto out;
650 : }
651 : cru2x(inp->sctp_socket->so_cred, &xuc);
652 : SCTP_INP_WUNLOCK(inp);
653 : error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
654 : out:
655 : return (error);
656 : }
657 :
658 : SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
659 : 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
660 : #endif /* #if defined(__FreeBSD__) */
661 :
662 :
663 : #ifdef INET
664 : #if defined(__Panda__) || defined(__Windows__) || defined(__Userspace__)
665 : int
666 : #elif defined(__FreeBSD__) && __FreeBSD_version > 690000
667 : static void
668 : #else
669 : static int
670 : #endif
671 : sctp_abort(struct socket *so)
672 : {
673 : struct sctp_inpcb *inp;
674 : uint32_t flags;
675 :
676 : inp = (struct sctp_inpcb *)so->so_pcb;
677 : if (inp == NULL) {
678 : #if defined(__FreeBSD__) && __FreeBSD_version > 690000
679 : return;
680 : #else
681 : SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
682 : return (EINVAL);
683 : #endif
684 : }
685 :
686 : sctp_must_try_again:
687 : flags = inp->sctp_flags;
688 : #ifdef SCTP_LOG_CLOSING
689 : sctp_log_closing(inp, NULL, 17);
690 : #endif
691 : if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
692 : (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
693 : #ifdef SCTP_LOG_CLOSING
694 : sctp_log_closing(inp, NULL, 16);
695 : #endif
696 : sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
697 : SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
698 : SOCK_LOCK(so);
699 : SCTP_SB_CLEAR(so->so_snd);
700 : /* same for the rcv ones, they are only
701 : * here for the accounting/select.
702 : */
703 : SCTP_SB_CLEAR(so->so_rcv);
704 :
705 : #if defined(__APPLE__)
706 : so->so_usecount--;
707 : #else
708 : /* Now null out the reference, we are completely detached. */
709 : so->so_pcb = NULL;
710 : #endif
711 : SOCK_UNLOCK(so);
712 : } else {
713 : flags = inp->sctp_flags;
714 : if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
715 : goto sctp_must_try_again;
716 : }
717 : }
718 : #if defined(__FreeBSD__) && __FreeBSD_version > 690000
719 : return;
720 : #else
721 : return (0);
722 : #endif
723 : }
724 :
725 : #if defined(__Panda__) || defined(__Userspace__)
726 : int
727 : #else
728 : static int
729 : #endif
730 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
731 : sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
732 : #elif defined(__Panda__) || defined(__Userspace__)
733 : sctp_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
734 : #elif defined(__Windows__)
735 : sctp_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED)
736 : #else
737 : sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED)
738 : #endif
739 : {
740 : struct sctp_inpcb *inp;
741 : struct inpcb *ip_inp;
742 : int error;
743 : #if !defined(__Panda__) && !defined(__Userspace__)
744 : uint32_t vrf_id = SCTP_DEFAULT_VRFID;
745 : #endif
746 : #ifdef IPSEC
747 : uint32_t flags;
748 : #endif
749 :
750 : inp = (struct sctp_inpcb *)so->so_pcb;
751 : if (inp != 0) {
752 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
753 : return (EINVAL);
754 : }
755 : if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
756 : error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
757 : if (error) {
758 : return (error);
759 : }
760 : }
761 : error = sctp_inpcb_alloc(so, vrf_id);
762 : if (error) {
763 : return (error);
764 : }
765 : inp = (struct sctp_inpcb *)so->so_pcb;
766 : SCTP_INP_WLOCK(inp);
767 : inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */
768 : ip_inp = &inp->ip_inp.inp;
769 : ip_inp->inp_vflag |= INP_IPV4;
770 : ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
771 : #ifdef IPSEC
772 : #if !(defined(__APPLE__))
773 : error = ipsec_init_policy(so, &ip_inp->inp_sp);
774 : #ifdef SCTP_LOG_CLOSING
775 : sctp_log_closing(inp, NULL, 17);
776 : #endif
777 : if (error != 0) {
778 : try_again:
779 : flags = inp->sctp_flags;
780 : if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
781 : (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
782 : #ifdef SCTP_LOG_CLOSING
783 : sctp_log_closing(inp, NULL, 15);
784 : #endif
785 : SCTP_INP_WUNLOCK(inp);
786 : sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
787 : SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
788 : } else {
789 : flags = inp->sctp_flags;
790 : if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
791 : goto try_again;
792 : } else {
793 : SCTP_INP_WUNLOCK(inp);
794 : }
795 : }
796 : return (error);
797 : }
798 : #endif
799 : #endif /* IPSEC */
800 : SCTP_INP_WUNLOCK(inp);
801 : return (0);
802 : }
803 :
804 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
805 : static int
806 : sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
807 : {
808 : #elif defined(__FreeBSD__) || defined(__APPLE__)
809 : static int
810 : sctp_bind(struct socket *so, struct sockaddr *addr, struct proc *p) {
811 : #elif defined(__Panda__) || defined(__Userspace__)
812 : int
813 : sctp_bind(struct socket *so, struct sockaddr *addr) {
814 : void *p = NULL;
815 : #elif defined(__Windows__)
816 : static int
817 : sctp_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) {
818 : #else
819 : static int
820 : sctp_bind(struct socket *so, struct mbuf *nam, struct proc *p)
821 : {
822 : struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL;
823 :
824 : #endif
825 : struct sctp_inpcb *inp;
826 :
827 : inp = (struct sctp_inpcb *)so->so_pcb;
828 : if (inp == NULL) {
829 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
830 : return (EINVAL);
831 : }
832 : if (addr != NULL) {
833 : #ifdef HAVE_SA_LEN
834 : if ((addr->sa_family != AF_INET) ||
835 : (addr->sa_len != sizeof(struct sockaddr_in))) {
836 : #else
837 : if (addr->sa_family != AF_INET) {
838 : #endif
839 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
840 : return (EINVAL);
841 : }
842 : }
843 : return (sctp_inpcb_bind(so, addr, NULL, p));
844 : }
845 :
846 : #endif
847 : #if defined(__Userspace__)
848 :
849 : int
850 0 : sctpconn_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
851 : {
852 : struct sctp_inpcb *inp;
853 : struct inpcb *ip_inp;
854 : int error;
855 :
856 0 : inp = (struct sctp_inpcb *)so->so_pcb;
857 0 : if (inp != NULL) {
858 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
859 0 : return (EINVAL);
860 : }
861 0 : if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
862 0 : error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
863 0 : if (error) {
864 0 : return (error);
865 : }
866 : }
867 0 : error = sctp_inpcb_alloc(so, vrf_id);
868 0 : if (error) {
869 0 : return (error);
870 : }
871 0 : inp = (struct sctp_inpcb *)so->so_pcb;
872 0 : SCTP_INP_WLOCK(inp);
873 0 : inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;
874 0 : inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_CONN;
875 0 : ip_inp = &inp->ip_inp.inp;
876 0 : ip_inp->inp_vflag |= INP_CONN;
877 0 : ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
878 0 : SCTP_INP_WUNLOCK(inp);
879 0 : return (0);
880 : }
881 :
882 : int
883 0 : sctpconn_bind(struct socket *so, struct sockaddr *addr)
884 : {
885 : struct sctp_inpcb *inp;
886 :
887 0 : inp = (struct sctp_inpcb *)so->so_pcb;
888 0 : if (inp == NULL) {
889 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
890 0 : return (EINVAL);
891 : }
892 0 : if (addr != NULL) {
893 : #ifdef HAVE_SA_LEN
894 : if ((addr->sa_family != AF_CONN) ||
895 : (addr->sa_len != sizeof(struct sockaddr_conn))) {
896 : #else
897 0 : if (addr->sa_family != AF_CONN) {
898 : #endif
899 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
900 0 : return (EINVAL);
901 : }
902 : }
903 0 : return (sctp_inpcb_bind(so, addr, NULL, NULL));
904 : }
905 :
906 : #endif
907 : #if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__)
908 : void
909 0 : sctp_close(struct socket *so)
910 : {
911 : struct sctp_inpcb *inp;
912 : uint32_t flags;
913 :
914 0 : inp = (struct sctp_inpcb *)so->so_pcb;
915 0 : if (inp == NULL)
916 0 : return;
917 :
918 : /* Inform all the lower layer assoc that we
919 : * are done.
920 : */
921 : sctp_must_try_again:
922 0 : flags = inp->sctp_flags;
923 : #ifdef SCTP_LOG_CLOSING
924 : sctp_log_closing(inp, NULL, 17);
925 : #endif
926 0 : if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
927 0 : (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
928 : #if defined(__Userspace__)
929 0 : if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) ||
930 0 : (so->so_rcv.sb_cc > 0)) {
931 : #else
932 : if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
933 : (so->so_rcv.sb_cc > 0)) {
934 : #endif
935 : #ifdef SCTP_LOG_CLOSING
936 : sctp_log_closing(inp, NULL, 13);
937 : #endif
938 0 : sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
939 : SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
940 : } else {
941 : #ifdef SCTP_LOG_CLOSING
942 : sctp_log_closing(inp, NULL, 14);
943 : #endif
944 0 : sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
945 : SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
946 : }
947 : /* The socket is now detached, no matter what
948 : * the state of the SCTP association.
949 : */
950 0 : SOCK_LOCK(so);
951 0 : SCTP_SB_CLEAR(so->so_snd);
952 : /* same for the rcv ones, they are only
953 : * here for the accounting/select.
954 : */
955 0 : SCTP_SB_CLEAR(so->so_rcv);
956 :
957 : #if !defined(__APPLE__)
958 : /* Now null out the reference, we are completely detached. */
959 0 : so->so_pcb = NULL;
960 : #endif
961 0 : SOCK_UNLOCK(so);
962 : } else {
963 0 : flags = inp->sctp_flags;
964 0 : if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
965 0 : goto sctp_must_try_again;
966 : }
967 : }
968 0 : return;
969 : }
970 :
971 : #else
972 :
973 :
974 : int
975 : sctp_detach(struct socket *so)
976 : {
977 : struct sctp_inpcb *inp;
978 : uint32_t flags;
979 :
980 : inp = (struct sctp_inpcb *)so->so_pcb;
981 : if (inp == NULL) {
982 : #if defined(__FreeBSD__) && __FreeBSD_version > 690000
983 : return;
984 : #else
985 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
986 : return (EINVAL);
987 : #endif
988 : }
989 : sctp_must_try_again:
990 : flags = inp->sctp_flags;
991 : #ifdef SCTP_LOG_CLOSING
992 : sctp_log_closing(inp, NULL, 17);
993 : #endif
994 : if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
995 : (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
996 : #if defined(__Userspace__)
997 : if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) ||
998 : (so->so_rcv.sb_cc > 0)) {
999 : #else
1000 : if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
1001 : (so->so_rcv.sb_cc > 0)) {
1002 : #endif
1003 : #ifdef SCTP_LOG_CLOSING
1004 : sctp_log_closing(inp, NULL, 13);
1005 : #endif
1006 : sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
1007 : SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
1008 : } else {
1009 : #ifdef SCTP_LOG_CLOSING
1010 : sctp_log_closing(inp, NULL, 13);
1011 : #endif
1012 : sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
1013 : SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
1014 : }
1015 : /* The socket is now detached, no matter what
1016 : * the state of the SCTP association.
1017 : */
1018 : SCTP_SB_CLEAR(so->so_snd);
1019 : /* same for the rcv ones, they are only
1020 : * here for the accounting/select.
1021 : */
1022 : SCTP_SB_CLEAR(so->so_rcv);
1023 : #if !defined(__APPLE__)
1024 : /* Now disconnect */
1025 : so->so_pcb = NULL;
1026 : #endif
1027 : } else {
1028 : flags = inp->sctp_flags;
1029 : if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
1030 : goto sctp_must_try_again;
1031 : }
1032 : }
1033 : #if defined(__FreeBSD__) && __FreeBSD_version > 690000
1034 : return;
1035 : #else
1036 : return (0);
1037 : #endif
1038 : }
1039 : #endif
1040 :
1041 : #if defined(__Userspace__)
1042 : /* __Userspace__ is not calling sctp_sendm */
1043 : #endif
1044 : #if !(defined(__Panda__) || defined(__Windows__))
1045 : int
1046 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
1047 : sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1048 : struct mbuf *control, struct thread *p);
1049 :
1050 : #else
1051 : sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1052 : struct mbuf *control, struct proc *p);
1053 :
1054 : #endif
1055 :
1056 : int
1057 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
1058 : sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1059 : struct mbuf *control, struct thread *p)
1060 : {
1061 : #else
1062 0 : sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1063 : struct mbuf *control, struct proc *p)
1064 : {
1065 : #endif
1066 : struct sctp_inpcb *inp;
1067 : int error;
1068 :
1069 0 : inp = (struct sctp_inpcb *)so->so_pcb;
1070 0 : if (inp == NULL) {
1071 0 : if (control) {
1072 0 : sctp_m_freem(control);
1073 0 : control = NULL;
1074 : }
1075 : SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1076 0 : sctp_m_freem(m);
1077 0 : return (EINVAL);
1078 : }
1079 : /* Got to have an to address if we are NOT a connected socket */
1080 0 : if ((addr == NULL) &&
1081 0 : ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
1082 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) {
1083 : goto connected_type;
1084 0 : } else if (addr == NULL) {
1085 : SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
1086 0 : error = EDESTADDRREQ;
1087 0 : sctp_m_freem(m);
1088 0 : if (control) {
1089 0 : sctp_m_freem(control);
1090 0 : control = NULL;
1091 : }
1092 0 : return (error);
1093 : }
1094 : #ifdef INET6
1095 : if (addr->sa_family != AF_INET) {
1096 : /* must be a v4 address! */
1097 : SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
1098 : sctp_m_freem(m);
1099 : if (control) {
1100 : sctp_m_freem(control);
1101 : control = NULL;
1102 : }
1103 : error = EDESTADDRREQ;
1104 : return (error);
1105 : }
1106 : #endif /* INET6 */
1107 : connected_type:
1108 : /* now what about control */
1109 0 : if (control) {
1110 0 : if (inp->control) {
1111 0 : SCTP_PRINTF("huh? control set?\n");
1112 0 : sctp_m_freem(inp->control);
1113 0 : inp->control = NULL;
1114 : }
1115 0 : inp->control = control;
1116 : }
1117 : /* Place the data */
1118 0 : if (inp->pkt) {
1119 0 : SCTP_BUF_NEXT(inp->pkt_last) = m;
1120 0 : inp->pkt_last = m;
1121 : } else {
1122 0 : inp->pkt_last = inp->pkt = m;
1123 : }
1124 : if (
1125 : #if defined(__FreeBSD__) || defined(__APPLE__)
1126 : /* FreeBSD uses a flag passed */
1127 : ((flags & PRUS_MORETOCOME) == 0)
1128 : #else
1129 : 1 /* Open BSD does not have any "more to come"
1130 : * indication */
1131 : #endif
1132 : ) {
1133 : /*
1134 : * note with the current version this code will only be used
1135 : * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
1136 : * re-defining sosend to use the sctp_sosend. One can
1137 : * optionally switch back to this code (by changing back the
1138 : * definitions) but this is not advisable. This code is used
1139 : * by FreeBSD when sending a file with sendfile() though.
1140 : */
1141 : int ret;
1142 :
1143 0 : ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
1144 0 : inp->pkt = NULL;
1145 0 : inp->control = NULL;
1146 0 : return (ret);
1147 : } else {
1148 : return (0);
1149 : }
1150 : }
1151 : #endif
1152 :
1153 : int
1154 0 : sctp_disconnect(struct socket *so)
1155 : {
1156 : struct sctp_inpcb *inp;
1157 :
1158 0 : inp = (struct sctp_inpcb *)so->so_pcb;
1159 0 : if (inp == NULL) {
1160 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
1161 0 : return (ENOTCONN);
1162 : }
1163 0 : SCTP_INP_RLOCK(inp);
1164 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1165 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
1166 0 : if (LIST_EMPTY(&inp->sctp_asoc_list)) {
1167 : /* No connection */
1168 0 : SCTP_INP_RUNLOCK(inp);
1169 0 : return (0);
1170 : } else {
1171 : struct sctp_association *asoc;
1172 : struct sctp_tcb *stcb;
1173 :
1174 0 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
1175 0 : if (stcb == NULL) {
1176 0 : SCTP_INP_RUNLOCK(inp);
1177 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1178 0 : return (EINVAL);
1179 : }
1180 0 : SCTP_TCB_LOCK(stcb);
1181 0 : asoc = &stcb->asoc;
1182 0 : if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
1183 : /* We are about to be freed, out of here */
1184 0 : SCTP_TCB_UNLOCK(stcb);
1185 0 : SCTP_INP_RUNLOCK(inp);
1186 0 : return (0);
1187 : }
1188 : #if defined(__Userspace__)
1189 0 : if (((so->so_options & SCTP_SO_LINGER) &&
1190 0 : (so->so_linger == 0)) ||
1191 0 : (so->so_rcv.sb_cc > 0)) {
1192 : #else
1193 : if (((so->so_options & SO_LINGER) &&
1194 : (so->so_linger == 0)) ||
1195 : (so->so_rcv.sb_cc > 0)) {
1196 : #endif
1197 0 : if (SCTP_GET_STATE(asoc) !=
1198 : SCTP_STATE_COOKIE_WAIT) {
1199 : /* Left with Data unread */
1200 : struct mbuf *err;
1201 :
1202 0 : err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
1203 0 : if (err) {
1204 : /*
1205 : * Fill in the user
1206 : * initiated abort
1207 : */
1208 : struct sctp_paramhdr *ph;
1209 :
1210 0 : ph = mtod(err, struct sctp_paramhdr *);
1211 0 : SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
1212 0 : ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
1213 0 : ph->param_length = htons(SCTP_BUF_LEN(err));
1214 : }
1215 0 : sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
1216 0 : SCTP_STAT_INCR_COUNTER32(sctps_aborted);
1217 : }
1218 0 : SCTP_INP_RUNLOCK(inp);
1219 0 : if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
1220 0 : (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1221 0 : SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1222 : }
1223 0 : (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_3);
1224 : /* No unlock tcb assoc is gone */
1225 0 : return (0);
1226 : }
1227 0 : if (TAILQ_EMPTY(&asoc->send_queue) &&
1228 0 : TAILQ_EMPTY(&asoc->sent_queue) &&
1229 0 : (asoc->stream_queue_cnt == 0)) {
1230 : /* there is nothing queued to send, so done */
1231 0 : if (asoc->locked_on_sending) {
1232 0 : goto abort_anyway;
1233 : }
1234 0 : if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
1235 0 : (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
1236 : /* only send SHUTDOWN 1st time thru */
1237 : struct sctp_nets *netp;
1238 :
1239 0 : if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
1240 0 : (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1241 0 : SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1242 : }
1243 0 : SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
1244 0 : SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
1245 0 : sctp_stop_timers_for_shutdown(stcb);
1246 0 : if (stcb->asoc.alternate) {
1247 0 : netp = stcb->asoc.alternate;
1248 : } else {
1249 0 : netp = stcb->asoc.primary_destination;
1250 : }
1251 0 : sctp_send_shutdown(stcb,netp);
1252 0 : sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1253 : stcb->sctp_ep, stcb, netp);
1254 0 : sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1255 : stcb->sctp_ep, stcb, netp);
1256 0 : sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
1257 : }
1258 : } else {
1259 : /*
1260 : * we still got (or just got) data to send,
1261 : * so set SHUTDOWN_PENDING
1262 : */
1263 : /*
1264 : * XXX sockets draft says that SCTP_EOF
1265 : * should be sent with no data. currently,
1266 : * we will allow user data to be sent first
1267 : * and move to SHUTDOWN-PENDING
1268 : */
1269 : struct sctp_nets *netp;
1270 0 : if (stcb->asoc.alternate) {
1271 0 : netp = stcb->asoc.alternate;
1272 : } else {
1273 0 : netp = stcb->asoc.primary_destination;
1274 : }
1275 :
1276 0 : asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1277 0 : sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1278 : netp);
1279 0 : if (asoc->locked_on_sending) {
1280 : /* Locked to send out the data */
1281 : struct sctp_stream_queue_pending *sp;
1282 0 : sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1283 0 : if (sp == NULL) {
1284 0 : SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1285 : asoc->locked_on_sending->stream_no);
1286 : } else {
1287 0 : if ((sp->length == 0) && (sp->msg_is_complete == 0))
1288 0 : asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1289 : }
1290 : }
1291 0 : if (TAILQ_EMPTY(&asoc->send_queue) &&
1292 0 : TAILQ_EMPTY(&asoc->sent_queue) &&
1293 0 : (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1294 : struct mbuf *op_err;
1295 : abort_anyway:
1296 0 : op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
1297 0 : stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_4;
1298 0 : sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
1299 0 : SCTP_STAT_INCR_COUNTER32(sctps_aborted);
1300 0 : if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
1301 0 : (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1302 0 : SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1303 : }
1304 0 : SCTP_INP_RUNLOCK(inp);
1305 0 : (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_5);
1306 0 : return (0);
1307 : } else {
1308 0 : sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
1309 : }
1310 : }
1311 0 : soisdisconnecting(so);
1312 0 : SCTP_TCB_UNLOCK(stcb);
1313 0 : SCTP_INP_RUNLOCK(inp);
1314 0 : return (0);
1315 : }
1316 : /* not reached */
1317 : } else {
1318 : /* UDP model does not support this */
1319 0 : SCTP_INP_RUNLOCK(inp);
1320 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1321 0 : return (EOPNOTSUPP);
1322 : }
1323 : }
1324 :
1325 : #if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
1326 : int
1327 0 : sctp_flush(struct socket *so, int how)
1328 : {
1329 : /*
1330 : * We will just clear out the values and let
1331 : * subsequent close clear out the data, if any.
1332 : * Note if the user did a shutdown(SHUT_RD) they
1333 : * will not be able to read the data, the socket
1334 : * will block that from happening.
1335 : */
1336 : struct sctp_inpcb *inp;
1337 :
1338 0 : inp = (struct sctp_inpcb *)so->so_pcb;
1339 0 : if (inp == NULL) {
1340 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1341 0 : return (EINVAL);
1342 : }
1343 0 : SCTP_INP_RLOCK(inp);
1344 : /* For the 1 to many model this does nothing */
1345 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
1346 0 : SCTP_INP_RUNLOCK(inp);
1347 0 : return (0);
1348 : }
1349 0 : SCTP_INP_RUNLOCK(inp);
1350 0 : if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
1351 : /* First make sure the sb will be happy, we don't
1352 : * use these except maybe the count
1353 : */
1354 0 : SCTP_INP_WLOCK(inp);
1355 0 : SCTP_INP_READ_LOCK(inp);
1356 0 : inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
1357 0 : SCTP_INP_READ_UNLOCK(inp);
1358 0 : SCTP_INP_WUNLOCK(inp);
1359 0 : so->so_rcv.sb_cc = 0;
1360 0 : so->so_rcv.sb_mbcnt = 0;
1361 0 : so->so_rcv.sb_mb = NULL;
1362 : }
1363 0 : if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
1364 : /* First make sure the sb will be happy, we don't
1365 : * use these except maybe the count
1366 : */
1367 0 : so->so_snd.sb_cc = 0;
1368 0 : so->so_snd.sb_mbcnt = 0;
1369 0 : so->so_snd.sb_mb = NULL;
1370 :
1371 : }
1372 0 : return (0);
1373 : }
1374 : #endif
1375 :
1376 : int
1377 0 : sctp_shutdown(struct socket *so)
1378 : {
1379 : struct sctp_inpcb *inp;
1380 :
1381 0 : inp = (struct sctp_inpcb *)so->so_pcb;
1382 0 : if (inp == NULL) {
1383 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1384 0 : return (EINVAL);
1385 : }
1386 0 : SCTP_INP_RLOCK(inp);
1387 : /* For UDP model this is a invalid call */
1388 0 : if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1389 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
1390 : /* Restore the flags that the soshutdown took away. */
1391 : #if (defined(__FreeBSD__) && __FreeBSD_version >= 502115) || defined(__Windows__)
1392 : SOCKBUF_LOCK(&so->so_rcv);
1393 : so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
1394 : SOCKBUF_UNLOCK(&so->so_rcv);
1395 : #else
1396 0 : so->so_state &= ~SS_CANTRCVMORE;
1397 : #endif
1398 : /* This proc will wakeup for read and do nothing (I hope) */
1399 0 : SCTP_INP_RUNLOCK(inp);
1400 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1401 0 : return (EOPNOTSUPP);
1402 : }
1403 : /*
1404 : * Ok if we reach here its the TCP model and it is either a SHUT_WR
1405 : * or SHUT_RDWR. This means we put the shutdown flag against it.
1406 : */
1407 : {
1408 : struct sctp_tcb *stcb;
1409 : struct sctp_association *asoc;
1410 :
1411 0 : if ((so->so_state &
1412 : (SS_ISCONNECTED|SS_ISCONNECTING|SS_ISDISCONNECTING)) == 0) {
1413 0 : SCTP_INP_RUNLOCK(inp);
1414 0 : return (ENOTCONN);
1415 : }
1416 0 : socantsendmore(so);
1417 :
1418 0 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
1419 0 : if (stcb == NULL) {
1420 : /*
1421 : * Ok we hit the case that the shutdown call was
1422 : * made after an abort or something. Nothing to do
1423 : * now.
1424 : */
1425 0 : SCTP_INP_RUNLOCK(inp);
1426 0 : return (0);
1427 : }
1428 0 : SCTP_TCB_LOCK(stcb);
1429 0 : asoc = &stcb->asoc;
1430 0 : if (TAILQ_EMPTY(&asoc->send_queue) &&
1431 0 : TAILQ_EMPTY(&asoc->sent_queue) &&
1432 0 : (asoc->stream_queue_cnt == 0)) {
1433 0 : if (asoc->locked_on_sending) {
1434 0 : goto abort_anyway;
1435 : }
1436 : /* there is nothing queued to send, so I'm done... */
1437 0 : if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
1438 : /* only send SHUTDOWN the first time through */
1439 : struct sctp_nets *netp;
1440 :
1441 0 : if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
1442 0 : (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1443 0 : SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1444 : }
1445 0 : SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
1446 0 : SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
1447 0 : sctp_stop_timers_for_shutdown(stcb);
1448 0 : if (stcb->asoc.alternate) {
1449 0 : netp = stcb->asoc.alternate;
1450 : } else {
1451 0 : netp = stcb->asoc.primary_destination;
1452 : }
1453 0 : sctp_send_shutdown(stcb, netp);
1454 0 : sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1455 : stcb->sctp_ep, stcb, netp);
1456 0 : sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1457 : stcb->sctp_ep, stcb, netp);
1458 0 : sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
1459 : }
1460 : } else {
1461 : /*
1462 : * we still got (or just got) data to send, so set
1463 : * SHUTDOWN_PENDING
1464 : */
1465 : struct sctp_nets *netp;
1466 0 : if (stcb->asoc.alternate) {
1467 0 : netp = stcb->asoc.alternate;
1468 : } else {
1469 0 : netp = stcb->asoc.primary_destination;
1470 : }
1471 :
1472 0 : asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1473 0 : sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1474 : netp);
1475 :
1476 0 : if (asoc->locked_on_sending) {
1477 : /* Locked to send out the data */
1478 : struct sctp_stream_queue_pending *sp;
1479 0 : sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1480 0 : if (sp == NULL) {
1481 0 : SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1482 : asoc->locked_on_sending->stream_no);
1483 : } else {
1484 0 : if ((sp->length == 0) && (sp-> msg_is_complete == 0)) {
1485 0 : asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1486 : }
1487 : }
1488 : }
1489 0 : if (TAILQ_EMPTY(&asoc->send_queue) &&
1490 0 : TAILQ_EMPTY(&asoc->sent_queue) &&
1491 0 : (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1492 : struct mbuf *op_err;
1493 : abort_anyway:
1494 0 : op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
1495 0 : stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6;
1496 0 : sctp_abort_an_association(stcb->sctp_ep, stcb,
1497 : op_err, SCTP_SO_LOCKED);
1498 0 : goto skip_unlock;
1499 : } else {
1500 0 : sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
1501 : }
1502 : }
1503 0 : SCTP_TCB_UNLOCK(stcb);
1504 : }
1505 : skip_unlock:
1506 0 : SCTP_INP_RUNLOCK(inp);
1507 0 : return (0);
1508 : }
1509 :
1510 : /*
1511 : * copies a "user" presentable address and removes embedded scope, etc.
1512 : * returns 0 on success, 1 on error
1513 : */
1514 : static uint32_t
1515 0 : sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1516 : {
1517 : #ifdef INET6
1518 : #if defined(SCTP_EMBEDDED_V6_SCOPE)
1519 : struct sockaddr_in6 lsa6;
1520 :
1521 : sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1522 : &lsa6);
1523 : #endif
1524 : #endif
1525 : #ifdef HAVE_SA_LEN
1526 : memcpy(ss, sa, sa->sa_len);
1527 : #else
1528 0 : switch (sa->sa_family) {
1529 : #ifdef INET
1530 : case AF_INET:
1531 : memcpy(ss, sa, sizeof(struct sockaddr_in));
1532 : break;
1533 : #endif
1534 : #ifdef INET6
1535 : case AF_INET6:
1536 : memcpy(ss, sa, sizeof(struct sockaddr_in6));
1537 : break;
1538 : #endif
1539 : #if defined(__Userspace__)
1540 : case AF_CONN:
1541 0 : memcpy(ss, sa, sizeof(struct sockaddr_conn));
1542 0 : break;
1543 : #endif
1544 : default:
1545 : /* TSNH */
1546 0 : break;
1547 : }
1548 : #endif
1549 0 : return (0);
1550 : }
1551 :
1552 :
1553 :
1554 : /*
1555 : * NOTE: assumes addr lock is held
1556 : */
1557 : static size_t
1558 0 : sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
1559 : struct sctp_tcb *stcb,
1560 : size_t limit,
1561 : struct sockaddr_storage *sas,
1562 : uint32_t vrf_id)
1563 : {
1564 : struct sctp_ifn *sctp_ifn;
1565 : struct sctp_ifa *sctp_ifa;
1566 : size_t actual;
1567 : int loopback_scope;
1568 : #if defined(INET)
1569 : int ipv4_local_scope, ipv4_addr_legal;
1570 : #endif
1571 : #if defined(INET6)
1572 : int local_scope, site_scope, ipv6_addr_legal;
1573 : #endif
1574 : #if defined(__Userspace__)
1575 : int conn_addr_legal;
1576 : #endif
1577 : struct sctp_vrf *vrf;
1578 :
1579 0 : actual = 0;
1580 0 : if (limit <= 0)
1581 0 : return (actual);
1582 :
1583 0 : if (stcb) {
1584 : /* Turn on all the appropriate scope */
1585 0 : loopback_scope = stcb->asoc.scope.loopback_scope;
1586 : #if defined(INET)
1587 : ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
1588 : ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
1589 : #endif
1590 : #if defined(INET6)
1591 : local_scope = stcb->asoc.scope.local_scope;
1592 : site_scope = stcb->asoc.scope.site_scope;
1593 : ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
1594 : #endif
1595 : #if defined(__Userspace__)
1596 0 : conn_addr_legal = stcb->asoc.scope.conn_addr_legal;
1597 : #endif
1598 : } else {
1599 : /* Use generic values for endpoints. */
1600 0 : loopback_scope = 1;
1601 : #if defined(INET)
1602 : ipv4_local_scope = 1;
1603 : #endif
1604 : #if defined(INET6)
1605 : local_scope = 1;
1606 : site_scope = 1;
1607 : #endif
1608 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1609 : #if defined(INET6)
1610 : ipv6_addr_legal = 1;
1611 : #endif
1612 : #if defined(INET)
1613 : if (SCTP_IPV6_V6ONLY(inp)) {
1614 : ipv4_addr_legal = 0;
1615 : } else {
1616 : ipv4_addr_legal = 1;
1617 : }
1618 : #endif
1619 : #if defined(__Userspace__)
1620 0 : conn_addr_legal = 0;
1621 : #endif
1622 : } else {
1623 : #if defined(INET6)
1624 : ipv6_addr_legal = 0;
1625 : #endif
1626 : #if defined(__Userspace__)
1627 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
1628 0 : conn_addr_legal = 1;
1629 : #if defined(INET)
1630 : ipv4_addr_legal = 0;
1631 : #endif
1632 : } else {
1633 0 : conn_addr_legal = 0;
1634 : #if defined(INET)
1635 : ipv4_addr_legal = 1;
1636 : #endif
1637 : }
1638 : #else
1639 : #if defined(INET)
1640 : ipv4_addr_legal = 1;
1641 : #endif
1642 : #endif
1643 : }
1644 : }
1645 0 : vrf = sctp_find_vrf(vrf_id);
1646 0 : if (vrf == NULL) {
1647 0 : return (0);
1648 : }
1649 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1650 0 : LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1651 0 : if ((loopback_scope == 0) &&
1652 0 : SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
1653 : /* Skip loopback if loopback_scope not set */
1654 0 : continue;
1655 : }
1656 0 : LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1657 0 : if (stcb) {
1658 : /*
1659 : * For the BOUND-ALL case, the list
1660 : * associated with a TCB is Always
1661 : * considered a reverse list.. i.e.
1662 : * it lists addresses that are NOT
1663 : * part of the association. If this
1664 : * is one of those we must skip it.
1665 : */
1666 0 : if (sctp_is_addr_restricted(stcb,
1667 : sctp_ifa)) {
1668 0 : continue;
1669 : }
1670 : }
1671 0 : switch (sctp_ifa->address.sa.sa_family) {
1672 : #ifdef INET
1673 : case AF_INET:
1674 : if (ipv4_addr_legal) {
1675 : struct sockaddr_in *sin;
1676 :
1677 : sin = &sctp_ifa->address.sin;
1678 : if (sin->sin_addr.s_addr == 0) {
1679 : /*
1680 : * we skip unspecifed
1681 : * addresses
1682 : */
1683 : continue;
1684 : }
1685 : #if defined(__FreeBSD__)
1686 : if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
1687 : &sin->sin_addr) != 0) {
1688 : continue;
1689 : }
1690 : #endif
1691 : if ((ipv4_local_scope == 0) &&
1692 : (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1693 : continue;
1694 : }
1695 : #ifdef INET6
1696 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
1697 : in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1698 : ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1699 : sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1700 : actual += sizeof(struct sockaddr_in6);
1701 : } else {
1702 : #endif
1703 : memcpy(sas, sin, sizeof(*sin));
1704 : ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1705 : sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1706 : actual += sizeof(*sin);
1707 : #ifdef INET6
1708 : }
1709 : #endif
1710 : if (actual >= limit) {
1711 : return (actual);
1712 : }
1713 : } else {
1714 : continue;
1715 : }
1716 : break;
1717 : #endif
1718 : #ifdef INET6
1719 : case AF_INET6:
1720 : if (ipv6_addr_legal) {
1721 : struct sockaddr_in6 *sin6;
1722 :
1723 : #if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME)
1724 : struct sockaddr_in6 lsa6;
1725 : #endif
1726 : sin6 = &sctp_ifa->address.sin6;
1727 : if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1728 : /*
1729 : * we skip unspecifed
1730 : * addresses
1731 : */
1732 : continue;
1733 : }
1734 : #if defined(__FreeBSD__)
1735 : if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
1736 : &sin6->sin6_addr) != 0) {
1737 : continue;
1738 : }
1739 : #endif
1740 : if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1741 : if (local_scope == 0)
1742 : continue;
1743 : #if defined(SCTP_EMBEDDED_V6_SCOPE)
1744 : if (sin6->sin6_scope_id == 0) {
1745 : #ifdef SCTP_KAME
1746 : if (sa6_recoverscope(sin6) != 0)
1747 : /*
1748 : * bad link
1749 : * local
1750 : * address
1751 : */
1752 : continue;
1753 : #else
1754 : lsa6 = *sin6;
1755 : if (in6_recoverscope(&lsa6,
1756 : &lsa6.sin6_addr,
1757 : NULL))
1758 : /*
1759 : * bad link
1760 : * local
1761 : * address
1762 : */
1763 : continue;
1764 : sin6 = &lsa6;
1765 : #endif /* SCTP_KAME */
1766 : }
1767 : #endif /* SCTP_EMBEDDED_V6_SCOPE */
1768 : }
1769 : if ((site_scope == 0) &&
1770 : (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1771 : continue;
1772 : }
1773 : memcpy(sas, sin6, sizeof(*sin6));
1774 : ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1775 : sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1776 : actual += sizeof(*sin6);
1777 : if (actual >= limit) {
1778 : return (actual);
1779 : }
1780 : } else {
1781 : continue;
1782 : }
1783 : break;
1784 : #endif
1785 : #if defined(__Userspace__)
1786 : case AF_CONN:
1787 0 : if (conn_addr_legal) {
1788 0 : memcpy(sas, &sctp_ifa->address.sconn, sizeof(struct sockaddr_conn));
1789 0 : ((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport;
1790 0 : sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_conn));
1791 0 : actual += sizeof(struct sockaddr_conn);
1792 0 : if (actual >= limit) {
1793 0 : return (actual);
1794 : }
1795 : } else {
1796 0 : continue;
1797 : }
1798 : #endif
1799 : default:
1800 : /* TSNH */
1801 0 : break;
1802 : }
1803 : }
1804 : }
1805 : } else {
1806 : struct sctp_laddr *laddr;
1807 : #ifndef HAVE_SA_LEN
1808 0 : uint32_t sa_len = 0;
1809 : #endif
1810 :
1811 0 : LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1812 0 : if (stcb) {
1813 0 : if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
1814 0 : continue;
1815 : }
1816 : }
1817 0 : if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
1818 0 : continue;
1819 0 : switch (laddr->ifa->address.sa.sa_family) {
1820 : #ifdef INET
1821 : case AF_INET:
1822 : ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1823 : break;
1824 : #endif
1825 : #ifdef INET6
1826 : case AF_INET6:
1827 : ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1828 : break;
1829 : #endif
1830 : #if defined(__Userspace__)
1831 : case AF_CONN:
1832 0 : ((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport;
1833 0 : break;
1834 : #endif
1835 : default:
1836 : /* TSNH */
1837 0 : break;
1838 : }
1839 : #ifdef HAVE_SA_LEN
1840 : sas = (struct sockaddr_storage *)((caddr_t)sas +
1841 : laddr->ifa->address.sa.sa_len);
1842 : actual += laddr->ifa->address.sa.sa_len;
1843 : #else
1844 0 : switch (laddr->ifa->address.sa.sa_family) {
1845 : #ifdef INET
1846 : case AF_INET:
1847 : sa_len = sizeof(struct sockaddr_in);
1848 : break;
1849 : #endif
1850 : #ifdef INET6
1851 : case AF_INET6:
1852 : sa_len = sizeof(struct sockaddr_in6);
1853 : break;
1854 : #endif
1855 : #if defined(__Userspace__)
1856 : case AF_CONN:
1857 0 : sa_len = sizeof(struct sockaddr_conn);
1858 0 : break;
1859 : #endif
1860 : default:
1861 : /* TSNH */
1862 0 : break;
1863 : }
1864 0 : sas = (struct sockaddr_storage *)((caddr_t)sas + sa_len);
1865 0 : actual += sa_len;
1866 : #endif
1867 0 : if (actual >= limit) {
1868 0 : return (actual);
1869 : }
1870 : }
1871 : }
1872 0 : return (actual);
1873 : }
1874 :
1875 : static size_t
1876 0 : sctp_fill_up_addresses(struct sctp_inpcb *inp,
1877 : struct sctp_tcb *stcb,
1878 : size_t limit,
1879 : struct sockaddr_storage *sas)
1880 : {
1881 0 : size_t size = 0;
1882 : #ifdef SCTP_MVRF
1883 : uint32_t id;
1884 : #endif
1885 :
1886 0 : SCTP_IPI_ADDR_RLOCK();
1887 : #ifdef SCTP_MVRF
1888 : /*
1889 : * FIX ME: ?? this WILL report duplicate addresses if they appear
1890 : * in more than one VRF.
1891 : */
1892 : /* fill up addresses for all VRFs on the endpoint */
1893 : for (id = 0; (id < inp->num_vrfs) && (size < limit); id++) {
1894 : size += sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1895 : inp->m_vrf_ids[id]);
1896 : sas = (struct sockaddr_storage *)((caddr_t)sas + size);
1897 : }
1898 : #else
1899 : /* fill up addresses for the endpoint's default vrf */
1900 0 : size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1901 : inp->def_vrf_id);
1902 : #endif
1903 0 : SCTP_IPI_ADDR_RUNLOCK();
1904 0 : return (size);
1905 : }
1906 :
1907 : /*
1908 : * NOTE: assumes addr lock is held
1909 : */
1910 : static int
1911 0 : sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
1912 : {
1913 0 : int cnt = 0;
1914 0 : struct sctp_vrf *vrf = NULL;
1915 :
1916 : /*
1917 : * In both sub-set bound an bound_all cases we return the MAXIMUM
1918 : * number of addresses that you COULD get. In reality the sub-set
1919 : * bound may have an exclusion list for a given TCB OR in the
1920 : * bound-all case a TCB may NOT include the loopback or other
1921 : * addresses as well.
1922 : */
1923 0 : vrf = sctp_find_vrf(vrf_id);
1924 0 : if (vrf == NULL) {
1925 0 : return (0);
1926 : }
1927 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1928 : struct sctp_ifn *sctp_ifn;
1929 : struct sctp_ifa *sctp_ifa;
1930 :
1931 0 : LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1932 0 : LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1933 : /* Count them if they are the right type */
1934 0 : switch (sctp_ifa->address.sa.sa_family) {
1935 : #ifdef INET
1936 : case AF_INET:
1937 : #ifdef INET6
1938 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1939 : cnt += sizeof(struct sockaddr_in6);
1940 : else
1941 : cnt += sizeof(struct sockaddr_in);
1942 : #else
1943 : cnt += sizeof(struct sockaddr_in);
1944 : #endif
1945 : break;
1946 : #endif
1947 : #ifdef INET6
1948 : case AF_INET6:
1949 : cnt += sizeof(struct sockaddr_in6);
1950 : break;
1951 : #endif
1952 : #if defined(__Userspace__)
1953 : case AF_CONN:
1954 0 : cnt += sizeof(struct sockaddr_conn);
1955 0 : break;
1956 : #endif
1957 : default:
1958 0 : break;
1959 : }
1960 : }
1961 : }
1962 : } else {
1963 : struct sctp_laddr *laddr;
1964 :
1965 0 : LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1966 0 : switch (laddr->ifa->address.sa.sa_family) {
1967 : #ifdef INET
1968 : case AF_INET:
1969 : #ifdef INET6
1970 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1971 : cnt += sizeof(struct sockaddr_in6);
1972 : else
1973 : cnt += sizeof(struct sockaddr_in);
1974 : #else
1975 : cnt += sizeof(struct sockaddr_in);
1976 : #endif
1977 : break;
1978 : #endif
1979 : #ifdef INET6
1980 : case AF_INET6:
1981 : cnt += sizeof(struct sockaddr_in6);
1982 : break;
1983 : #endif
1984 : #if defined(__Userspace__)
1985 : case AF_CONN:
1986 0 : cnt += sizeof(struct sockaddr_conn);
1987 0 : break;
1988 : #endif
1989 : default:
1990 0 : break;
1991 : }
1992 : }
1993 : }
1994 0 : return (cnt);
1995 : }
1996 :
1997 : static int
1998 0 : sctp_count_max_addresses(struct sctp_inpcb *inp)
1999 : {
2000 0 : int cnt = 0;
2001 : #ifdef SCTP_MVRF
2002 : int id;
2003 : #endif
2004 :
2005 0 : SCTP_IPI_ADDR_RLOCK();
2006 : #ifdef SCTP_MVRF
2007 : /*
2008 : * FIX ME: ?? this WILL count duplicate addresses if they appear
2009 : * in more than one VRF.
2010 : */
2011 : /* count addresses for all VRFs on the endpoint */
2012 : for (id = 0; id < inp->num_vrfs; id++) {
2013 : cnt += sctp_count_max_addresses_vrf(inp, inp->m_vrf_ids[id]);
2014 : }
2015 : #else
2016 : /* count addresses for the endpoint's default VRF */
2017 0 : cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
2018 : #endif
2019 0 : SCTP_IPI_ADDR_RUNLOCK();
2020 0 : return (cnt);
2021 : }
2022 :
2023 : static int
2024 0 : sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
2025 : size_t optsize, void *p, int delay)
2026 : {
2027 0 : int error = 0;
2028 0 : int creat_lock_on = 0;
2029 0 : struct sctp_tcb *stcb = NULL;
2030 : struct sockaddr *sa;
2031 0 : int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
2032 : uint32_t vrf_id;
2033 0 : int bad_addresses = 0;
2034 : sctp_assoc_t *a_id;
2035 :
2036 0 : SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
2037 :
2038 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
2039 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
2040 : /* We are already connected AND the TCP model */
2041 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
2042 0 : return (EADDRINUSE);
2043 : }
2044 :
2045 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
2046 0 : (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
2047 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2048 0 : return (EINVAL);
2049 : }
2050 :
2051 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2052 0 : SCTP_INP_RLOCK(inp);
2053 0 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
2054 0 : SCTP_INP_RUNLOCK(inp);
2055 : }
2056 0 : if (stcb) {
2057 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
2058 0 : return (EALREADY);
2059 : }
2060 0 : SCTP_INP_INCR_REF(inp);
2061 0 : SCTP_ASOC_CREATE_LOCK(inp);
2062 0 : creat_lock_on = 1;
2063 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
2064 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
2065 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
2066 0 : error = EFAULT;
2067 0 : goto out_now;
2068 : }
2069 0 : totaddrp = (int *)optval;
2070 0 : totaddr = *totaddrp;
2071 0 : sa = (struct sockaddr *)(totaddrp + 1);
2072 0 : stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
2073 0 : if ((stcb != NULL) || bad_addresses) {
2074 : /* Already have or am bring up an association */
2075 0 : SCTP_ASOC_CREATE_UNLOCK(inp);
2076 0 : creat_lock_on = 0;
2077 0 : if (stcb)
2078 0 : SCTP_TCB_UNLOCK(stcb);
2079 0 : if (bad_addresses == 0) {
2080 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
2081 0 : error = EALREADY;
2082 : }
2083 0 : goto out_now;
2084 : }
2085 : #ifdef INET6
2086 : if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
2087 : (num_v6 > 0)) {
2088 : error = EINVAL;
2089 : goto out_now;
2090 : }
2091 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2092 : (num_v4 > 0)) {
2093 : struct in6pcb *inp6;
2094 :
2095 : inp6 = (struct in6pcb *)inp;
2096 : if (SCTP_IPV6_V6ONLY(inp6)) {
2097 : /*
2098 : * if IPV6_V6ONLY flag, ignore connections destined
2099 : * to a v4 addr or v4-mapped addr
2100 : */
2101 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2102 : error = EINVAL;
2103 : goto out_now;
2104 : }
2105 : }
2106 : #endif /* INET6 */
2107 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
2108 : SCTP_PCB_FLAGS_UNBOUND) {
2109 : /* Bind a ephemeral port */
2110 0 : error = sctp_inpcb_bind(so, NULL, NULL, p);
2111 0 : if (error) {
2112 0 : goto out_now;
2113 : }
2114 : }
2115 :
2116 : /* FIX ME: do we want to pass in a vrf on the connect call? */
2117 0 : vrf_id = inp->def_vrf_id;
2118 :
2119 :
2120 : /* We are GOOD to go */
2121 0 : stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
2122 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
2123 : (struct thread *)p
2124 : #elif defined(__Windows__)
2125 : (PKTHREAD)p
2126 : #else
2127 : (struct proc *)p
2128 : #endif
2129 : );
2130 0 : if (stcb == NULL) {
2131 : /* Gak! no memory */
2132 0 : goto out_now;
2133 : }
2134 0 : if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
2135 0 : stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
2136 : /* Set the connected flag so we can queue data */
2137 0 : soisconnecting(so);
2138 : }
2139 0 : SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
2140 : /* move to second address */
2141 0 : switch (sa->sa_family) {
2142 : #ifdef INET
2143 : case AF_INET:
2144 : sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
2145 : break;
2146 : #endif
2147 : #ifdef INET6
2148 : case AF_INET6:
2149 : sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
2150 : break;
2151 : #endif
2152 : default:
2153 0 : break;
2154 : }
2155 :
2156 0 : error = 0;
2157 0 : sctp_connectx_helper_add(stcb, sa, (totaddr-1), &error);
2158 : /* Fill in the return id */
2159 0 : if (error) {
2160 0 : (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6);
2161 0 : goto out_now;
2162 : }
2163 0 : a_id = (sctp_assoc_t *)optval;
2164 0 : *a_id = sctp_get_associd(stcb);
2165 :
2166 : /* initialize authentication parameters for the assoc */
2167 0 : sctp_initialize_auth_params(inp, stcb);
2168 :
2169 0 : if (delay) {
2170 : /* doing delayed connection */
2171 0 : stcb->asoc.delayed_connection = 1;
2172 0 : sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
2173 : } else {
2174 0 : (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
2175 0 : sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
2176 : }
2177 0 : SCTP_TCB_UNLOCK(stcb);
2178 0 : if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
2179 0 : stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
2180 : /* Set the connected flag so we can queue data */
2181 0 : soisconnecting(so);
2182 : }
2183 : out_now:
2184 0 : if (creat_lock_on) {
2185 0 : SCTP_ASOC_CREATE_UNLOCK(inp);
2186 : }
2187 0 : SCTP_INP_DECR_REF(inp);
2188 0 : return (error);
2189 : }
2190 :
2191 : #define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
2192 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
2193 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
2194 : SCTP_INP_RLOCK(inp); \
2195 : stcb = LIST_FIRST(&inp->sctp_asoc_list); \
2196 : if (stcb) { \
2197 : SCTP_TCB_LOCK(stcb); \
2198 : } \
2199 : SCTP_INP_RUNLOCK(inp); \
2200 : } else if (assoc_id > SCTP_ALL_ASSOC) { \
2201 : stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
2202 : if (stcb == NULL) { \
2203 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
2204 : error = ENOENT; \
2205 : break; \
2206 : } \
2207 : } else { \
2208 : stcb = NULL; \
2209 : } \
2210 : }
2211 :
2212 :
2213 : #define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
2214 : if (size < sizeof(type)) { \
2215 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
2216 : error = EINVAL; \
2217 : break; \
2218 : } else { \
2219 : destp = (type *)srcp; \
2220 : } \
2221 : }
2222 :
2223 : #if defined(__Panda__) || defined(__Userspace__)
2224 : int
2225 : #else
2226 : static int
2227 : #endif
2228 0 : sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
2229 : void *p) {
2230 0 : struct sctp_inpcb *inp = NULL;
2231 0 : int error, val = 0;
2232 0 : struct sctp_tcb *stcb = NULL;
2233 :
2234 0 : if (optval == NULL) {
2235 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2236 0 : return (EINVAL);
2237 : }
2238 :
2239 0 : inp = (struct sctp_inpcb *)so->so_pcb;
2240 0 : if (inp == NULL) {
2241 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2242 0 : return EINVAL;
2243 : }
2244 0 : error = 0;
2245 :
2246 0 : switch (optname) {
2247 : case SCTP_NODELAY:
2248 : case SCTP_AUTOCLOSE:
2249 : case SCTP_EXPLICIT_EOR:
2250 : case SCTP_AUTO_ASCONF:
2251 : case SCTP_DISABLE_FRAGMENTS:
2252 : case SCTP_I_WANT_MAPPED_V4_ADDR:
2253 : case SCTP_USE_EXT_RCVINFO:
2254 0 : SCTP_INP_RLOCK(inp);
2255 0 : switch (optname) {
2256 : case SCTP_DISABLE_FRAGMENTS:
2257 0 : val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
2258 0 : break;
2259 : case SCTP_I_WANT_MAPPED_V4_ADDR:
2260 0 : val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
2261 0 : break;
2262 : case SCTP_AUTO_ASCONF:
2263 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
2264 : /* only valid for bound all sockets */
2265 0 : val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
2266 : } else {
2267 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2268 0 : error = EINVAL;
2269 0 : goto flags_out;
2270 : }
2271 0 : break;
2272 : case SCTP_EXPLICIT_EOR:
2273 0 : val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
2274 0 : break;
2275 : case SCTP_NODELAY:
2276 0 : val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
2277 0 : break;
2278 : case SCTP_USE_EXT_RCVINFO:
2279 0 : val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
2280 0 : break;
2281 : case SCTP_AUTOCLOSE:
2282 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
2283 0 : val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
2284 : else
2285 0 : val = 0;
2286 0 : break;
2287 :
2288 : default:
2289 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
2290 0 : error = ENOPROTOOPT;
2291 : } /* end switch (sopt->sopt_name) */
2292 0 : if (*optsize < sizeof(val)) {
2293 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2294 0 : error = EINVAL;
2295 : }
2296 : flags_out:
2297 0 : SCTP_INP_RUNLOCK(inp);
2298 0 : if (error == 0) {
2299 : /* return the option value */
2300 0 : *(int *)optval = val;
2301 0 : *optsize = sizeof(val);
2302 : }
2303 0 : break;
2304 : case SCTP_GET_PACKET_LOG:
2305 : {
2306 : #ifdef SCTP_PACKET_LOGGING
2307 : uint8_t *target;
2308 : int ret;
2309 :
2310 : SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
2311 : ret = sctp_copy_out_packet_log(target , (int)*optsize);
2312 : *optsize = ret;
2313 : #else
2314 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
2315 0 : error = EOPNOTSUPP;
2316 : #endif
2317 0 : break;
2318 : }
2319 : case SCTP_REUSE_PORT:
2320 : {
2321 : uint32_t *value;
2322 :
2323 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
2324 : /* Can't do this for a 1-m socket */
2325 0 : error = EINVAL;
2326 0 : break;
2327 : }
2328 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2329 0 : *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
2330 0 : *optsize = sizeof(uint32_t);
2331 0 : break;
2332 : }
2333 : case SCTP_PARTIAL_DELIVERY_POINT:
2334 : {
2335 : uint32_t *value;
2336 :
2337 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2338 0 : *value = inp->partial_delivery_point;
2339 0 : *optsize = sizeof(uint32_t);
2340 0 : break;
2341 : }
2342 : case SCTP_FRAGMENT_INTERLEAVE:
2343 : {
2344 : uint32_t *value;
2345 :
2346 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2347 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
2348 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
2349 0 : *value = SCTP_FRAG_LEVEL_2;
2350 : } else {
2351 0 : *value = SCTP_FRAG_LEVEL_1;
2352 : }
2353 : } else {
2354 0 : *value = SCTP_FRAG_LEVEL_0;
2355 : }
2356 0 : *optsize = sizeof(uint32_t);
2357 0 : break;
2358 : }
2359 : case SCTP_CMT_ON_OFF:
2360 : {
2361 : struct sctp_assoc_value *av;
2362 :
2363 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2364 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2365 0 : if (stcb) {
2366 0 : av->assoc_value = stcb->asoc.sctp_cmt_on_off;
2367 0 : SCTP_TCB_UNLOCK(stcb);
2368 : } else {
2369 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2370 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2371 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2372 0 : SCTP_INP_RLOCK(inp);
2373 0 : av->assoc_value = inp->sctp_cmt_on_off;
2374 0 : SCTP_INP_RUNLOCK(inp);
2375 : } else {
2376 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2377 0 : error = EINVAL;
2378 : }
2379 : }
2380 0 : if (error == 0) {
2381 0 : *optsize = sizeof(struct sctp_assoc_value);
2382 : }
2383 0 : break;
2384 : }
2385 : case SCTP_PLUGGABLE_CC:
2386 : {
2387 : struct sctp_assoc_value *av;
2388 :
2389 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2390 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2391 0 : if (stcb) {
2392 0 : av->assoc_value = stcb->asoc.congestion_control_module;
2393 0 : SCTP_TCB_UNLOCK(stcb);
2394 : } else {
2395 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2396 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2397 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2398 0 : SCTP_INP_RLOCK(inp);
2399 0 : av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
2400 0 : SCTP_INP_RUNLOCK(inp);
2401 : } else {
2402 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2403 0 : error = EINVAL;
2404 : }
2405 : }
2406 0 : if (error == 0) {
2407 0 : *optsize = sizeof(struct sctp_assoc_value);
2408 : }
2409 0 : break;
2410 : }
2411 : case SCTP_CC_OPTION:
2412 : {
2413 : struct sctp_cc_option *cc_opt;
2414 :
2415 0 : SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
2416 0 : SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
2417 0 : if (stcb == NULL) {
2418 0 : error = EINVAL;
2419 : } else {
2420 0 : if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
2421 0 : error = ENOTSUP;
2422 : } else {
2423 0 : error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 0, cc_opt);
2424 0 : *optsize = sizeof(struct sctp_cc_option);
2425 : }
2426 0 : SCTP_TCB_UNLOCK(stcb);
2427 : }
2428 0 : break;
2429 : }
2430 : case SCTP_PLUGGABLE_SS:
2431 : {
2432 : struct sctp_assoc_value *av;
2433 :
2434 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2435 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2436 0 : if (stcb) {
2437 0 : av->assoc_value = stcb->asoc.stream_scheduling_module;
2438 0 : SCTP_TCB_UNLOCK(stcb);
2439 : } else {
2440 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2441 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2442 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2443 0 : SCTP_INP_RLOCK(inp);
2444 0 : av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
2445 0 : SCTP_INP_RUNLOCK(inp);
2446 : } else {
2447 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2448 0 : error = EINVAL;
2449 : }
2450 : }
2451 0 : if (error == 0) {
2452 0 : *optsize = sizeof(struct sctp_assoc_value);
2453 : }
2454 0 : break;
2455 : }
2456 : case SCTP_SS_VALUE:
2457 : {
2458 : struct sctp_stream_value *av;
2459 :
2460 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
2461 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2462 0 : if (stcb) {
2463 0 : if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
2464 0 : (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
2465 : &av->stream_value) < 0)) {
2466 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2467 0 : error = EINVAL;
2468 : } else {
2469 0 : *optsize = sizeof(struct sctp_stream_value);
2470 : }
2471 0 : SCTP_TCB_UNLOCK(stcb);
2472 : } else {
2473 : /* Can't get stream value without association */
2474 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2475 0 : error = EINVAL;
2476 : }
2477 0 : break;
2478 : }
2479 : case SCTP_GET_ADDR_LEN:
2480 : {
2481 : struct sctp_assoc_value *av;
2482 :
2483 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2484 0 : error = EINVAL;
2485 : #ifdef INET
2486 : if (av->assoc_value == AF_INET) {
2487 : av->assoc_value = sizeof(struct sockaddr_in);
2488 : error = 0;
2489 : }
2490 : #endif
2491 : #ifdef INET6
2492 : if (av->assoc_value == AF_INET6) {
2493 : av->assoc_value = sizeof(struct sockaddr_in6);
2494 : error = 0;
2495 : }
2496 : #endif
2497 : #if defined(__Userspace__)
2498 0 : if (av->assoc_value == AF_CONN) {
2499 0 : av->assoc_value = sizeof(struct sockaddr_conn);
2500 0 : error = 0;
2501 : }
2502 : #endif
2503 0 : if (error) {
2504 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2505 : } else {
2506 0 : *optsize = sizeof(struct sctp_assoc_value);
2507 : }
2508 0 : break;
2509 : }
2510 : case SCTP_GET_ASSOC_NUMBER:
2511 : {
2512 : uint32_t *value, cnt;
2513 :
2514 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2515 0 : cnt = 0;
2516 0 : SCTP_INP_RLOCK(inp);
2517 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
2518 0 : cnt++;
2519 : }
2520 0 : SCTP_INP_RUNLOCK(inp);
2521 0 : *value = cnt;
2522 0 : *optsize = sizeof(uint32_t);
2523 0 : break;
2524 : }
2525 : case SCTP_GET_ASSOC_ID_LIST:
2526 : {
2527 : struct sctp_assoc_ids *ids;
2528 : unsigned int at, limit;
2529 :
2530 0 : SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
2531 0 : at = 0;
2532 0 : limit = (*optsize-sizeof(uint32_t))/ sizeof(sctp_assoc_t);
2533 0 : SCTP_INP_RLOCK(inp);
2534 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
2535 0 : if (at < limit) {
2536 0 : ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
2537 : } else {
2538 0 : error = EINVAL;
2539 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2540 0 : break;
2541 : }
2542 : }
2543 0 : SCTP_INP_RUNLOCK(inp);
2544 0 : if (error == 0) {
2545 0 : ids->gaids_number_of_ids = at;
2546 0 : *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
2547 : }
2548 0 : break;
2549 : }
2550 : case SCTP_CONTEXT:
2551 : {
2552 : struct sctp_assoc_value *av;
2553 :
2554 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2555 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2556 :
2557 0 : if (stcb) {
2558 0 : av->assoc_value = stcb->asoc.context;
2559 0 : SCTP_TCB_UNLOCK(stcb);
2560 : } else {
2561 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2562 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2563 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2564 0 : SCTP_INP_RLOCK(inp);
2565 0 : av->assoc_value = inp->sctp_context;
2566 0 : SCTP_INP_RUNLOCK(inp);
2567 : } else {
2568 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2569 0 : error = EINVAL;
2570 : }
2571 : }
2572 0 : if (error == 0) {
2573 0 : *optsize = sizeof(struct sctp_assoc_value);
2574 : }
2575 0 : break;
2576 : }
2577 : case SCTP_VRF_ID:
2578 : {
2579 : uint32_t *default_vrfid;
2580 :
2581 0 : SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
2582 0 : *default_vrfid = inp->def_vrf_id;
2583 0 : *optsize = sizeof(uint32_t);
2584 0 : break;
2585 : }
2586 : case SCTP_GET_ASOC_VRF:
2587 : {
2588 : struct sctp_assoc_value *id;
2589 :
2590 0 : SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
2591 0 : SCTP_FIND_STCB(inp, stcb, id->assoc_id);
2592 0 : if (stcb == NULL) {
2593 0 : error = EINVAL;
2594 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2595 : } else {
2596 0 : id->assoc_value = stcb->asoc.vrf_id;
2597 0 : *optsize = sizeof(struct sctp_assoc_value);
2598 : }
2599 0 : break;
2600 : }
2601 : case SCTP_GET_VRF_IDS:
2602 : {
2603 : #ifdef SCTP_MVRF
2604 : int siz_needed;
2605 : uint32_t *vrf_ids;
2606 :
2607 : SCTP_CHECK_AND_CAST(vrf_ids, optval, uint32_t, *optsize);
2608 : siz_needed = inp->num_vrfs * sizeof(uint32_t);
2609 : if (*optsize < siz_needed) {
2610 : error = EINVAL;
2611 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2612 : } else {
2613 : memcpy(vrf_ids, inp->m_vrf_ids, siz_needed);
2614 : *optsize = siz_needed;
2615 : }
2616 : #else
2617 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
2618 0 : error = EOPNOTSUPP;
2619 : #endif
2620 0 : break;
2621 : }
2622 : case SCTP_GET_NONCE_VALUES:
2623 : {
2624 : struct sctp_get_nonce_values *gnv;
2625 :
2626 0 : SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
2627 0 : SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
2628 :
2629 0 : if (stcb) {
2630 0 : gnv->gn_peers_tag = stcb->asoc.peer_vtag;
2631 0 : gnv->gn_local_tag = stcb->asoc.my_vtag;
2632 0 : SCTP_TCB_UNLOCK(stcb);
2633 0 : *optsize = sizeof(struct sctp_get_nonce_values);
2634 : } else {
2635 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2636 0 : error = ENOTCONN;
2637 : }
2638 0 : break;
2639 : }
2640 : case SCTP_DELAYED_SACK:
2641 : {
2642 : struct sctp_sack_info *sack;
2643 :
2644 0 : SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
2645 0 : SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
2646 0 : if (stcb) {
2647 0 : sack->sack_delay = stcb->asoc.delayed_ack;
2648 0 : sack->sack_freq = stcb->asoc.sack_freq;
2649 0 : SCTP_TCB_UNLOCK(stcb);
2650 : } else {
2651 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2652 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2653 0 : (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) {
2654 0 : SCTP_INP_RLOCK(inp);
2655 0 : sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2656 0 : sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
2657 0 : SCTP_INP_RUNLOCK(inp);
2658 : } else {
2659 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2660 0 : error = EINVAL;
2661 : }
2662 : }
2663 0 : if (error == 0) {
2664 0 : *optsize = sizeof(struct sctp_sack_info);
2665 : }
2666 0 : break;
2667 : }
2668 : case SCTP_GET_SNDBUF_USE:
2669 : {
2670 : struct sctp_sockstat *ss;
2671 :
2672 0 : SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
2673 0 : SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
2674 :
2675 0 : if (stcb) {
2676 0 : ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
2677 0 : ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
2678 0 : stcb->asoc.size_on_all_streams);
2679 0 : SCTP_TCB_UNLOCK(stcb);
2680 0 : *optsize = sizeof(struct sctp_sockstat);
2681 : } else {
2682 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2683 0 : error = ENOTCONN;
2684 : }
2685 0 : break;
2686 : }
2687 : case SCTP_MAX_BURST:
2688 : {
2689 : #if defined(__FreeBSD__) && __FreeBSD_version < 900000
2690 : uint8_t *value;
2691 :
2692 : SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize);
2693 :
2694 : SCTP_INP_RLOCK(inp);
2695 : if (inp->sctp_ep.max_burst < 256) {
2696 : *value = inp->sctp_ep.max_burst;
2697 : } else {
2698 : *value = 255;
2699 : }
2700 : SCTP_INP_RUNLOCK(inp);
2701 : *optsize = sizeof(uint8_t);
2702 : #else
2703 : struct sctp_assoc_value *av;
2704 :
2705 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2706 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2707 :
2708 0 : if (stcb) {
2709 0 : av->assoc_value = stcb->asoc.max_burst;
2710 0 : SCTP_TCB_UNLOCK(stcb);
2711 : } else {
2712 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2713 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2714 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2715 0 : SCTP_INP_RLOCK(inp);
2716 0 : av->assoc_value = inp->sctp_ep.max_burst;
2717 0 : SCTP_INP_RUNLOCK(inp);
2718 : } else {
2719 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2720 0 : error = EINVAL;
2721 : }
2722 : }
2723 0 : if (error == 0) {
2724 0 : *optsize = sizeof(struct sctp_assoc_value);
2725 : }
2726 : #endif
2727 0 : break;
2728 : }
2729 : case SCTP_MAXSEG:
2730 : {
2731 : struct sctp_assoc_value *av;
2732 : int ovh;
2733 :
2734 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2735 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2736 :
2737 0 : if (stcb) {
2738 0 : av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
2739 0 : SCTP_TCB_UNLOCK(stcb);
2740 : } else {
2741 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2742 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2743 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2744 0 : SCTP_INP_RLOCK(inp);
2745 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2746 0 : ovh = SCTP_MED_OVERHEAD;
2747 : } else {
2748 0 : ovh = SCTP_MED_V4_OVERHEAD;
2749 : }
2750 0 : if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
2751 0 : av->assoc_value = 0;
2752 : else
2753 0 : av->assoc_value = inp->sctp_frag_point - ovh;
2754 0 : SCTP_INP_RUNLOCK(inp);
2755 : } else {
2756 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2757 0 : error = EINVAL;
2758 : }
2759 : }
2760 0 : if (error == 0) {
2761 0 : *optsize = sizeof(struct sctp_assoc_value);
2762 : }
2763 0 : break;
2764 : }
2765 : case SCTP_GET_STAT_LOG:
2766 0 : error = sctp_fill_stat_log(optval, optsize);
2767 0 : break;
2768 : case SCTP_EVENTS:
2769 : {
2770 : struct sctp_event_subscribe *events;
2771 :
2772 0 : SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
2773 0 : memset(events, 0, sizeof(struct sctp_event_subscribe));
2774 0 : SCTP_INP_RLOCK(inp);
2775 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
2776 0 : events->sctp_data_io_event = 1;
2777 :
2778 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
2779 0 : events->sctp_association_event = 1;
2780 :
2781 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
2782 0 : events->sctp_address_event = 1;
2783 :
2784 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2785 0 : events->sctp_send_failure_event = 1;
2786 :
2787 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
2788 0 : events->sctp_peer_error_event = 1;
2789 :
2790 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2791 0 : events->sctp_shutdown_event = 1;
2792 :
2793 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
2794 0 : events->sctp_partial_delivery_event = 1;
2795 :
2796 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
2797 0 : events->sctp_adaptation_layer_event = 1;
2798 :
2799 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
2800 0 : events->sctp_authentication_event = 1;
2801 :
2802 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
2803 0 : events->sctp_sender_dry_event = 1;
2804 :
2805 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2806 0 : events->sctp_stream_reset_event = 1;
2807 0 : SCTP_INP_RUNLOCK(inp);
2808 0 : *optsize = sizeof(struct sctp_event_subscribe);
2809 0 : break;
2810 : }
2811 : case SCTP_ADAPTATION_LAYER:
2812 : {
2813 : uint32_t *value;
2814 :
2815 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2816 :
2817 0 : SCTP_INP_RLOCK(inp);
2818 0 : *value = inp->sctp_ep.adaptation_layer_indicator;
2819 0 : SCTP_INP_RUNLOCK(inp);
2820 0 : *optsize = sizeof(uint32_t);
2821 0 : break;
2822 : }
2823 : case SCTP_SET_INITIAL_DBG_SEQ:
2824 : {
2825 : uint32_t *value;
2826 :
2827 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2828 0 : SCTP_INP_RLOCK(inp);
2829 0 : *value = inp->sctp_ep.initial_sequence_debug;
2830 0 : SCTP_INP_RUNLOCK(inp);
2831 0 : *optsize = sizeof(uint32_t);
2832 0 : break;
2833 : }
2834 : case SCTP_GET_LOCAL_ADDR_SIZE:
2835 : {
2836 : uint32_t *value;
2837 :
2838 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2839 0 : SCTP_INP_RLOCK(inp);
2840 0 : *value = sctp_count_max_addresses(inp);
2841 0 : SCTP_INP_RUNLOCK(inp);
2842 0 : *optsize = sizeof(uint32_t);
2843 0 : break;
2844 : }
2845 : case SCTP_GET_REMOTE_ADDR_SIZE:
2846 : {
2847 : uint32_t *value;
2848 : size_t size;
2849 : struct sctp_nets *net;
2850 :
2851 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2852 : /* FIXME MT: change to sctp_assoc_value? */
2853 0 : SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value);
2854 :
2855 0 : if (stcb) {
2856 0 : size = 0;
2857 : /* Count the sizes */
2858 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2859 0 : switch (net->ro._l_addr.sa.sa_family) {
2860 : #ifdef INET
2861 : case AF_INET:
2862 : #ifdef INET6
2863 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2864 : size += sizeof(struct sockaddr_in6);
2865 : } else {
2866 : size += sizeof(struct sockaddr_in);
2867 : }
2868 : #else
2869 : size += sizeof(struct sockaddr_in);
2870 : #endif
2871 : break;
2872 : #endif
2873 : #ifdef INET6
2874 : case AF_INET6:
2875 : size += sizeof(struct sockaddr_in6);
2876 : break;
2877 : #endif
2878 : #if defined(__Userspace__)
2879 : case AF_CONN:
2880 0 : size += sizeof(struct sockaddr_conn);
2881 0 : break;
2882 : #endif
2883 : default:
2884 0 : break;
2885 : }
2886 : }
2887 0 : SCTP_TCB_UNLOCK(stcb);
2888 0 : *value = (uint32_t) size;
2889 0 : *optsize = sizeof(uint32_t);
2890 : } else {
2891 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2892 0 : error = ENOTCONN;
2893 : }
2894 0 : break;
2895 : }
2896 : case SCTP_GET_PEER_ADDRESSES:
2897 : /*
2898 : * Get the address information, an array is passed in to
2899 : * fill up we pack it.
2900 : */
2901 : {
2902 : size_t cpsz, left;
2903 : struct sockaddr_storage *sas;
2904 : struct sctp_nets *net;
2905 : struct sctp_getaddresses *saddr;
2906 :
2907 0 : SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2908 0 : SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2909 :
2910 0 : if (stcb) {
2911 0 : left = (*optsize) - sizeof(struct sctp_getaddresses);
2912 0 : *optsize = sizeof(struct sctp_getaddresses);
2913 0 : sas = (struct sockaddr_storage *)&saddr->addr[0];
2914 :
2915 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2916 0 : switch (net->ro._l_addr.sa.sa_family) {
2917 : #ifdef INET
2918 : case AF_INET:
2919 : #ifdef INET6
2920 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2921 : cpsz = sizeof(struct sockaddr_in6);
2922 : } else {
2923 : cpsz = sizeof(struct sockaddr_in);
2924 : }
2925 : #else
2926 : cpsz = sizeof(struct sockaddr_in);
2927 : #endif
2928 : break;
2929 : #endif
2930 : #ifdef INET6
2931 : case AF_INET6:
2932 : cpsz = sizeof(struct sockaddr_in6);
2933 : break;
2934 : #endif
2935 : #if defined(__Userspace__)
2936 : case AF_CONN:
2937 0 : cpsz = sizeof(struct sockaddr_conn);
2938 0 : break;
2939 : #endif
2940 : default:
2941 0 : cpsz = 0;
2942 0 : break;
2943 : }
2944 0 : if (cpsz == 0) {
2945 0 : break;
2946 : }
2947 0 : if (left < cpsz) {
2948 : /* not enough room. */
2949 0 : break;
2950 : }
2951 : #if defined(INET) && defined(INET6)
2952 : if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
2953 : (net->ro._l_addr.sa.sa_family == AF_INET)) {
2954 : /* Must map the address */
2955 : in6_sin_2_v4mapsin6(&net->ro._l_addr.sin,
2956 : (struct sockaddr_in6 *)sas);
2957 : } else {
2958 : memcpy(sas, &net->ro._l_addr, cpsz);
2959 : }
2960 : #else
2961 0 : memcpy(sas, &net->ro._l_addr, cpsz);
2962 : #endif
2963 0 : ((struct sockaddr_in *)sas)->sin_port = stcb->rport;
2964 :
2965 0 : sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
2966 0 : left -= cpsz;
2967 0 : *optsize += cpsz;
2968 : }
2969 0 : SCTP_TCB_UNLOCK(stcb);
2970 : } else {
2971 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2972 0 : error = ENOENT;
2973 : }
2974 0 : break;
2975 : }
2976 : case SCTP_GET_LOCAL_ADDRESSES:
2977 : {
2978 : size_t limit, actual;
2979 : struct sockaddr_storage *sas;
2980 : struct sctp_getaddresses *saddr;
2981 :
2982 0 : SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2983 0 : SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2984 :
2985 0 : sas = (struct sockaddr_storage *)&saddr->addr[0];
2986 0 : limit = *optsize - sizeof(sctp_assoc_t);
2987 0 : actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
2988 0 : if (stcb) {
2989 0 : SCTP_TCB_UNLOCK(stcb);
2990 : }
2991 0 : *optsize = sizeof(struct sockaddr_storage) + actual;
2992 0 : break;
2993 : }
2994 : case SCTP_PEER_ADDR_PARAMS:
2995 : {
2996 : struct sctp_paddrparams *paddrp;
2997 : struct sctp_nets *net;
2998 : struct sockaddr *addr;
2999 : #if defined(INET) && defined(INET6)
3000 : struct sockaddr_in sin_store;
3001 : #endif
3002 :
3003 0 : SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
3004 0 : SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
3005 :
3006 : #if defined(INET) && defined(INET6)
3007 : if (paddrp->spp_address.ss_family == AF_INET6) {
3008 : struct sockaddr_in6 *sin6;
3009 :
3010 : sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
3011 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3012 : in6_sin6_2_sin(&sin_store, sin6);
3013 : addr = (struct sockaddr *)&sin_store;
3014 : } else {
3015 : addr = (struct sockaddr *)&paddrp->spp_address;
3016 : }
3017 : } else {
3018 : addr = (struct sockaddr *)&paddrp->spp_address;
3019 : }
3020 : #else
3021 0 : addr = (struct sockaddr *)&paddrp->spp_address;
3022 : #endif
3023 0 : if (stcb != NULL) {
3024 0 : net = sctp_findnet(stcb, addr);
3025 : } else {
3026 : /* We increment here since sctp_findassociation_ep_addr() wil
3027 : * do a decrement if it finds the stcb as long as the locked
3028 : * tcb (last argument) is NOT a TCB.. aka NULL.
3029 : */
3030 0 : net = NULL;
3031 0 : SCTP_INP_INCR_REF(inp);
3032 0 : stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
3033 0 : if (stcb == NULL) {
3034 0 : SCTP_INP_DECR_REF(inp);
3035 : }
3036 : }
3037 0 : if ((stcb != NULL) && (net == NULL)) {
3038 : #ifdef INET
3039 : if (addr->sa_family == AF_INET) {
3040 : struct sockaddr_in *sin;
3041 :
3042 : sin = (struct sockaddr_in *)addr;
3043 : if (sin->sin_addr.s_addr != INADDR_ANY) {
3044 : error = EINVAL;
3045 : SCTP_TCB_UNLOCK(stcb);
3046 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3047 : break;
3048 : }
3049 : } else
3050 : #endif
3051 : #ifdef INET6
3052 : if (addr->sa_family == AF_INET6) {
3053 : struct sockaddr_in6 *sin6;
3054 :
3055 : sin6 = (struct sockaddr_in6 *)addr;
3056 : if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3057 : error = EINVAL;
3058 : SCTP_TCB_UNLOCK(stcb);
3059 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3060 : break;
3061 : }
3062 : } else
3063 : #endif
3064 : #if defined(__Userspace__)
3065 0 : if (addr->sa_family == AF_CONN) {
3066 : struct sockaddr_conn *sconn;
3067 :
3068 0 : sconn = (struct sockaddr_conn *)addr;
3069 0 : if (sconn->sconn_addr != NULL) {
3070 0 : error = EINVAL;
3071 0 : SCTP_TCB_UNLOCK(stcb);
3072 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3073 0 : break;
3074 : }
3075 : } else
3076 : #endif
3077 : {
3078 0 : error = EAFNOSUPPORT;
3079 0 : SCTP_TCB_UNLOCK(stcb);
3080 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3081 0 : break;
3082 : }
3083 : }
3084 :
3085 0 : if (stcb != NULL) {
3086 : /* Applies to the specific association */
3087 0 : paddrp->spp_flags = 0;
3088 0 : if (net != NULL) {
3089 : int ovh;
3090 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3091 0 : ovh = SCTP_MED_OVERHEAD;
3092 : } else {
3093 0 : ovh = SCTP_MED_V4_OVERHEAD;
3094 : }
3095 :
3096 0 : paddrp->spp_hbinterval = net->heart_beat_delay;
3097 0 : paddrp->spp_pathmaxrxt = net->failure_threshold;
3098 0 : paddrp->spp_pathmtu = net->mtu - ovh;
3099 : /* get flags for HB */
3100 0 : if (net->dest_state & SCTP_ADDR_NOHB) {
3101 0 : paddrp->spp_flags |= SPP_HB_DISABLE;
3102 : } else {
3103 0 : paddrp->spp_flags |= SPP_HB_ENABLE;
3104 : }
3105 : /* get flags for PMTU */
3106 0 : if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
3107 0 : paddrp->spp_flags |= SPP_PMTUD_ENABLE;
3108 : } else {
3109 0 : paddrp->spp_flags |= SPP_PMTUD_DISABLE;
3110 : }
3111 0 : if (net->dscp & 0x01) {
3112 0 : paddrp->spp_dscp = net->dscp & 0xfc;
3113 0 : paddrp->spp_flags |= SPP_DSCP;
3114 : }
3115 : #ifdef INET6
3116 : if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
3117 : (net->flowlabel & 0x80000000)) {
3118 : paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
3119 : paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
3120 : }
3121 : #endif
3122 : } else {
3123 : /*
3124 : * No destination so return default
3125 : * value
3126 : */
3127 0 : paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
3128 0 : paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
3129 0 : if (stcb->asoc.default_dscp & 0x01) {
3130 0 : paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
3131 0 : paddrp->spp_flags |= SPP_DSCP;
3132 : }
3133 : #ifdef INET6
3134 : if (stcb->asoc.default_flowlabel & 0x80000000) {
3135 : paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
3136 : paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
3137 : }
3138 : #endif
3139 : /* default settings should be these */
3140 0 : if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
3141 0 : paddrp->spp_flags |= SPP_HB_DISABLE;
3142 : } else {
3143 0 : paddrp->spp_flags |= SPP_HB_ENABLE;
3144 : }
3145 0 : if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
3146 0 : paddrp->spp_flags |= SPP_PMTUD_DISABLE;
3147 : } else {
3148 0 : paddrp->spp_flags |= SPP_PMTUD_ENABLE;
3149 : }
3150 0 : paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
3151 : }
3152 0 : paddrp->spp_assoc_id = sctp_get_associd(stcb);
3153 0 : SCTP_TCB_UNLOCK(stcb);
3154 : } else {
3155 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3156 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3157 0 : (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
3158 : /* Use endpoint defaults */
3159 0 : SCTP_INP_RLOCK(inp);
3160 0 : paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
3161 0 : paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
3162 0 : paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
3163 : /* get inp's default */
3164 0 : if (inp->sctp_ep.default_dscp & 0x01) {
3165 0 : paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc;
3166 0 : paddrp->spp_flags |= SPP_DSCP;
3167 : }
3168 : #ifdef INET6
3169 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
3170 : (inp->sctp_ep.default_flowlabel & 0x80000000)) {
3171 : paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
3172 : paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
3173 : }
3174 : #endif
3175 : /* can't return this */
3176 0 : paddrp->spp_pathmtu = 0;
3177 :
3178 0 : if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
3179 0 : paddrp->spp_flags |= SPP_HB_ENABLE;
3180 : } else {
3181 0 : paddrp->spp_flags |= SPP_HB_DISABLE;
3182 : }
3183 0 : if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
3184 0 : paddrp->spp_flags |= SPP_PMTUD_ENABLE;
3185 : } else {
3186 0 : paddrp->spp_flags |= SPP_PMTUD_DISABLE;
3187 : }
3188 0 : SCTP_INP_RUNLOCK(inp);
3189 : } else {
3190 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3191 0 : error = EINVAL;
3192 : }
3193 : }
3194 0 : if (error == 0) {
3195 0 : *optsize = sizeof(struct sctp_paddrparams);
3196 : }
3197 0 : break;
3198 : }
3199 : case SCTP_GET_PEER_ADDR_INFO:
3200 : {
3201 : struct sctp_paddrinfo *paddri;
3202 : struct sctp_nets *net;
3203 : struct sockaddr *addr;
3204 : #if defined(INET) && defined(INET6)
3205 : struct sockaddr_in sin_store;
3206 : #endif
3207 :
3208 0 : SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
3209 0 : SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
3210 :
3211 : #if defined(INET) && defined(INET6)
3212 : if (paddri->spinfo_address.ss_family == AF_INET6) {
3213 : struct sockaddr_in6 *sin6;
3214 :
3215 : sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address;
3216 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3217 : in6_sin6_2_sin(&sin_store, sin6);
3218 : addr = (struct sockaddr *)&sin_store;
3219 : } else {
3220 : addr = (struct sockaddr *)&paddri->spinfo_address;
3221 : }
3222 : } else {
3223 : addr = (struct sockaddr *)&paddri->spinfo_address;
3224 : }
3225 : #else
3226 0 : addr = (struct sockaddr *)&paddri->spinfo_address;
3227 : #endif
3228 0 : if (stcb != NULL) {
3229 0 : net = sctp_findnet(stcb, addr);
3230 : } else {
3231 : /* We increment here since sctp_findassociation_ep_addr() wil
3232 : * do a decrement if it finds the stcb as long as the locked
3233 : * tcb (last argument) is NOT a TCB.. aka NULL.
3234 : */
3235 0 : net = NULL;
3236 0 : SCTP_INP_INCR_REF(inp);
3237 0 : stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
3238 0 : if (stcb == NULL) {
3239 0 : SCTP_INP_DECR_REF(inp);
3240 : }
3241 : }
3242 :
3243 0 : if ((stcb != NULL) && (net != NULL)) {
3244 0 : if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
3245 : /* It's unconfirmed */
3246 0 : paddri->spinfo_state = SCTP_UNCONFIRMED;
3247 0 : } else if (net->dest_state & SCTP_ADDR_REACHABLE) {
3248 : /* It's active */
3249 0 : paddri->spinfo_state = SCTP_ACTIVE;
3250 : } else {
3251 : /* It's inactive */
3252 0 : paddri->spinfo_state = SCTP_INACTIVE;
3253 : }
3254 0 : paddri->spinfo_cwnd = net->cwnd;
3255 0 : paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
3256 0 : paddri->spinfo_rto = net->RTO;
3257 0 : paddri->spinfo_assoc_id = sctp_get_associd(stcb);
3258 0 : paddri->spinfo_mtu = net->mtu;
3259 0 : SCTP_TCB_UNLOCK(stcb);
3260 0 : *optsize = sizeof(struct sctp_paddrinfo);
3261 : } else {
3262 0 : if (stcb != NULL) {
3263 0 : SCTP_TCB_UNLOCK(stcb);
3264 : }
3265 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
3266 0 : error = ENOENT;
3267 : }
3268 0 : break;
3269 : }
3270 : case SCTP_PCB_STATUS:
3271 : {
3272 : struct sctp_pcbinfo *spcb;
3273 :
3274 0 : SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
3275 0 : sctp_fill_pcbinfo(spcb);
3276 0 : *optsize = sizeof(struct sctp_pcbinfo);
3277 0 : break;
3278 : }
3279 : case SCTP_STATUS:
3280 : {
3281 : struct sctp_nets *net;
3282 : struct sctp_status *sstat;
3283 :
3284 0 : SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
3285 0 : SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
3286 :
3287 0 : if (stcb == NULL) {
3288 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3289 0 : error = EINVAL;
3290 0 : break;
3291 : }
3292 : /*
3293 : * I think passing the state is fine since
3294 : * sctp_constants.h will be available to the user
3295 : * land.
3296 : */
3297 0 : sstat->sstat_state = stcb->asoc.state;
3298 0 : sstat->sstat_assoc_id = sctp_get_associd(stcb);
3299 0 : sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
3300 0 : sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
3301 : /*
3302 : * We can't include chunks that have been passed to
3303 : * the socket layer. Only things in queue.
3304 : */
3305 0 : sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
3306 0 : stcb->asoc.cnt_on_all_streams);
3307 :
3308 :
3309 0 : sstat->sstat_instrms = stcb->asoc.streamincnt;
3310 0 : sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
3311 0 : sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
3312 : #ifdef HAVE_SA_LEN
3313 : memcpy(&sstat->sstat_primary.spinfo_address,
3314 : &stcb->asoc.primary_destination->ro._l_addr,
3315 : ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
3316 : #else
3317 0 : if (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET) {
3318 0 : memcpy(&sstat->sstat_primary.spinfo_address,
3319 0 : &stcb->asoc.primary_destination->ro._l_addr,
3320 : sizeof(struct sockaddr_in));
3321 : } else {
3322 0 : memcpy(&sstat->sstat_primary.spinfo_address,
3323 0 : &stcb->asoc.primary_destination->ro._l_addr,
3324 : sizeof(struct sockaddr_in6));
3325 : }
3326 : #endif
3327 0 : net = stcb->asoc.primary_destination;
3328 0 : ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
3329 : /*
3330 : * Again the user can get info from sctp_constants.h
3331 : * for what the state of the network is.
3332 : */
3333 0 : if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
3334 : /* It's unconfirmed */
3335 0 : sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
3336 0 : } else if (net->dest_state & SCTP_ADDR_REACHABLE) {
3337 : /* It's active */
3338 0 : sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
3339 : } else {
3340 : /* It's inactive */
3341 0 : sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
3342 : }
3343 0 : sstat->sstat_primary.spinfo_cwnd = net->cwnd;
3344 0 : sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
3345 0 : sstat->sstat_primary.spinfo_rto = net->RTO;
3346 0 : sstat->sstat_primary.spinfo_mtu = net->mtu;
3347 0 : sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
3348 0 : SCTP_TCB_UNLOCK(stcb);
3349 0 : *optsize = sizeof(struct sctp_status);
3350 0 : break;
3351 : }
3352 : case SCTP_RTOINFO:
3353 : {
3354 : struct sctp_rtoinfo *srto;
3355 :
3356 0 : SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
3357 0 : SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
3358 :
3359 0 : if (stcb) {
3360 0 : srto->srto_initial = stcb->asoc.initial_rto;
3361 0 : srto->srto_max = stcb->asoc.maxrto;
3362 0 : srto->srto_min = stcb->asoc.minrto;
3363 0 : SCTP_TCB_UNLOCK(stcb);
3364 : } else {
3365 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3366 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3367 0 : (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
3368 0 : SCTP_INP_RLOCK(inp);
3369 0 : srto->srto_initial = inp->sctp_ep.initial_rto;
3370 0 : srto->srto_max = inp->sctp_ep.sctp_maxrto;
3371 0 : srto->srto_min = inp->sctp_ep.sctp_minrto;
3372 0 : SCTP_INP_RUNLOCK(inp);
3373 : } else {
3374 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3375 0 : error = EINVAL;
3376 : }
3377 : }
3378 0 : if (error == 0) {
3379 0 : *optsize = sizeof(struct sctp_rtoinfo);
3380 : }
3381 0 : break;
3382 : }
3383 : case SCTP_TIMEOUTS:
3384 : {
3385 : struct sctp_timeouts *stimo;
3386 :
3387 0 : SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
3388 0 : SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
3389 :
3390 0 : if (stcb) {
3391 0 : stimo->stimo_init= stcb->asoc.timoinit;
3392 0 : stimo->stimo_data= stcb->asoc.timodata;
3393 0 : stimo->stimo_sack= stcb->asoc.timosack;
3394 0 : stimo->stimo_shutdown= stcb->asoc.timoshutdown;
3395 0 : stimo->stimo_heartbeat= stcb->asoc.timoheartbeat;
3396 0 : stimo->stimo_cookie= stcb->asoc.timocookie;
3397 0 : stimo->stimo_shutdownack= stcb->asoc.timoshutdownack;
3398 0 : SCTP_TCB_UNLOCK(stcb);
3399 0 : *optsize = sizeof(struct sctp_timeouts);
3400 : } else {
3401 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3402 0 : error = EINVAL;
3403 : }
3404 0 : break;
3405 : }
3406 : case SCTP_ASSOCINFO:
3407 : {
3408 : struct sctp_assocparams *sasoc;
3409 :
3410 0 : SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
3411 0 : SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
3412 :
3413 0 : if (stcb) {
3414 0 : sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
3415 0 : sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
3416 0 : sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
3417 0 : sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
3418 0 : sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
3419 0 : SCTP_TCB_UNLOCK(stcb);
3420 : } else {
3421 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3422 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3423 0 : (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
3424 0 : SCTP_INP_RLOCK(inp);
3425 0 : sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
3426 0 : sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
3427 0 : sasoc->sasoc_number_peer_destinations = 0;
3428 0 : sasoc->sasoc_peer_rwnd = 0;
3429 0 : sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
3430 0 : SCTP_INP_RUNLOCK(inp);
3431 : } else {
3432 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3433 0 : error = EINVAL;
3434 : }
3435 : }
3436 0 : if (error == 0) {
3437 0 : *optsize = sizeof(struct sctp_assocparams);
3438 : }
3439 0 : break;
3440 : }
3441 : case SCTP_DEFAULT_SEND_PARAM:
3442 : {
3443 : struct sctp_sndrcvinfo *s_info;
3444 :
3445 0 : SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
3446 0 : SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
3447 :
3448 0 : if (stcb) {
3449 0 : memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
3450 0 : SCTP_TCB_UNLOCK(stcb);
3451 : } else {
3452 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3453 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3454 0 : (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) {
3455 0 : SCTP_INP_RLOCK(inp);
3456 0 : memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
3457 0 : SCTP_INP_RUNLOCK(inp);
3458 : } else {
3459 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3460 0 : error = EINVAL;
3461 : }
3462 : }
3463 0 : if (error == 0) {
3464 0 : *optsize = sizeof(struct sctp_sndrcvinfo);
3465 : }
3466 0 : break;
3467 : }
3468 : case SCTP_INITMSG:
3469 : {
3470 : struct sctp_initmsg *sinit;
3471 :
3472 0 : SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
3473 0 : SCTP_INP_RLOCK(inp);
3474 0 : sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
3475 0 : sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
3476 0 : sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
3477 0 : sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
3478 0 : SCTP_INP_RUNLOCK(inp);
3479 0 : *optsize = sizeof(struct sctp_initmsg);
3480 0 : break;
3481 : }
3482 : case SCTP_PRIMARY_ADDR:
3483 : /* we allow a "get" operation on this */
3484 : {
3485 : struct sctp_setprim *ssp;
3486 :
3487 0 : SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
3488 0 : SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
3489 :
3490 0 : if (stcb) {
3491 : union sctp_sockstore *addr;
3492 :
3493 0 : addr = &stcb->asoc.primary_destination->ro._l_addr;
3494 0 : switch (addr->sa.sa_family) {
3495 : #ifdef INET
3496 : case AF_INET:
3497 : #ifdef INET6
3498 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
3499 : in6_sin_2_v4mapsin6(&addr->sin,
3500 : (struct sockaddr_in6 *)&ssp->ssp_addr);
3501 : } else {
3502 : memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
3503 : }
3504 : #else
3505 : memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
3506 : #endif
3507 : break;
3508 : #endif
3509 : #ifdef INET6
3510 : case AF_INET6:
3511 : memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6));
3512 : break;
3513 : #endif
3514 : #if defined(__Userspace__)
3515 : case AF_CONN:
3516 0 : memcpy(&ssp->ssp_addr, &addr->sconn, sizeof(struct sockaddr_conn));
3517 0 : break;
3518 : #endif
3519 : default:
3520 0 : break;
3521 : }
3522 0 : SCTP_TCB_UNLOCK(stcb);
3523 0 : *optsize = sizeof(struct sctp_setprim);
3524 : } else {
3525 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3526 0 : error = EINVAL;
3527 : }
3528 0 : break;
3529 : }
3530 : case SCTP_HMAC_IDENT:
3531 : {
3532 : struct sctp_hmacalgo *shmac;
3533 : sctp_hmaclist_t *hmaclist;
3534 : uint32_t size;
3535 : int i;
3536 :
3537 0 : SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
3538 :
3539 0 : SCTP_INP_RLOCK(inp);
3540 0 : hmaclist = inp->sctp_ep.local_hmacs;
3541 0 : if (hmaclist == NULL) {
3542 : /* no HMACs to return */
3543 0 : *optsize = sizeof(*shmac);
3544 0 : SCTP_INP_RUNLOCK(inp);
3545 0 : break;
3546 : }
3547 : /* is there room for all of the hmac ids? */
3548 0 : size = sizeof(*shmac) + (hmaclist->num_algo *
3549 : sizeof(shmac->shmac_idents[0]));
3550 0 : if ((size_t)(*optsize) < size) {
3551 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3552 0 : error = EINVAL;
3553 0 : SCTP_INP_RUNLOCK(inp);
3554 0 : break;
3555 : }
3556 : /* copy in the list */
3557 0 : shmac->shmac_number_of_idents = hmaclist->num_algo;
3558 0 : for (i = 0; i < hmaclist->num_algo; i++) {
3559 0 : shmac->shmac_idents[i] = hmaclist->hmac[i];
3560 : }
3561 0 : SCTP_INP_RUNLOCK(inp);
3562 0 : *optsize = size;
3563 0 : break;
3564 : }
3565 : case SCTP_AUTH_ACTIVE_KEY:
3566 : {
3567 : struct sctp_authkeyid *scact;
3568 :
3569 0 : SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
3570 0 : SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
3571 :
3572 0 : if (stcb) {
3573 : /* get the active key on the assoc */
3574 0 : scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
3575 0 : SCTP_TCB_UNLOCK(stcb);
3576 : } else {
3577 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3578 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3579 0 : (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) {
3580 : /* get the endpoint active key */
3581 0 : SCTP_INP_RLOCK(inp);
3582 0 : scact->scact_keynumber = inp->sctp_ep.default_keyid;
3583 0 : SCTP_INP_RUNLOCK(inp);
3584 : } else {
3585 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3586 0 : error = EINVAL;
3587 : }
3588 : }
3589 0 : if (error == 0) {
3590 0 : *optsize = sizeof(struct sctp_authkeyid);
3591 : }
3592 0 : break;
3593 : }
3594 : case SCTP_LOCAL_AUTH_CHUNKS:
3595 : {
3596 : struct sctp_authchunks *sac;
3597 0 : sctp_auth_chklist_t *chklist = NULL;
3598 0 : size_t size = 0;
3599 :
3600 0 : SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
3601 0 : SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
3602 :
3603 0 : if (stcb) {
3604 : /* get off the assoc */
3605 0 : chklist = stcb->asoc.local_auth_chunks;
3606 : /* is there enough space? */
3607 0 : size = sctp_auth_get_chklist_size(chklist);
3608 0 : if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
3609 0 : error = EINVAL;
3610 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3611 : } else {
3612 : /* copy in the chunks */
3613 0 : (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
3614 0 : sac->gauth_number_of_chunks = (uint32_t)size;
3615 0 : *optsize = sizeof(struct sctp_authchunks) + size;
3616 : }
3617 0 : SCTP_TCB_UNLOCK(stcb);
3618 : } else {
3619 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3620 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3621 0 : (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) {
3622 : /* get off the endpoint */
3623 0 : SCTP_INP_RLOCK(inp);
3624 0 : chklist = inp->sctp_ep.local_auth_chunks;
3625 : /* is there enough space? */
3626 0 : size = sctp_auth_get_chklist_size(chklist);
3627 0 : if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
3628 0 : error = EINVAL;
3629 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3630 : } else {
3631 : /* copy in the chunks */
3632 0 : (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
3633 0 : sac->gauth_number_of_chunks = (uint32_t)size;
3634 0 : *optsize = sizeof(struct sctp_authchunks) + size;
3635 : }
3636 0 : SCTP_INP_RUNLOCK(inp);
3637 : } else {
3638 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3639 0 : error = EINVAL;
3640 : }
3641 : }
3642 0 : break;
3643 : }
3644 : case SCTP_PEER_AUTH_CHUNKS:
3645 : {
3646 : struct sctp_authchunks *sac;
3647 0 : sctp_auth_chklist_t *chklist = NULL;
3648 0 : size_t size = 0;
3649 :
3650 0 : SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
3651 0 : SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
3652 :
3653 0 : if (stcb) {
3654 : /* get off the assoc */
3655 0 : chklist = stcb->asoc.peer_auth_chunks;
3656 : /* is there enough space? */
3657 0 : size = sctp_auth_get_chklist_size(chklist);
3658 0 : if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
3659 0 : error = EINVAL;
3660 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3661 : } else {
3662 : /* copy in the chunks */
3663 0 : (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
3664 0 : sac->gauth_number_of_chunks = (uint32_t)size;
3665 0 : *optsize = sizeof(struct sctp_authchunks) + size;
3666 : }
3667 0 : SCTP_TCB_UNLOCK(stcb);
3668 : } else {
3669 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
3670 0 : error = ENOENT;
3671 : }
3672 0 : break;
3673 : }
3674 : #if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
3675 : case SCTP_PEELOFF:
3676 : {
3677 : struct sctp_peeloff_opt *peeloff;
3678 :
3679 : SCTP_CHECK_AND_CAST(peeloff, optval, struct sctp_peeloff_opt, *optsize);
3680 : /* do the peeloff */
3681 : error = sctp_peeloff_option(p, peeloff);
3682 : if (error == 0) {
3683 : *optsize = sizeof(struct sctp_peeloff_opt);
3684 : }
3685 : }
3686 : break;
3687 : #endif /* HAVE_SCTP_PEELOFF_SOCKOPT */
3688 : case SCTP_EVENT:
3689 : {
3690 : struct sctp_event *event;
3691 : uint32_t event_type;
3692 :
3693 0 : SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
3694 0 : SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
3695 :
3696 0 : switch (event->se_type) {
3697 : case SCTP_ASSOC_CHANGE:
3698 0 : event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
3699 0 : break;
3700 : case SCTP_PEER_ADDR_CHANGE:
3701 0 : event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
3702 0 : break;
3703 : case SCTP_REMOTE_ERROR:
3704 0 : event_type = SCTP_PCB_FLAGS_RECVPEERERR;
3705 0 : break;
3706 : case SCTP_SEND_FAILED:
3707 0 : event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
3708 0 : break;
3709 : case SCTP_SHUTDOWN_EVENT:
3710 0 : event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
3711 0 : break;
3712 : case SCTP_ADAPTATION_INDICATION:
3713 0 : event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
3714 0 : break;
3715 : case SCTP_PARTIAL_DELIVERY_EVENT:
3716 0 : event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
3717 0 : break;
3718 : case SCTP_AUTHENTICATION_EVENT:
3719 0 : event_type = SCTP_PCB_FLAGS_AUTHEVNT;
3720 0 : break;
3721 : case SCTP_STREAM_RESET_EVENT:
3722 0 : event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
3723 0 : break;
3724 : case SCTP_SENDER_DRY_EVENT:
3725 0 : event_type = SCTP_PCB_FLAGS_DRYEVNT;
3726 0 : break;
3727 : case SCTP_NOTIFICATIONS_STOPPED_EVENT:
3728 0 : event_type = 0;
3729 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
3730 0 : error = ENOTSUP;
3731 0 : break;
3732 : case SCTP_ASSOC_RESET_EVENT:
3733 0 : event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
3734 0 : break;
3735 : case SCTP_STREAM_CHANGE_EVENT:
3736 0 : event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
3737 0 : break;
3738 : case SCTP_SEND_FAILED_EVENT:
3739 0 : event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
3740 0 : break;
3741 : default:
3742 0 : event_type = 0;
3743 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3744 0 : error = EINVAL;
3745 0 : break;
3746 : }
3747 0 : if (event_type > 0) {
3748 0 : if (stcb) {
3749 0 : event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
3750 0 : SCTP_TCB_UNLOCK(stcb);
3751 : } else {
3752 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3753 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3754 0 : (event->se_assoc_id == SCTP_FUTURE_ASSOC)) {
3755 0 : SCTP_INP_RLOCK(inp);
3756 0 : event->se_on = sctp_is_feature_on(inp, event_type);
3757 0 : SCTP_INP_RUNLOCK(inp);
3758 : } else {
3759 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3760 0 : error = EINVAL;
3761 : }
3762 : }
3763 : }
3764 0 : if (error == 0) {
3765 0 : *optsize = sizeof(struct sctp_event);
3766 : }
3767 0 : break;
3768 : }
3769 : case SCTP_RECVRCVINFO:
3770 : {
3771 : int onoff;
3772 :
3773 0 : if (*optsize < sizeof(int)) {
3774 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3775 0 : error = EINVAL;
3776 : } else {
3777 0 : SCTP_INP_RLOCK(inp);
3778 0 : onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
3779 0 : SCTP_INP_RUNLOCK(inp);
3780 : }
3781 0 : if (error == 0) {
3782 : /* return the option value */
3783 0 : *(int *)optval = onoff;
3784 0 : *optsize = sizeof(int);
3785 : }
3786 0 : break;
3787 : }
3788 : case SCTP_RECVNXTINFO:
3789 : {
3790 : int onoff;
3791 :
3792 0 : if (*optsize < sizeof(int)) {
3793 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3794 0 : error = EINVAL;
3795 : } else {
3796 0 : SCTP_INP_RLOCK(inp);
3797 0 : onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
3798 0 : SCTP_INP_RUNLOCK(inp);
3799 : }
3800 0 : if (error == 0) {
3801 : /* return the option value */
3802 0 : *(int *)optval = onoff;
3803 0 : *optsize = sizeof(int);
3804 : }
3805 0 : break;
3806 : }
3807 : case SCTP_DEFAULT_SNDINFO:
3808 : {
3809 : struct sctp_sndinfo *info;
3810 :
3811 0 : SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
3812 0 : SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
3813 :
3814 0 : if (stcb) {
3815 0 : info->snd_sid = stcb->asoc.def_send.sinfo_stream;
3816 0 : info->snd_flags = stcb->asoc.def_send.sinfo_flags;
3817 0 : info->snd_flags &= 0xfff0;
3818 0 : info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
3819 0 : info->snd_context = stcb->asoc.def_send.sinfo_context;
3820 0 : SCTP_TCB_UNLOCK(stcb);
3821 : } else {
3822 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3823 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3824 0 : (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) {
3825 0 : SCTP_INP_RLOCK(inp);
3826 0 : info->snd_sid = inp->def_send.sinfo_stream;
3827 0 : info->snd_flags = inp->def_send.sinfo_flags;
3828 0 : info->snd_flags &= 0xfff0;
3829 0 : info->snd_ppid = inp->def_send.sinfo_ppid;
3830 0 : info->snd_context = inp->def_send.sinfo_context;
3831 0 : SCTP_INP_RUNLOCK(inp);
3832 : } else {
3833 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3834 0 : error = EINVAL;
3835 : }
3836 : }
3837 0 : if (error == 0) {
3838 0 : *optsize = sizeof(struct sctp_sndinfo);
3839 : }
3840 0 : break;
3841 : }
3842 : case SCTP_DEFAULT_PRINFO:
3843 : {
3844 : struct sctp_default_prinfo *info;
3845 :
3846 0 : SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize);
3847 0 : SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
3848 :
3849 0 : if (stcb) {
3850 0 : info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
3851 0 : info->pr_value = stcb->asoc.def_send.sinfo_timetolive;
3852 0 : SCTP_TCB_UNLOCK(stcb);
3853 : } else {
3854 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3855 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3856 0 : (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) {
3857 0 : SCTP_INP_RLOCK(inp);
3858 0 : info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
3859 0 : info->pr_value = inp->def_send.sinfo_timetolive;
3860 0 : SCTP_INP_RUNLOCK(inp);
3861 : } else {
3862 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3863 0 : error = EINVAL;
3864 : }
3865 : }
3866 0 : if (error == 0) {
3867 0 : *optsize = sizeof(struct sctp_default_prinfo);
3868 : }
3869 0 : break;
3870 : }
3871 : case SCTP_PEER_ADDR_THLDS:
3872 : {
3873 : struct sctp_paddrthlds *thlds;
3874 : struct sctp_nets *net;
3875 : struct sockaddr *addr;
3876 : #if defined(INET) && defined(INET6)
3877 : struct sockaddr_in sin_store;
3878 : #endif
3879 :
3880 0 : SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
3881 0 : SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
3882 :
3883 : #if defined(INET) && defined(INET6)
3884 : if (thlds->spt_address.ss_family == AF_INET6) {
3885 : struct sockaddr_in6 *sin6;
3886 :
3887 : sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
3888 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3889 : in6_sin6_2_sin(&sin_store, sin6);
3890 : addr = (struct sockaddr *)&sin_store;
3891 : } else {
3892 : addr = (struct sockaddr *)&thlds->spt_address;
3893 : }
3894 : } else {
3895 : addr = (struct sockaddr *)&thlds->spt_address;
3896 : }
3897 : #else
3898 0 : addr = (struct sockaddr *)&thlds->spt_address;
3899 : #endif
3900 0 : if (stcb != NULL) {
3901 0 : net = sctp_findnet(stcb, addr);
3902 : } else {
3903 : /* We increment here since sctp_findassociation_ep_addr() wil
3904 : * do a decrement if it finds the stcb as long as the locked
3905 : * tcb (last argument) is NOT a TCB.. aka NULL.
3906 : */
3907 0 : net = NULL;
3908 0 : SCTP_INP_INCR_REF(inp);
3909 0 : stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
3910 0 : if (stcb == NULL) {
3911 0 : SCTP_INP_DECR_REF(inp);
3912 : }
3913 : }
3914 0 : if ((stcb != NULL) && (net == NULL)) {
3915 : #ifdef INET
3916 : if (addr->sa_family == AF_INET) {
3917 : struct sockaddr_in *sin;
3918 :
3919 : sin = (struct sockaddr_in *)addr;
3920 : if (sin->sin_addr.s_addr != INADDR_ANY) {
3921 : error = EINVAL;
3922 : SCTP_TCB_UNLOCK(stcb);
3923 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3924 : break;
3925 : }
3926 : } else
3927 : #endif
3928 : #ifdef INET6
3929 : if (addr->sa_family == AF_INET6) {
3930 : struct sockaddr_in6 *sin6;
3931 :
3932 : sin6 = (struct sockaddr_in6 *)addr;
3933 : if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3934 : error = EINVAL;
3935 : SCTP_TCB_UNLOCK(stcb);
3936 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3937 : break;
3938 : }
3939 : } else
3940 : #endif
3941 : #if defined(__Userspace__)
3942 0 : if (addr->sa_family == AF_CONN) {
3943 : struct sockaddr_conn *sconn;
3944 :
3945 0 : sconn = (struct sockaddr_conn *)addr;
3946 0 : if (sconn->sconn_addr != NULL) {
3947 0 : error = EINVAL;
3948 0 : SCTP_TCB_UNLOCK(stcb);
3949 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3950 0 : break;
3951 : }
3952 : } else
3953 : #endif
3954 : {
3955 0 : error = EAFNOSUPPORT;
3956 0 : SCTP_TCB_UNLOCK(stcb);
3957 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3958 0 : break;
3959 : }
3960 : }
3961 :
3962 0 : if (stcb != NULL) {
3963 0 : if (net != NULL) {
3964 0 : thlds->spt_pathmaxrxt = net->failure_threshold;
3965 0 : thlds->spt_pathpfthld = net->pf_threshold;
3966 : } else {
3967 0 : thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
3968 0 : thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
3969 : }
3970 0 : thlds->spt_assoc_id = sctp_get_associd(stcb);
3971 0 : SCTP_TCB_UNLOCK(stcb);
3972 : } else {
3973 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3974 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3975 0 : (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
3976 : /* Use endpoint defaults */
3977 0 : SCTP_INP_RLOCK(inp);
3978 0 : thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
3979 0 : thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
3980 0 : SCTP_INP_RUNLOCK(inp);
3981 : } else {
3982 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3983 0 : error = EINVAL;
3984 : }
3985 : }
3986 0 : if (error == 0) {
3987 0 : *optsize = sizeof(struct sctp_paddrthlds);
3988 : }
3989 0 : break;
3990 : }
3991 : case SCTP_REMOTE_UDP_ENCAPS_PORT:
3992 : {
3993 : struct sctp_udpencaps *encaps;
3994 : struct sctp_nets *net;
3995 : struct sockaddr *addr;
3996 : #if defined(INET) && defined(INET6)
3997 : struct sockaddr_in sin_store;
3998 : #endif
3999 :
4000 0 : SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
4001 0 : SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
4002 :
4003 : #if defined(INET) && defined(INET6)
4004 : if (encaps->sue_address.ss_family == AF_INET6) {
4005 : struct sockaddr_in6 *sin6;
4006 :
4007 : sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
4008 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
4009 : in6_sin6_2_sin(&sin_store, sin6);
4010 : addr = (struct sockaddr *)&sin_store;
4011 : } else {
4012 : addr = (struct sockaddr *)&encaps->sue_address;
4013 : }
4014 : } else {
4015 : addr = (struct sockaddr *)&encaps->sue_address;
4016 : }
4017 : #else
4018 0 : addr = (struct sockaddr *)&encaps->sue_address;
4019 : #endif
4020 0 : if (stcb) {
4021 0 : net = sctp_findnet(stcb, addr);
4022 : } else {
4023 : /* We increment here since sctp_findassociation_ep_addr() wil
4024 : * do a decrement if it finds the stcb as long as the locked
4025 : * tcb (last argument) is NOT a TCB.. aka NULL.
4026 : */
4027 0 : net = NULL;
4028 0 : SCTP_INP_INCR_REF(inp);
4029 0 : stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
4030 0 : if (stcb == NULL) {
4031 0 : SCTP_INP_DECR_REF(inp);
4032 : }
4033 : }
4034 0 : if ((stcb != NULL) && (net == NULL)) {
4035 : #ifdef INET
4036 : if (addr->sa_family == AF_INET) {
4037 : struct sockaddr_in *sin;
4038 :
4039 : sin = (struct sockaddr_in *)addr;
4040 : if (sin->sin_addr.s_addr != INADDR_ANY) {
4041 : error = EINVAL;
4042 : SCTP_TCB_UNLOCK(stcb);
4043 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4044 : break;
4045 : }
4046 : } else
4047 : #endif
4048 : #ifdef INET6
4049 : if (addr->sa_family == AF_INET6) {
4050 : struct sockaddr_in6 *sin6;
4051 :
4052 : sin6 = (struct sockaddr_in6 *)addr;
4053 : if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4054 : error = EINVAL;
4055 : SCTP_TCB_UNLOCK(stcb);
4056 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4057 : break;
4058 : }
4059 : } else
4060 : #endif
4061 : #if defined(__Userspace__)
4062 0 : if (addr->sa_family == AF_CONN) {
4063 : struct sockaddr_conn *sconn;
4064 :
4065 0 : sconn = (struct sockaddr_conn *)addr;
4066 0 : if (sconn->sconn_addr != NULL) {
4067 0 : error = EINVAL;
4068 0 : SCTP_TCB_UNLOCK(stcb);
4069 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4070 0 : break;
4071 : }
4072 : } else
4073 : #endif
4074 : {
4075 0 : error = EAFNOSUPPORT;
4076 0 : SCTP_TCB_UNLOCK(stcb);
4077 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4078 0 : break;
4079 : }
4080 : }
4081 :
4082 0 : if (stcb != NULL) {
4083 0 : if (net) {
4084 0 : encaps->sue_port = net->port;
4085 : } else {
4086 0 : encaps->sue_port = stcb->asoc.port;
4087 : }
4088 0 : SCTP_TCB_UNLOCK(stcb);
4089 : } else {
4090 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4091 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4092 0 : (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
4093 0 : SCTP_INP_RLOCK(inp);
4094 0 : encaps->sue_port = inp->sctp_ep.port;
4095 0 : SCTP_INP_RUNLOCK(inp);
4096 : } else {
4097 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4098 0 : error = EINVAL;
4099 : }
4100 : }
4101 0 : if (error == 0) {
4102 0 : *optsize = sizeof(struct sctp_udpencaps);
4103 : }
4104 0 : break;
4105 : }
4106 : case SCTP_ECN_SUPPORTED:
4107 : {
4108 : struct sctp_assoc_value *av;
4109 :
4110 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4111 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4112 :
4113 0 : if (stcb) {
4114 0 : av->assoc_value = stcb->asoc.ecn_supported;
4115 0 : SCTP_TCB_UNLOCK(stcb);
4116 : } else {
4117 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4118 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4119 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4120 0 : SCTP_INP_RLOCK(inp);
4121 0 : av->assoc_value = inp->ecn_supported;
4122 0 : SCTP_INP_RUNLOCK(inp);
4123 : } else {
4124 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4125 0 : error = EINVAL;
4126 : }
4127 : }
4128 0 : if (error == 0) {
4129 0 : *optsize = sizeof(struct sctp_assoc_value);
4130 : }
4131 0 : break;
4132 : }
4133 : case SCTP_PR_SUPPORTED:
4134 : {
4135 : struct sctp_assoc_value *av;
4136 :
4137 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4138 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4139 :
4140 0 : if (stcb) {
4141 0 : av->assoc_value = stcb->asoc.prsctp_supported;
4142 0 : SCTP_TCB_UNLOCK(stcb);
4143 : } else {
4144 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4145 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4146 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4147 0 : SCTP_INP_RLOCK(inp);
4148 0 : av->assoc_value = inp->prsctp_supported;
4149 0 : SCTP_INP_RUNLOCK(inp);
4150 : } else {
4151 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4152 0 : error = EINVAL;
4153 : }
4154 : }
4155 0 : if (error == 0) {
4156 0 : *optsize = sizeof(struct sctp_assoc_value);
4157 : }
4158 0 : break;
4159 : }
4160 : case SCTP_AUTH_SUPPORTED:
4161 : {
4162 : struct sctp_assoc_value *av;
4163 :
4164 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4165 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4166 :
4167 0 : if (stcb) {
4168 0 : av->assoc_value = stcb->asoc.auth_supported;
4169 0 : SCTP_TCB_UNLOCK(stcb);
4170 : } else {
4171 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4172 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4173 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4174 0 : SCTP_INP_RLOCK(inp);
4175 0 : av->assoc_value = inp->auth_supported;
4176 0 : SCTP_INP_RUNLOCK(inp);
4177 : } else {
4178 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4179 0 : error = EINVAL;
4180 : }
4181 : }
4182 0 : if (error == 0) {
4183 0 : *optsize = sizeof(struct sctp_assoc_value);
4184 : }
4185 0 : break;
4186 : }
4187 : case SCTP_ASCONF_SUPPORTED:
4188 : {
4189 : struct sctp_assoc_value *av;
4190 :
4191 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4192 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4193 :
4194 0 : if (stcb) {
4195 0 : av->assoc_value = stcb->asoc.asconf_supported;
4196 0 : SCTP_TCB_UNLOCK(stcb);
4197 : } else {
4198 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4199 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4200 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4201 0 : SCTP_INP_RLOCK(inp);
4202 0 : av->assoc_value = inp->asconf_supported;
4203 0 : SCTP_INP_RUNLOCK(inp);
4204 : } else {
4205 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4206 0 : error = EINVAL;
4207 : }
4208 : }
4209 0 : if (error == 0) {
4210 0 : *optsize = sizeof(struct sctp_assoc_value);
4211 : }
4212 0 : break;
4213 : }
4214 : case SCTP_RECONFIG_SUPPORTED:
4215 : {
4216 : struct sctp_assoc_value *av;
4217 :
4218 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4219 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4220 :
4221 0 : if (stcb) {
4222 0 : av->assoc_value = stcb->asoc.reconfig_supported;
4223 0 : SCTP_TCB_UNLOCK(stcb);
4224 : } else {
4225 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4226 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4227 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4228 0 : SCTP_INP_RLOCK(inp);
4229 0 : av->assoc_value = inp->reconfig_supported;
4230 0 : SCTP_INP_RUNLOCK(inp);
4231 : } else {
4232 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4233 0 : error = EINVAL;
4234 : }
4235 : }
4236 0 : if (error == 0) {
4237 0 : *optsize = sizeof(struct sctp_assoc_value);
4238 : }
4239 0 : break;
4240 : }
4241 : case SCTP_NRSACK_SUPPORTED:
4242 : {
4243 : struct sctp_assoc_value *av;
4244 :
4245 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4246 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4247 :
4248 0 : if (stcb) {
4249 0 : av->assoc_value = stcb->asoc.nrsack_supported;
4250 0 : SCTP_TCB_UNLOCK(stcb);
4251 : } else {
4252 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4253 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4254 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4255 0 : SCTP_INP_RLOCK(inp);
4256 0 : av->assoc_value = inp->nrsack_supported;
4257 0 : SCTP_INP_RUNLOCK(inp);
4258 : } else {
4259 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4260 0 : error = EINVAL;
4261 : }
4262 : }
4263 0 : if (error == 0) {
4264 0 : *optsize = sizeof(struct sctp_assoc_value);
4265 : }
4266 0 : break;
4267 : }
4268 : case SCTP_PKTDROP_SUPPORTED:
4269 : {
4270 : struct sctp_assoc_value *av;
4271 :
4272 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4273 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4274 :
4275 0 : if (stcb) {
4276 0 : av->assoc_value = stcb->asoc.pktdrop_supported;
4277 0 : SCTP_TCB_UNLOCK(stcb);
4278 : } else {
4279 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4280 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4281 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4282 0 : SCTP_INP_RLOCK(inp);
4283 0 : av->assoc_value = inp->pktdrop_supported;
4284 0 : SCTP_INP_RUNLOCK(inp);
4285 : } else {
4286 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4287 0 : error = EINVAL;
4288 : }
4289 : }
4290 0 : if (error == 0) {
4291 0 : *optsize = sizeof(struct sctp_assoc_value);
4292 : }
4293 0 : break;
4294 : }
4295 : case SCTP_ENABLE_STREAM_RESET:
4296 : {
4297 : struct sctp_assoc_value *av;
4298 :
4299 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4300 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4301 :
4302 0 : if (stcb) {
4303 0 : av->assoc_value = (uint32_t)stcb->asoc.local_strreset_support;
4304 0 : SCTP_TCB_UNLOCK(stcb);
4305 : } else {
4306 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4307 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4308 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4309 0 : SCTP_INP_RLOCK(inp);
4310 0 : av->assoc_value = (uint32_t)inp->local_strreset_support;
4311 0 : SCTP_INP_RUNLOCK(inp);
4312 : } else {
4313 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4314 0 : error = EINVAL;
4315 : }
4316 : }
4317 0 : if (error == 0) {
4318 0 : *optsize = sizeof(struct sctp_assoc_value);
4319 : }
4320 0 : break;
4321 : }
4322 : case SCTP_PR_STREAM_STATUS:
4323 : {
4324 : struct sctp_prstatus *sprstat;
4325 : uint16_t sid;
4326 : uint16_t policy;
4327 :
4328 0 : SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
4329 0 : SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
4330 :
4331 0 : sid = sprstat->sprstat_sid;
4332 0 : policy = sprstat->sprstat_policy;
4333 : #if defined(SCTP_DETAILED_STR_STATS)
4334 : if ((stcb != NULL) &&
4335 : (sid < stcb->asoc.streamoutcnt) &&
4336 : (policy != SCTP_PR_SCTP_NONE) &&
4337 : ((policy <= SCTP_PR_SCTP_MAX) ||
4338 : (policy == SCTP_PR_SCTP_ALL))) {
4339 : if (policy == SCTP_PR_SCTP_ALL) {
4340 : sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
4341 : sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
4342 : } else {
4343 : sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy];
4344 : sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy];
4345 : }
4346 : #else
4347 0 : if ((stcb != NULL) &&
4348 0 : (sid < stcb->asoc.streamoutcnt) &&
4349 : (policy == SCTP_PR_SCTP_ALL)) {
4350 0 : sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
4351 0 : sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
4352 : #endif
4353 0 : SCTP_TCB_UNLOCK(stcb);
4354 0 : *optsize = sizeof(struct sctp_prstatus);
4355 : } else {
4356 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4357 0 : error = EINVAL;
4358 : }
4359 0 : break;
4360 : }
4361 : case SCTP_PR_ASSOC_STATUS:
4362 : {
4363 : struct sctp_prstatus *sprstat;
4364 : uint16_t policy;
4365 :
4366 0 : SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
4367 0 : SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
4368 :
4369 0 : policy = sprstat->sprstat_policy;
4370 0 : if ((stcb != NULL) &&
4371 0 : (policy != SCTP_PR_SCTP_NONE) &&
4372 0 : ((policy <= SCTP_PR_SCTP_MAX) ||
4373 : (policy == SCTP_PR_SCTP_ALL))) {
4374 0 : if (policy == SCTP_PR_SCTP_ALL) {
4375 0 : sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0];
4376 0 : sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0];
4377 : } else {
4378 0 : sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy];
4379 0 : sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy];
4380 : }
4381 0 : SCTP_TCB_UNLOCK(stcb);
4382 0 : *optsize = sizeof(struct sctp_prstatus);
4383 : } else {
4384 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4385 0 : error = EINVAL;
4386 : }
4387 0 : break;
4388 : }
4389 : case SCTP_MAX_CWND:
4390 : {
4391 : struct sctp_assoc_value *av;
4392 :
4393 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
4394 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4395 :
4396 0 : if (stcb) {
4397 0 : av->assoc_value = stcb->asoc.max_cwnd;
4398 0 : SCTP_TCB_UNLOCK(stcb);
4399 : } else {
4400 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4401 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4402 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4403 0 : SCTP_INP_RLOCK(inp);
4404 0 : av->assoc_value = inp->max_cwnd;
4405 0 : SCTP_INP_RUNLOCK(inp);
4406 : } else {
4407 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4408 0 : error = EINVAL;
4409 : }
4410 : }
4411 0 : if (error == 0) {
4412 0 : *optsize = sizeof(struct sctp_assoc_value);
4413 : }
4414 0 : break;
4415 : }
4416 : default:
4417 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
4418 0 : error = ENOPROTOOPT;
4419 0 : break;
4420 : } /* end switch (sopt->sopt_name) */
4421 0 : if (error) {
4422 0 : *optsize = 0;
4423 : }
4424 0 : return (error);
4425 : }
4426 :
4427 : #if defined(__Panda__) || defined(__Userspace__)
4428 : int
4429 : #else
4430 : static int
4431 : #endif
4432 0 : sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
4433 : void *p)
4434 : {
4435 : int error, set_opt;
4436 : uint32_t *mopt;
4437 0 : struct sctp_tcb *stcb = NULL;
4438 0 : struct sctp_inpcb *inp = NULL;
4439 : uint32_t vrf_id;
4440 :
4441 0 : if (optval == NULL) {
4442 0 : SCTP_PRINTF("optval is NULL\n");
4443 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4444 0 : return (EINVAL);
4445 : }
4446 0 : inp = (struct sctp_inpcb *)so->so_pcb;
4447 0 : if (inp == NULL) {
4448 0 : SCTP_PRINTF("inp is NULL?\n");
4449 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4450 0 : return (EINVAL);
4451 : }
4452 0 : vrf_id = inp->def_vrf_id;
4453 :
4454 0 : error = 0;
4455 0 : switch (optname) {
4456 : case SCTP_NODELAY:
4457 : case SCTP_AUTOCLOSE:
4458 : case SCTP_AUTO_ASCONF:
4459 : case SCTP_EXPLICIT_EOR:
4460 : case SCTP_DISABLE_FRAGMENTS:
4461 : case SCTP_USE_EXT_RCVINFO:
4462 : case SCTP_I_WANT_MAPPED_V4_ADDR:
4463 : /* copy in the option value */
4464 0 : SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
4465 0 : set_opt = 0;
4466 0 : if (error)
4467 0 : break;
4468 0 : switch (optname) {
4469 : case SCTP_DISABLE_FRAGMENTS:
4470 0 : set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
4471 0 : break;
4472 : case SCTP_AUTO_ASCONF:
4473 : /*
4474 : * NOTE: we don't really support this flag
4475 : */
4476 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
4477 : /* only valid for bound all sockets */
4478 0 : if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
4479 0 : (*mopt != 0)) {
4480 : /* forbidden by admin */
4481 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
4482 0 : return (EPERM);
4483 : }
4484 0 : set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
4485 : } else {
4486 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4487 0 : return (EINVAL);
4488 : }
4489 0 : break;
4490 : case SCTP_EXPLICIT_EOR:
4491 0 : set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
4492 0 : break;
4493 : case SCTP_USE_EXT_RCVINFO:
4494 0 : set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
4495 0 : break;
4496 : case SCTP_I_WANT_MAPPED_V4_ADDR:
4497 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
4498 0 : set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
4499 : } else {
4500 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4501 0 : return (EINVAL);
4502 : }
4503 0 : break;
4504 : case SCTP_NODELAY:
4505 0 : set_opt = SCTP_PCB_FLAGS_NODELAY;
4506 0 : break;
4507 : case SCTP_AUTOCLOSE:
4508 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4509 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
4510 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4511 0 : return (EINVAL);
4512 : }
4513 0 : set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
4514 : /*
4515 : * The value is in ticks. Note this does not effect
4516 : * old associations, only new ones.
4517 : */
4518 0 : inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
4519 0 : break;
4520 : }
4521 0 : SCTP_INP_WLOCK(inp);
4522 0 : if (*mopt != 0) {
4523 0 : sctp_feature_on(inp, set_opt);
4524 : } else {
4525 0 : sctp_feature_off(inp, set_opt);
4526 : }
4527 0 : SCTP_INP_WUNLOCK(inp);
4528 0 : break;
4529 : case SCTP_REUSE_PORT:
4530 : {
4531 0 : SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
4532 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
4533 : /* Can't set it after we are bound */
4534 0 : error = EINVAL;
4535 0 : break;
4536 : }
4537 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
4538 : /* Can't do this for a 1-m socket */
4539 0 : error = EINVAL;
4540 0 : break;
4541 : }
4542 0 : if (optval)
4543 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
4544 : else
4545 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
4546 0 : break;
4547 : }
4548 : case SCTP_PARTIAL_DELIVERY_POINT:
4549 : {
4550 : uint32_t *value;
4551 :
4552 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
4553 0 : if (*value > SCTP_SB_LIMIT_RCV(so)) {
4554 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4555 0 : error = EINVAL;
4556 0 : break;
4557 : }
4558 0 : inp->partial_delivery_point = *value;
4559 0 : break;
4560 : }
4561 : case SCTP_FRAGMENT_INTERLEAVE:
4562 : /* not yet until we re-write sctp_recvmsg() */
4563 : {
4564 : uint32_t *level;
4565 :
4566 0 : SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
4567 0 : if (*level == SCTP_FRAG_LEVEL_2) {
4568 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
4569 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
4570 0 : } else if (*level == SCTP_FRAG_LEVEL_1) {
4571 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
4572 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
4573 0 : } else if (*level == SCTP_FRAG_LEVEL_0) {
4574 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
4575 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
4576 :
4577 : } else {
4578 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4579 0 : error = EINVAL;
4580 : }
4581 0 : break;
4582 : }
4583 : case SCTP_CMT_ON_OFF:
4584 0 : if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
4585 : struct sctp_assoc_value *av;
4586 :
4587 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4588 0 : if (av->assoc_value > SCTP_CMT_MAX) {
4589 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4590 0 : error = EINVAL;
4591 0 : break;
4592 : }
4593 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4594 0 : if (stcb) {
4595 0 : stcb->asoc.sctp_cmt_on_off = av->assoc_value;
4596 0 : SCTP_TCB_UNLOCK(stcb);
4597 : } else {
4598 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4599 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4600 0 : (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4601 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4602 0 : SCTP_INP_WLOCK(inp);
4603 0 : inp->sctp_cmt_on_off = av->assoc_value;
4604 0 : SCTP_INP_WUNLOCK(inp);
4605 : }
4606 0 : if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4607 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4608 0 : SCTP_INP_RLOCK(inp);
4609 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4610 0 : SCTP_TCB_LOCK(stcb);
4611 0 : stcb->asoc.sctp_cmt_on_off = av->assoc_value;
4612 0 : SCTP_TCB_UNLOCK(stcb);
4613 : }
4614 0 : SCTP_INP_RUNLOCK(inp);
4615 : }
4616 : }
4617 : } else {
4618 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
4619 0 : error = ENOPROTOOPT;
4620 : }
4621 0 : break;
4622 : case SCTP_PLUGGABLE_CC:
4623 : {
4624 : struct sctp_assoc_value *av;
4625 : struct sctp_nets *net;
4626 :
4627 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4628 0 : if ((av->assoc_value != SCTP_CC_RFC2581) &&
4629 0 : (av->assoc_value != SCTP_CC_HSTCP) &&
4630 0 : (av->assoc_value != SCTP_CC_HTCP) &&
4631 0 : (av->assoc_value != SCTP_CC_RTCC)) {
4632 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4633 0 : error = EINVAL;
4634 0 : break;
4635 : }
4636 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4637 0 : if (stcb) {
4638 0 : stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
4639 0 : stcb->asoc.congestion_control_module = av->assoc_value;
4640 0 : if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
4641 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4642 0 : stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
4643 : }
4644 : }
4645 0 : SCTP_TCB_UNLOCK(stcb);
4646 : } else {
4647 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4648 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4649 0 : (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4650 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4651 0 : SCTP_INP_WLOCK(inp);
4652 0 : inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
4653 0 : SCTP_INP_WUNLOCK(inp);
4654 : }
4655 0 : if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4656 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4657 0 : SCTP_INP_RLOCK(inp);
4658 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4659 0 : SCTP_TCB_LOCK(stcb);
4660 0 : stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
4661 0 : stcb->asoc.congestion_control_module = av->assoc_value;
4662 0 : if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
4663 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4664 0 : stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
4665 : }
4666 : }
4667 0 : SCTP_TCB_UNLOCK(stcb);
4668 : }
4669 0 : SCTP_INP_RUNLOCK(inp);
4670 : }
4671 : }
4672 0 : break;
4673 : }
4674 : case SCTP_CC_OPTION:
4675 : {
4676 : struct sctp_cc_option *cc_opt;
4677 :
4678 0 : SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
4679 0 : SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
4680 0 : if (stcb == NULL) {
4681 0 : if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
4682 0 : SCTP_INP_RLOCK(inp);
4683 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4684 0 : SCTP_TCB_LOCK(stcb);
4685 0 : if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
4686 0 : (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1, cc_opt);
4687 : }
4688 0 : SCTP_TCB_UNLOCK(stcb);
4689 : }
4690 0 : SCTP_INP_RUNLOCK(inp);
4691 : } else {
4692 0 : error = EINVAL;
4693 : }
4694 : } else {
4695 0 : if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
4696 0 : error = ENOTSUP;
4697 : } else {
4698 0 : error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1,
4699 : cc_opt);
4700 : }
4701 0 : SCTP_TCB_UNLOCK(stcb);
4702 : }
4703 0 : break;
4704 : }
4705 : case SCTP_PLUGGABLE_SS:
4706 : {
4707 : struct sctp_assoc_value *av;
4708 :
4709 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4710 0 : if ((av->assoc_value != SCTP_SS_DEFAULT) &&
4711 0 : (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
4712 0 : (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
4713 0 : (av->assoc_value != SCTP_SS_PRIORITY) &&
4714 0 : (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
4715 0 : (av->assoc_value != SCTP_SS_FIRST_COME)) {
4716 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4717 0 : error = EINVAL;
4718 0 : break;
4719 : }
4720 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4721 0 : if (stcb) {
4722 0 : stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
4723 0 : stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
4724 0 : stcb->asoc.stream_scheduling_module = av->assoc_value;
4725 0 : stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
4726 0 : SCTP_TCB_UNLOCK(stcb);
4727 : } else {
4728 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4729 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4730 0 : (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4731 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4732 0 : SCTP_INP_WLOCK(inp);
4733 0 : inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
4734 0 : SCTP_INP_WUNLOCK(inp);
4735 : }
4736 0 : if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4737 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4738 0 : SCTP_INP_RLOCK(inp);
4739 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4740 0 : SCTP_TCB_LOCK(stcb);
4741 0 : stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
4742 0 : stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
4743 0 : stcb->asoc.stream_scheduling_module = av->assoc_value;
4744 0 : stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
4745 0 : SCTP_TCB_UNLOCK(stcb);
4746 : }
4747 0 : SCTP_INP_RUNLOCK(inp);
4748 : }
4749 : }
4750 0 : break;
4751 : }
4752 : case SCTP_SS_VALUE:
4753 : {
4754 : struct sctp_stream_value *av;
4755 :
4756 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
4757 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4758 0 : if (stcb) {
4759 0 : if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
4760 0 : (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
4761 0 : av->stream_value) < 0)) {
4762 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4763 0 : error = EINVAL;
4764 : }
4765 0 : SCTP_TCB_UNLOCK(stcb);
4766 : } else {
4767 0 : if (av->assoc_id == SCTP_CURRENT_ASSOC) {
4768 0 : SCTP_INP_RLOCK(inp);
4769 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4770 0 : SCTP_TCB_LOCK(stcb);
4771 0 : if (av->stream_id < stcb->asoc.streamoutcnt) {
4772 0 : stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
4773 : &stcb->asoc,
4774 0 : &stcb->asoc.strmout[av->stream_id],
4775 0 : av->stream_value);
4776 : }
4777 0 : SCTP_TCB_UNLOCK(stcb);
4778 : }
4779 0 : SCTP_INP_RUNLOCK(inp);
4780 : } else {
4781 : /* Can't set stream value without association */
4782 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4783 0 : error = EINVAL;
4784 : }
4785 : }
4786 0 : break;
4787 : }
4788 : case SCTP_CLR_STAT_LOG:
4789 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4790 0 : error = EOPNOTSUPP;
4791 0 : break;
4792 : case SCTP_CONTEXT:
4793 : {
4794 : struct sctp_assoc_value *av;
4795 :
4796 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4797 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4798 :
4799 0 : if (stcb) {
4800 0 : stcb->asoc.context = av->assoc_value;
4801 0 : SCTP_TCB_UNLOCK(stcb);
4802 : } else {
4803 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4804 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4805 0 : (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4806 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4807 0 : SCTP_INP_WLOCK(inp);
4808 0 : inp->sctp_context = av->assoc_value;
4809 0 : SCTP_INP_WUNLOCK(inp);
4810 : }
4811 0 : if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4812 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
4813 0 : SCTP_INP_RLOCK(inp);
4814 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4815 0 : SCTP_TCB_LOCK(stcb);
4816 0 : stcb->asoc.context = av->assoc_value;
4817 0 : SCTP_TCB_UNLOCK(stcb);
4818 : }
4819 0 : SCTP_INP_RUNLOCK(inp);
4820 : }
4821 : }
4822 0 : break;
4823 : }
4824 : case SCTP_VRF_ID:
4825 : {
4826 : uint32_t *default_vrfid;
4827 : #ifdef SCTP_MVRF
4828 : int i;
4829 : #endif
4830 0 : SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
4831 0 : if (*default_vrfid > SCTP_MAX_VRF_ID) {
4832 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4833 0 : error = EINVAL;
4834 0 : break;
4835 : }
4836 : #ifdef SCTP_MVRF
4837 : for (i = 0; i < inp->num_vrfs; i++) {
4838 : /* The VRF must be in the VRF list */
4839 : if (*default_vrfid == inp->m_vrf_ids[i]) {
4840 : SCTP_INP_WLOCK(inp);
4841 : inp->def_vrf_id = *default_vrfid;
4842 : SCTP_INP_WUNLOCK(inp);
4843 : goto sctp_done;
4844 : }
4845 : }
4846 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4847 : error = EINVAL;
4848 : #else
4849 0 : inp->def_vrf_id = *default_vrfid;
4850 : #endif
4851 : #ifdef SCTP_MVRF
4852 : sctp_done:
4853 : #endif
4854 0 : break;
4855 : }
4856 : case SCTP_DEL_VRF_ID:
4857 : {
4858 : #ifdef SCTP_MVRF
4859 : uint32_t *del_vrfid;
4860 : int i, fnd = 0;
4861 :
4862 : SCTP_CHECK_AND_CAST(del_vrfid, optval, uint32_t, optsize);
4863 : if (*del_vrfid > SCTP_MAX_VRF_ID) {
4864 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4865 : error = EINVAL;
4866 : break;
4867 : }
4868 : if (inp->num_vrfs == 1) {
4869 : /* Can't delete last one */
4870 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4871 : error = EINVAL;
4872 : break;
4873 : }
4874 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
4875 : /* Can't add more once you are bound */
4876 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4877 : error = EINVAL;
4878 : break;
4879 : }
4880 : SCTP_INP_WLOCK(inp);
4881 : for (i = 0; i < inp->num_vrfs; i++) {
4882 : if (*del_vrfid == inp->m_vrf_ids[i]) {
4883 : fnd = 1;
4884 : break;
4885 : }
4886 : }
4887 : if (!fnd) {
4888 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4889 : error = EINVAL;
4890 : break;
4891 : }
4892 : if (i != (inp->num_vrfs - 1)) {
4893 : /* Take bottom one and move to this slot */
4894 : inp->m_vrf_ids[i] = inp->m_vrf_ids[(inp->num_vrfs-1)];
4895 : }
4896 : if (*del_vrfid == inp->def_vrf_id) {
4897 : /* Take the first one as the new default */
4898 : inp->def_vrf_id = inp->m_vrf_ids[0];
4899 : }
4900 : /* Drop the number by one killing last one */
4901 : inp->num_vrfs--;
4902 : #else
4903 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4904 0 : error = EOPNOTSUPP;
4905 : #endif
4906 0 : break;
4907 : }
4908 : case SCTP_ADD_VRF_ID:
4909 : {
4910 : #ifdef SCTP_MVRF
4911 : uint32_t *add_vrfid;
4912 : int i;
4913 :
4914 : SCTP_CHECK_AND_CAST(add_vrfid, optval, uint32_t, optsize);
4915 : if (*add_vrfid > SCTP_MAX_VRF_ID) {
4916 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4917 : error = EINVAL;
4918 : break;
4919 : }
4920 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
4921 : /* Can't add more once you are bound */
4922 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4923 : error = EINVAL;
4924 : break;
4925 : }
4926 : SCTP_INP_WLOCK(inp);
4927 : /* Verify its not already here */
4928 : for (i = 0; i < inp->num_vrfs; i++) {
4929 : if (*add_vrfid == inp->m_vrf_ids[i]) {
4930 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4931 : error = EALREADY;
4932 : SCTP_INP_WUNLOCK(inp);
4933 : break;
4934 : }
4935 : }
4936 : if ((inp->num_vrfs + 1) > inp->vrf_size) {
4937 : /* need to grow array */
4938 : uint32_t *tarray;
4939 : SCTP_MALLOC(tarray, uint32_t *,
4940 : (sizeof(uint32_t) * (inp->vrf_size + SCTP_DEFAULT_VRF_SIZE)),
4941 : SCTP_M_MVRF);
4942 : if (tarray == NULL) {
4943 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4944 : error = ENOMEM;
4945 : SCTP_INP_WUNLOCK(inp);
4946 : break;
4947 : }
4948 : memcpy(tarray, inp->m_vrf_ids, (sizeof(uint32_t) * inp->vrf_size));
4949 : SCTP_FREE(inp->m_vrf_ids, SCTP_M_MVRF);
4950 : inp->m_vrf_ids = tarray;
4951 : inp->vrf_size += SCTP_DEFAULT_VRF_SIZE;
4952 : }
4953 : inp->m_vrf_ids[inp->num_vrfs] = *add_vrfid;
4954 : inp->num_vrfs++;
4955 : SCTP_INP_WUNLOCK(inp);
4956 : #else
4957 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4958 0 : error = EOPNOTSUPP;
4959 : #endif
4960 0 : break;
4961 : }
4962 : case SCTP_DELAYED_SACK:
4963 : {
4964 : struct sctp_sack_info *sack;
4965 :
4966 0 : SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
4967 0 : SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
4968 0 : if (sack->sack_delay) {
4969 0 : if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
4970 0 : sack->sack_delay = SCTP_MAX_SACK_DELAY;
4971 0 : if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
4972 0 : sack->sack_delay = TICKS_TO_MSEC(1);
4973 : }
4974 : }
4975 0 : if (stcb) {
4976 0 : if (sack->sack_delay) {
4977 0 : stcb->asoc.delayed_ack = sack->sack_delay;
4978 : }
4979 0 : if (sack->sack_freq) {
4980 0 : stcb->asoc.sack_freq = sack->sack_freq;
4981 : }
4982 0 : SCTP_TCB_UNLOCK(stcb);
4983 : } else {
4984 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4985 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4986 0 : (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
4987 0 : (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4988 0 : SCTP_INP_WLOCK(inp);
4989 0 : if (sack->sack_delay) {
4990 0 : inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
4991 : }
4992 0 : if (sack->sack_freq) {
4993 0 : inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
4994 : }
4995 0 : SCTP_INP_WUNLOCK(inp);
4996 : }
4997 0 : if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
4998 0 : (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4999 0 : SCTP_INP_RLOCK(inp);
5000 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5001 0 : SCTP_TCB_LOCK(stcb);
5002 0 : if (sack->sack_delay) {
5003 0 : stcb->asoc.delayed_ack = sack->sack_delay;
5004 : }
5005 0 : if (sack->sack_freq) {
5006 0 : stcb->asoc.sack_freq = sack->sack_freq;
5007 : }
5008 0 : SCTP_TCB_UNLOCK(stcb);
5009 : }
5010 0 : SCTP_INP_RUNLOCK(inp);
5011 : }
5012 : }
5013 0 : break;
5014 : }
5015 : case SCTP_AUTH_CHUNK:
5016 : {
5017 : struct sctp_authchunk *sauth;
5018 :
5019 0 : SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
5020 :
5021 0 : SCTP_INP_WLOCK(inp);
5022 0 : if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
5023 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5024 0 : error = EINVAL;
5025 : }
5026 0 : SCTP_INP_WUNLOCK(inp);
5027 0 : break;
5028 : }
5029 : case SCTP_AUTH_KEY:
5030 : {
5031 : struct sctp_authkey *sca;
5032 : struct sctp_keyhead *shared_keys;
5033 : sctp_sharedkey_t *shared_key;
5034 0 : sctp_key_t *key = NULL;
5035 : size_t size;
5036 :
5037 0 : SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
5038 0 : if (sca->sca_keylength == 0) {
5039 0 : size = optsize - sizeof(struct sctp_authkey);
5040 : } else {
5041 0 : if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
5042 0 : size = sca->sca_keylength;
5043 : } else {
5044 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5045 0 : error = EINVAL;
5046 0 : break;
5047 : }
5048 : }
5049 0 : SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
5050 :
5051 0 : if (stcb) {
5052 0 : shared_keys = &stcb->asoc.shared_keys;
5053 : /* clear the cached keys for this key id */
5054 0 : sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
5055 : /*
5056 : * create the new shared key and
5057 : * insert/replace it
5058 : */
5059 0 : if (size > 0) {
5060 0 : key = sctp_set_key(sca->sca_key, (uint32_t) size);
5061 0 : if (key == NULL) {
5062 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
5063 0 : error = ENOMEM;
5064 0 : SCTP_TCB_UNLOCK(stcb);
5065 0 : break;
5066 : }
5067 : }
5068 0 : shared_key = sctp_alloc_sharedkey();
5069 0 : if (shared_key == NULL) {
5070 0 : sctp_free_key(key);
5071 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
5072 0 : error = ENOMEM;
5073 0 : SCTP_TCB_UNLOCK(stcb);
5074 0 : break;
5075 : }
5076 0 : shared_key->key = key;
5077 0 : shared_key->keyid = sca->sca_keynumber;
5078 0 : error = sctp_insert_sharedkey(shared_keys, shared_key);
5079 0 : SCTP_TCB_UNLOCK(stcb);
5080 : } else {
5081 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5082 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5083 0 : (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
5084 0 : (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
5085 0 : SCTP_INP_WLOCK(inp);
5086 0 : shared_keys = &inp->sctp_ep.shared_keys;
5087 : /*
5088 : * clear the cached keys on all assocs for
5089 : * this key id
5090 : */
5091 0 : sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
5092 : /*
5093 : * create the new shared key and
5094 : * insert/replace it
5095 : */
5096 0 : if (size > 0) {
5097 0 : key = sctp_set_key(sca->sca_key, (uint32_t) size);
5098 0 : if (key == NULL) {
5099 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
5100 0 : error = ENOMEM;
5101 0 : SCTP_INP_WUNLOCK(inp);
5102 0 : break;
5103 : }
5104 : }
5105 0 : shared_key = sctp_alloc_sharedkey();
5106 0 : if (shared_key == NULL) {
5107 0 : sctp_free_key(key);
5108 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
5109 0 : error = ENOMEM;
5110 0 : SCTP_INP_WUNLOCK(inp);
5111 0 : break;
5112 : }
5113 0 : shared_key->key = key;
5114 0 : shared_key->keyid = sca->sca_keynumber;
5115 0 : error = sctp_insert_sharedkey(shared_keys, shared_key);
5116 0 : SCTP_INP_WUNLOCK(inp);
5117 : }
5118 0 : if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
5119 0 : (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
5120 0 : SCTP_INP_RLOCK(inp);
5121 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5122 0 : SCTP_TCB_LOCK(stcb);
5123 0 : shared_keys = &stcb->asoc.shared_keys;
5124 : /* clear the cached keys for this key id */
5125 0 : sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
5126 : /*
5127 : * create the new shared key and
5128 : * insert/replace it
5129 : */
5130 0 : if (size > 0) {
5131 0 : key = sctp_set_key(sca->sca_key, (uint32_t) size);
5132 0 : if (key == NULL) {
5133 0 : SCTP_TCB_UNLOCK(stcb);
5134 0 : continue;
5135 : }
5136 : }
5137 0 : shared_key = sctp_alloc_sharedkey();
5138 0 : if (shared_key == NULL) {
5139 0 : sctp_free_key(key);
5140 0 : SCTP_TCB_UNLOCK(stcb);
5141 0 : continue;
5142 : }
5143 0 : shared_key->key = key;
5144 0 : shared_key->keyid = sca->sca_keynumber;
5145 0 : error = sctp_insert_sharedkey(shared_keys, shared_key);
5146 0 : SCTP_TCB_UNLOCK(stcb);
5147 : }
5148 0 : SCTP_INP_RUNLOCK(inp);
5149 : }
5150 : }
5151 0 : break;
5152 : }
5153 : case SCTP_HMAC_IDENT:
5154 : {
5155 : struct sctp_hmacalgo *shmac;
5156 : sctp_hmaclist_t *hmaclist;
5157 : uint16_t hmacid;
5158 : uint32_t i;
5159 :
5160 0 : SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
5161 0 : if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) ||
5162 0 : (shmac->shmac_number_of_idents > 0xffff)) {
5163 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5164 0 : error = EINVAL;
5165 0 : break;
5166 : }
5167 :
5168 0 : hmaclist = sctp_alloc_hmaclist((uint16_t)shmac->shmac_number_of_idents);
5169 0 : if (hmaclist == NULL) {
5170 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
5171 0 : error = ENOMEM;
5172 0 : break;
5173 : }
5174 0 : for (i = 0; i < shmac->shmac_number_of_idents; i++) {
5175 0 : hmacid = shmac->shmac_idents[i];
5176 0 : if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
5177 : /* invalid HMACs were found */;
5178 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5179 0 : error = EINVAL;
5180 0 : sctp_free_hmaclist(hmaclist);
5181 0 : goto sctp_set_hmac_done;
5182 : }
5183 : }
5184 0 : for (i = 0; i < hmaclist->num_algo; i++) {
5185 0 : if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
5186 : /* already in list */
5187 0 : break;
5188 : }
5189 : }
5190 0 : if (i == hmaclist->num_algo) {
5191 : /* not found in list */
5192 0 : sctp_free_hmaclist(hmaclist);
5193 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5194 0 : error = EINVAL;
5195 0 : break;
5196 : }
5197 : /* set it on the endpoint */
5198 0 : SCTP_INP_WLOCK(inp);
5199 0 : if (inp->sctp_ep.local_hmacs)
5200 0 : sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
5201 0 : inp->sctp_ep.local_hmacs = hmaclist;
5202 0 : SCTP_INP_WUNLOCK(inp);
5203 : sctp_set_hmac_done:
5204 0 : break;
5205 : }
5206 : case SCTP_AUTH_ACTIVE_KEY:
5207 : {
5208 : struct sctp_authkeyid *scact;
5209 :
5210 0 : SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
5211 0 : SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
5212 :
5213 : /* set the active key on the right place */
5214 0 : if (stcb) {
5215 : /* set the active key on the assoc */
5216 0 : if (sctp_auth_setactivekey(stcb,
5217 0 : scact->scact_keynumber)) {
5218 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
5219 : SCTP_FROM_SCTP_USRREQ,
5220 : EINVAL);
5221 0 : error = EINVAL;
5222 : }
5223 0 : SCTP_TCB_UNLOCK(stcb);
5224 : } else {
5225 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5226 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5227 0 : (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
5228 0 : (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
5229 0 : SCTP_INP_WLOCK(inp);
5230 0 : if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
5231 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5232 0 : error = EINVAL;
5233 : }
5234 0 : SCTP_INP_WUNLOCK(inp);
5235 : }
5236 0 : if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
5237 0 : (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
5238 0 : SCTP_INP_RLOCK(inp);
5239 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5240 0 : SCTP_TCB_LOCK(stcb);
5241 0 : sctp_auth_setactivekey(stcb, scact->scact_keynumber);
5242 0 : SCTP_TCB_UNLOCK(stcb);
5243 : }
5244 0 : SCTP_INP_RUNLOCK(inp);
5245 : }
5246 : }
5247 0 : break;
5248 : }
5249 : case SCTP_AUTH_DELETE_KEY:
5250 : {
5251 : struct sctp_authkeyid *scdel;
5252 :
5253 0 : SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
5254 0 : SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
5255 :
5256 : /* delete the key from the right place */
5257 0 : if (stcb) {
5258 0 : if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
5259 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5260 0 : error = EINVAL;
5261 : }
5262 0 : SCTP_TCB_UNLOCK(stcb);
5263 : } else {
5264 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5265 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5266 0 : (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
5267 0 : (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
5268 0 : SCTP_INP_WLOCK(inp);
5269 0 : if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
5270 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5271 0 : error = EINVAL;
5272 : }
5273 0 : SCTP_INP_WUNLOCK(inp);
5274 : }
5275 0 : if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
5276 0 : (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
5277 0 : SCTP_INP_RLOCK(inp);
5278 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5279 0 : SCTP_TCB_LOCK(stcb);
5280 0 : sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
5281 0 : SCTP_TCB_UNLOCK(stcb);
5282 : }
5283 0 : SCTP_INP_RUNLOCK(inp);
5284 : }
5285 : }
5286 0 : break;
5287 : }
5288 : case SCTP_AUTH_DEACTIVATE_KEY:
5289 : {
5290 : struct sctp_authkeyid *keyid;
5291 :
5292 0 : SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
5293 0 : SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
5294 :
5295 : /* deactivate the key from the right place */
5296 0 : if (stcb) {
5297 0 : if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
5298 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5299 0 : error = EINVAL;
5300 : }
5301 0 : SCTP_TCB_UNLOCK(stcb);
5302 : } else {
5303 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5304 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5305 0 : (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
5306 0 : (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
5307 0 : SCTP_INP_WLOCK(inp);
5308 0 : if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
5309 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5310 0 : error = EINVAL;
5311 : }
5312 0 : SCTP_INP_WUNLOCK(inp);
5313 : }
5314 0 : if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
5315 0 : (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
5316 0 : SCTP_INP_RLOCK(inp);
5317 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5318 0 : SCTP_TCB_LOCK(stcb);
5319 0 : sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
5320 0 : SCTP_TCB_UNLOCK(stcb);
5321 : }
5322 0 : SCTP_INP_RUNLOCK(inp);
5323 : }
5324 : }
5325 0 : break;
5326 : }
5327 : case SCTP_ENABLE_STREAM_RESET:
5328 : {
5329 : struct sctp_assoc_value *av;
5330 :
5331 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
5332 0 : if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
5333 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5334 0 : error = EINVAL;
5335 0 : break;
5336 : }
5337 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
5338 0 : if (stcb) {
5339 0 : stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value;
5340 0 : SCTP_TCB_UNLOCK(stcb);
5341 : } else {
5342 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5343 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5344 0 : (av->assoc_id == SCTP_FUTURE_ASSOC) ||
5345 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
5346 0 : SCTP_INP_WLOCK(inp);
5347 0 : inp->local_strreset_support = (uint8_t)av->assoc_value;
5348 0 : SCTP_INP_WUNLOCK(inp);
5349 : }
5350 0 : if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
5351 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
5352 0 : SCTP_INP_RLOCK(inp);
5353 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5354 0 : SCTP_TCB_LOCK(stcb);
5355 0 : stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value;
5356 0 : SCTP_TCB_UNLOCK(stcb);
5357 : }
5358 0 : SCTP_INP_RUNLOCK(inp);
5359 : }
5360 :
5361 : }
5362 0 : break;
5363 : }
5364 : case SCTP_RESET_STREAMS:
5365 : {
5366 : struct sctp_reset_streams *strrst;
5367 0 : int i, send_out = 0;
5368 0 : int send_in = 0;
5369 :
5370 0 : SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
5371 0 : SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
5372 0 : if (stcb == NULL) {
5373 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
5374 0 : error = ENOENT;
5375 0 : break;
5376 : }
5377 0 : if (stcb->asoc.reconfig_supported == 0) {
5378 : /*
5379 : * Peer does not support the chunk type.
5380 : */
5381 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
5382 0 : error = EOPNOTSUPP;
5383 0 : SCTP_TCB_UNLOCK(stcb);
5384 0 : break;
5385 : }
5386 0 : if (sizeof(struct sctp_reset_streams) +
5387 0 : strrst->srs_number_streams * sizeof(uint16_t) > optsize) {
5388 0 : error = EINVAL;
5389 0 : SCTP_TCB_UNLOCK(stcb);
5390 0 : break;
5391 : }
5392 0 : if (stcb->asoc.stream_reset_outstanding) {
5393 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
5394 0 : error = EALREADY;
5395 0 : SCTP_TCB_UNLOCK(stcb);
5396 0 : break;
5397 : }
5398 0 : if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
5399 0 : send_in = 1;
5400 : }
5401 0 : if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
5402 0 : send_out = 1;
5403 : }
5404 0 : if ((send_in == 0) && (send_out == 0)) {
5405 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5406 0 : error = EINVAL;
5407 0 : SCTP_TCB_UNLOCK(stcb);
5408 0 : break;
5409 : }
5410 0 : for (i = 0; i < strrst->srs_number_streams; i++) {
5411 0 : if ((send_in) &&
5412 0 : (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
5413 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5414 0 : error = EINVAL;
5415 0 : break;
5416 : }
5417 0 : if ((send_out) &&
5418 0 : (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
5419 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5420 0 : error = EINVAL;
5421 0 : break;
5422 : }
5423 : }
5424 0 : if (error) {
5425 0 : SCTP_TCB_UNLOCK(stcb);
5426 0 : break;
5427 : }
5428 0 : error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
5429 0 : strrst->srs_stream_list,
5430 : send_out, send_in, 0, 0, 0, 0, 0);
5431 :
5432 0 : sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
5433 0 : SCTP_TCB_UNLOCK(stcb);
5434 0 : break;
5435 : }
5436 : case SCTP_ADD_STREAMS:
5437 : {
5438 : struct sctp_add_streams *stradd;
5439 0 : uint8_t addstream = 0;
5440 0 : uint16_t add_o_strmcnt = 0;
5441 0 : uint16_t add_i_strmcnt = 0;
5442 :
5443 0 : SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
5444 0 : SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
5445 0 : if (stcb == NULL) {
5446 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
5447 0 : error = ENOENT;
5448 0 : break;
5449 : }
5450 0 : if (stcb->asoc.reconfig_supported == 0) {
5451 : /*
5452 : * Peer does not support the chunk type.
5453 : */
5454 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
5455 0 : error = EOPNOTSUPP;
5456 0 : SCTP_TCB_UNLOCK(stcb);
5457 0 : break;
5458 : }
5459 0 : if (stcb->asoc.stream_reset_outstanding) {
5460 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
5461 0 : error = EALREADY;
5462 0 : SCTP_TCB_UNLOCK(stcb);
5463 0 : break;
5464 : }
5465 0 : if ((stradd->sas_outstrms == 0) &&
5466 0 : (stradd->sas_instrms == 0)) {
5467 0 : error = EINVAL;
5468 0 : goto skip_stuff;
5469 : }
5470 0 : if (stradd->sas_outstrms) {
5471 0 : addstream = 1;
5472 : /* We allocate here */
5473 0 : add_o_strmcnt = stradd->sas_outstrms;
5474 0 : if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
5475 : /* You can't have more than 64k */
5476 0 : error = EINVAL;
5477 0 : goto skip_stuff;
5478 : }
5479 : }
5480 0 : if (stradd->sas_instrms) {
5481 : int cnt;
5482 :
5483 0 : addstream |= 2;
5484 : /* We allocate inside sctp_send_str_reset_req() */
5485 0 : add_i_strmcnt = stradd->sas_instrms;
5486 0 : cnt = add_i_strmcnt;
5487 0 : cnt += stcb->asoc.streamincnt;
5488 0 : if (cnt > 0x0000ffff) {
5489 : /* You can't have more than 64k */
5490 0 : error = EINVAL;
5491 0 : goto skip_stuff;
5492 : }
5493 0 : if (cnt > (int)stcb->asoc.max_inbound_streams) {
5494 : /* More than you are allowed */
5495 0 : error = EINVAL;
5496 0 : goto skip_stuff;
5497 : }
5498 : }
5499 0 : error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
5500 0 : sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
5501 : skip_stuff:
5502 0 : SCTP_TCB_UNLOCK(stcb);
5503 0 : break;
5504 : }
5505 : case SCTP_RESET_ASSOC:
5506 : {
5507 : uint32_t *value;
5508 :
5509 0 : SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
5510 0 : SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value);
5511 0 : if (stcb == NULL) {
5512 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
5513 0 : error = ENOENT;
5514 0 : break;
5515 : }
5516 0 : if (stcb->asoc.reconfig_supported == 0) {
5517 : /*
5518 : * Peer does not support the chunk type.
5519 : */
5520 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
5521 0 : error = EOPNOTSUPP;
5522 0 : SCTP_TCB_UNLOCK(stcb);
5523 0 : break;
5524 : }
5525 0 : if (stcb->asoc.stream_reset_outstanding) {
5526 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
5527 0 : error = EALREADY;
5528 0 : SCTP_TCB_UNLOCK(stcb);
5529 0 : break;
5530 : }
5531 0 : error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0);
5532 0 : sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
5533 0 : SCTP_TCB_UNLOCK(stcb);
5534 0 : break;
5535 : }
5536 : case SCTP_CONNECT_X:
5537 0 : if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
5538 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5539 0 : error = EINVAL;
5540 0 : break;
5541 : }
5542 0 : error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
5543 0 : break;
5544 : case SCTP_CONNECT_X_DELAYED:
5545 0 : if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
5546 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5547 0 : error = EINVAL;
5548 0 : break;
5549 : }
5550 0 : error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
5551 0 : break;
5552 : case SCTP_CONNECT_X_COMPLETE:
5553 : {
5554 : struct sockaddr *sa;
5555 :
5556 : /* FIXME MT: check correct? */
5557 0 : SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
5558 :
5559 : /* find tcb */
5560 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
5561 0 : SCTP_INP_RLOCK(inp);
5562 0 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
5563 0 : if (stcb) {
5564 0 : SCTP_TCB_LOCK(stcb);
5565 : }
5566 0 : SCTP_INP_RUNLOCK(inp);
5567 : } else {
5568 : /* We increment here since sctp_findassociation_ep_addr() wil
5569 : * do a decrement if it finds the stcb as long as the locked
5570 : * tcb (last argument) is NOT a TCB.. aka NULL.
5571 : */
5572 0 : SCTP_INP_INCR_REF(inp);
5573 0 : stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
5574 0 : if (stcb == NULL) {
5575 0 : SCTP_INP_DECR_REF(inp);
5576 : }
5577 : }
5578 :
5579 0 : if (stcb == NULL) {
5580 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
5581 0 : error = ENOENT;
5582 0 : break;
5583 : }
5584 0 : if (stcb->asoc.delayed_connection == 1) {
5585 0 : stcb->asoc.delayed_connection = 0;
5586 0 : (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
5587 0 : sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
5588 : stcb->asoc.primary_destination,
5589 : SCTP_FROM_SCTP_USRREQ+SCTP_LOC_9);
5590 0 : sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
5591 : } else {
5592 : /*
5593 : * already expired or did not use delayed
5594 : * connectx
5595 : */
5596 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
5597 0 : error = EALREADY;
5598 : }
5599 0 : SCTP_TCB_UNLOCK(stcb);
5600 0 : break;
5601 : }
5602 : case SCTP_MAX_BURST:
5603 : {
5604 : #if defined(__FreeBSD__) && __FreeBSD_version < 900000
5605 : uint8_t *burst;
5606 :
5607 : SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize);
5608 :
5609 : SCTP_INP_WLOCK(inp);
5610 : inp->sctp_ep.max_burst = *burst;
5611 : SCTP_INP_WUNLOCK(inp);
5612 : #else
5613 : struct sctp_assoc_value *av;
5614 :
5615 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
5616 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
5617 :
5618 0 : if (stcb) {
5619 0 : stcb->asoc.max_burst = av->assoc_value;
5620 0 : SCTP_TCB_UNLOCK(stcb);
5621 : } else {
5622 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5623 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5624 0 : (av->assoc_id == SCTP_FUTURE_ASSOC) ||
5625 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
5626 0 : SCTP_INP_WLOCK(inp);
5627 0 : inp->sctp_ep.max_burst = av->assoc_value;
5628 0 : SCTP_INP_WUNLOCK(inp);
5629 : }
5630 0 : if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
5631 0 : (av->assoc_id == SCTP_ALL_ASSOC)) {
5632 0 : SCTP_INP_RLOCK(inp);
5633 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5634 0 : SCTP_TCB_LOCK(stcb);
5635 0 : stcb->asoc.max_burst = av->assoc_value;
5636 0 : SCTP_TCB_UNLOCK(stcb);
5637 : }
5638 0 : SCTP_INP_RUNLOCK(inp);
5639 : }
5640 : }
5641 : #endif
5642 0 : break;
5643 : }
5644 : case SCTP_MAXSEG:
5645 : {
5646 : struct sctp_assoc_value *av;
5647 : int ovh;
5648 :
5649 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
5650 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
5651 :
5652 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
5653 0 : ovh = SCTP_MED_OVERHEAD;
5654 : } else {
5655 0 : ovh = SCTP_MED_V4_OVERHEAD;
5656 : }
5657 0 : if (stcb) {
5658 0 : if (av->assoc_value) {
5659 0 : stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
5660 : } else {
5661 0 : stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
5662 : }
5663 0 : SCTP_TCB_UNLOCK(stcb);
5664 : } else {
5665 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5666 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5667 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
5668 0 : SCTP_INP_WLOCK(inp);
5669 : /* FIXME MT: I think this is not in tune with the API ID */
5670 0 : if (av->assoc_value) {
5671 0 : inp->sctp_frag_point = (av->assoc_value + ovh);
5672 : } else {
5673 0 : inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
5674 : }
5675 0 : SCTP_INP_WUNLOCK(inp);
5676 : } else {
5677 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5678 0 : error = EINVAL;
5679 : }
5680 : }
5681 0 : break;
5682 : }
5683 : case SCTP_EVENTS:
5684 : {
5685 : struct sctp_event_subscribe *events;
5686 :
5687 0 : SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
5688 :
5689 0 : SCTP_INP_WLOCK(inp);
5690 0 : if (events->sctp_data_io_event) {
5691 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
5692 : } else {
5693 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
5694 : }
5695 :
5696 0 : if (events->sctp_association_event) {
5697 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5698 : } else {
5699 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5700 : }
5701 :
5702 0 : if (events->sctp_address_event) {
5703 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
5704 : } else {
5705 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
5706 : }
5707 :
5708 0 : if (events->sctp_send_failure_event) {
5709 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5710 : } else {
5711 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5712 : }
5713 :
5714 0 : if (events->sctp_peer_error_event) {
5715 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
5716 : } else {
5717 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
5718 : }
5719 :
5720 0 : if (events->sctp_shutdown_event) {
5721 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5722 : } else {
5723 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5724 : }
5725 :
5726 0 : if (events->sctp_partial_delivery_event) {
5727 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
5728 : } else {
5729 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
5730 : }
5731 :
5732 0 : if (events->sctp_adaptation_layer_event) {
5733 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5734 : } else {
5735 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5736 : }
5737 :
5738 0 : if (events->sctp_authentication_event) {
5739 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
5740 : } else {
5741 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
5742 : }
5743 :
5744 0 : if (events->sctp_sender_dry_event) {
5745 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
5746 : } else {
5747 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
5748 : }
5749 :
5750 0 : if (events->sctp_stream_reset_event) {
5751 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5752 : } else {
5753 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5754 : }
5755 0 : SCTP_INP_WUNLOCK(inp);
5756 :
5757 0 : SCTP_INP_RLOCK(inp);
5758 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5759 0 : SCTP_TCB_LOCK(stcb);
5760 0 : if (events->sctp_association_event) {
5761 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5762 : } else {
5763 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5764 : }
5765 0 : if (events->sctp_address_event) {
5766 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
5767 : } else {
5768 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
5769 : }
5770 0 : if (events->sctp_send_failure_event) {
5771 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5772 : } else {
5773 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5774 : }
5775 0 : if (events->sctp_peer_error_event) {
5776 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
5777 : } else {
5778 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
5779 : }
5780 0 : if (events->sctp_shutdown_event) {
5781 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5782 : } else {
5783 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5784 : }
5785 0 : if (events->sctp_partial_delivery_event) {
5786 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
5787 : } else {
5788 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
5789 : }
5790 0 : if (events->sctp_adaptation_layer_event) {
5791 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5792 : } else {
5793 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5794 : }
5795 0 : if (events->sctp_authentication_event) {
5796 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
5797 : } else {
5798 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
5799 : }
5800 0 : if (events->sctp_sender_dry_event) {
5801 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
5802 : } else {
5803 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
5804 : }
5805 0 : if (events->sctp_stream_reset_event) {
5806 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5807 : } else {
5808 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5809 : }
5810 0 : SCTP_TCB_UNLOCK(stcb);
5811 : }
5812 : /* Send up the sender dry event only for 1-to-1 style sockets. */
5813 0 : if (events->sctp_sender_dry_event) {
5814 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5815 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
5816 0 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
5817 0 : if (stcb) {
5818 0 : SCTP_TCB_LOCK(stcb);
5819 0 : if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
5820 0 : TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
5821 0 : (stcb->asoc.stream_queue_cnt == 0)) {
5822 0 : sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
5823 : }
5824 0 : SCTP_TCB_UNLOCK(stcb);
5825 : }
5826 : }
5827 : }
5828 0 : SCTP_INP_RUNLOCK(inp);
5829 0 : break;
5830 : }
5831 : case SCTP_ADAPTATION_LAYER:
5832 : {
5833 : struct sctp_setadaptation *adap_bits;
5834 :
5835 0 : SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
5836 0 : SCTP_INP_WLOCK(inp);
5837 0 : inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
5838 0 : inp->sctp_ep.adaptation_layer_indicator_provided = 1;
5839 0 : SCTP_INP_WUNLOCK(inp);
5840 0 : break;
5841 : }
5842 : #ifdef SCTP_DEBUG
5843 : case SCTP_SET_INITIAL_DBG_SEQ:
5844 : {
5845 : uint32_t *vvv;
5846 :
5847 0 : SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
5848 0 : SCTP_INP_WLOCK(inp);
5849 0 : inp->sctp_ep.initial_sequence_debug = *vvv;
5850 0 : SCTP_INP_WUNLOCK(inp);
5851 0 : break;
5852 : }
5853 : #endif
5854 : case SCTP_DEFAULT_SEND_PARAM:
5855 : {
5856 : struct sctp_sndrcvinfo *s_info;
5857 :
5858 0 : SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
5859 0 : SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
5860 :
5861 0 : if (stcb) {
5862 0 : if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
5863 0 : memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
5864 : } else {
5865 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5866 0 : error = EINVAL;
5867 : }
5868 0 : SCTP_TCB_UNLOCK(stcb);
5869 : } else {
5870 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5871 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5872 0 : (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
5873 0 : (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
5874 0 : SCTP_INP_WLOCK(inp);
5875 0 : memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
5876 0 : SCTP_INP_WUNLOCK(inp);
5877 : }
5878 0 : if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
5879 0 : (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
5880 0 : SCTP_INP_RLOCK(inp);
5881 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5882 0 : SCTP_TCB_LOCK(stcb);
5883 0 : if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
5884 0 : memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
5885 : }
5886 0 : SCTP_TCB_UNLOCK(stcb);
5887 : }
5888 0 : SCTP_INP_RUNLOCK(inp);
5889 : }
5890 : }
5891 0 : break;
5892 : }
5893 : case SCTP_PEER_ADDR_PARAMS:
5894 : {
5895 : struct sctp_paddrparams *paddrp;
5896 : struct sctp_nets *net;
5897 : struct sockaddr *addr;
5898 : #if defined(INET) && defined(INET6)
5899 : struct sockaddr_in sin_store;
5900 : #endif
5901 :
5902 0 : SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
5903 0 : SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
5904 :
5905 : #if defined(INET) && defined(INET6)
5906 : if (paddrp->spp_address.ss_family == AF_INET6) {
5907 : struct sockaddr_in6 *sin6;
5908 :
5909 : sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
5910 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5911 : in6_sin6_2_sin(&sin_store, sin6);
5912 : addr = (struct sockaddr *)&sin_store;
5913 : } else {
5914 : addr = (struct sockaddr *)&paddrp->spp_address;
5915 : }
5916 : } else {
5917 : addr = (struct sockaddr *)&paddrp->spp_address;
5918 : }
5919 : #else
5920 0 : addr = (struct sockaddr *)&paddrp->spp_address;
5921 : #endif
5922 0 : if (stcb != NULL) {
5923 0 : net = sctp_findnet(stcb, addr);
5924 : } else {
5925 : /* We increment here since sctp_findassociation_ep_addr() wil
5926 : * do a decrement if it finds the stcb as long as the locked
5927 : * tcb (last argument) is NOT a TCB.. aka NULL.
5928 : */
5929 0 : net = NULL;
5930 0 : SCTP_INP_INCR_REF(inp);
5931 0 : stcb = sctp_findassociation_ep_addr(&inp, addr,
5932 : &net, NULL, NULL);
5933 0 : if (stcb == NULL) {
5934 0 : SCTP_INP_DECR_REF(inp);
5935 : }
5936 : }
5937 0 : if ((stcb != NULL) && (net == NULL)) {
5938 : #ifdef INET
5939 : if (addr->sa_family == AF_INET) {
5940 :
5941 : struct sockaddr_in *sin;
5942 : sin = (struct sockaddr_in *)addr;
5943 : if (sin->sin_addr.s_addr != INADDR_ANY) {
5944 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5945 : SCTP_TCB_UNLOCK(stcb);
5946 : error = EINVAL;
5947 : break;
5948 : }
5949 : } else
5950 : #endif
5951 : #ifdef INET6
5952 : if (addr->sa_family == AF_INET6) {
5953 : struct sockaddr_in6 *sin6;
5954 :
5955 : sin6 = (struct sockaddr_in6 *)addr;
5956 : if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5957 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5958 : SCTP_TCB_UNLOCK(stcb);
5959 : error = EINVAL;
5960 : break;
5961 : }
5962 : } else
5963 : #endif
5964 : #if defined(__Userspace__)
5965 0 : if (addr->sa_family == AF_CONN) {
5966 : struct sockaddr_conn *sconn;
5967 :
5968 0 : sconn = (struct sockaddr_conn *)addr;
5969 0 : if (sconn->sconn_addr != NULL) {
5970 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5971 0 : SCTP_TCB_UNLOCK(stcb);
5972 0 : error = EINVAL;
5973 0 : break;
5974 : }
5975 : } else
5976 : #endif
5977 : {
5978 0 : error = EAFNOSUPPORT;
5979 0 : SCTP_TCB_UNLOCK(stcb);
5980 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5981 0 : break;
5982 : }
5983 : }
5984 : /* sanity checks */
5985 0 : if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
5986 0 : if (stcb)
5987 0 : SCTP_TCB_UNLOCK(stcb);
5988 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5989 0 : return (EINVAL);
5990 : }
5991 :
5992 0 : if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
5993 0 : if (stcb)
5994 0 : SCTP_TCB_UNLOCK(stcb);
5995 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5996 0 : return (EINVAL);
5997 : }
5998 :
5999 0 : if (stcb != NULL) {
6000 : /************************TCB SPECIFIC SET ******************/
6001 : /*
6002 : * do we change the timer for HB, we run
6003 : * only one?
6004 : */
6005 0 : int ovh = 0;
6006 :
6007 0 : if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
6008 0 : ovh = SCTP_MED_OVERHEAD;
6009 : } else {
6010 0 : ovh = SCTP_MED_V4_OVERHEAD;
6011 : }
6012 :
6013 : /* network sets ? */
6014 0 : if (net != NULL) {
6015 : /************************NET SPECIFIC SET ******************/
6016 0 : if (paddrp->spp_flags & SPP_HB_DISABLE) {
6017 0 : if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
6018 0 : !(net->dest_state & SCTP_ADDR_NOHB)) {
6019 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
6020 : SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
6021 : }
6022 0 : net->dest_state |= SCTP_ADDR_NOHB;
6023 : }
6024 0 : if (paddrp->spp_flags & SPP_HB_ENABLE) {
6025 0 : if (paddrp->spp_hbinterval) {
6026 0 : net->heart_beat_delay = paddrp->spp_hbinterval;
6027 0 : } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
6028 0 : net->heart_beat_delay = 0;
6029 : }
6030 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
6031 : SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
6032 0 : sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
6033 0 : net->dest_state &= ~SCTP_ADDR_NOHB;
6034 : }
6035 0 : if (paddrp->spp_flags & SPP_HB_DEMAND) {
6036 : /* on demand HB */
6037 0 : sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6038 0 : sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
6039 0 : sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
6040 : }
6041 0 : if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
6042 0 : if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
6043 0 : sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
6044 : SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
6045 : }
6046 0 : net->dest_state |= SCTP_ADDR_NO_PMTUD;
6047 0 : net->mtu = paddrp->spp_pathmtu + ovh;
6048 0 : if (net->mtu < stcb->asoc.smallest_mtu) {
6049 0 : sctp_pathmtu_adjustment(stcb, net->mtu);
6050 : }
6051 : }
6052 0 : if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
6053 0 : if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
6054 0 : sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
6055 : }
6056 0 : net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
6057 : }
6058 0 : if (paddrp->spp_pathmaxrxt) {
6059 0 : if (net->dest_state & SCTP_ADDR_PF) {
6060 0 : if (net->error_count > paddrp->spp_pathmaxrxt) {
6061 0 : net->dest_state &= ~SCTP_ADDR_PF;
6062 : }
6063 : } else {
6064 0 : if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
6065 0 : (net->error_count > net->pf_threshold)) {
6066 0 : net->dest_state |= SCTP_ADDR_PF;
6067 0 : sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6068 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
6069 0 : sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
6070 : }
6071 : }
6072 0 : if (net->dest_state & SCTP_ADDR_REACHABLE) {
6073 0 : if (net->error_count > paddrp->spp_pathmaxrxt) {
6074 0 : net->dest_state &= ~SCTP_ADDR_REACHABLE;
6075 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
6076 : }
6077 : } else {
6078 0 : if (net->error_count <= paddrp->spp_pathmaxrxt) {
6079 0 : net->dest_state |= SCTP_ADDR_REACHABLE;
6080 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
6081 : }
6082 : }
6083 0 : net->failure_threshold = paddrp->spp_pathmaxrxt;
6084 : }
6085 0 : if (paddrp->spp_flags & SPP_DSCP) {
6086 0 : net->dscp = paddrp->spp_dscp & 0xfc;
6087 0 : net->dscp |= 0x01;
6088 : }
6089 : #ifdef INET6
6090 : if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
6091 : if (net->ro._l_addr.sa.sa_family == AF_INET6) {
6092 : net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
6093 : net->flowlabel |= 0x80000000;
6094 : }
6095 : }
6096 : #endif
6097 : } else {
6098 : /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
6099 0 : if (paddrp->spp_pathmaxrxt != 0) {
6100 0 : stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
6101 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6102 0 : if (net->dest_state & SCTP_ADDR_PF) {
6103 0 : if (net->error_count > paddrp->spp_pathmaxrxt) {
6104 0 : net->dest_state &= ~SCTP_ADDR_PF;
6105 : }
6106 : } else {
6107 0 : if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
6108 0 : (net->error_count > net->pf_threshold)) {
6109 0 : net->dest_state |= SCTP_ADDR_PF;
6110 0 : sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6111 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
6112 0 : sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
6113 : }
6114 : }
6115 0 : if (net->dest_state & SCTP_ADDR_REACHABLE) {
6116 0 : if (net->error_count > paddrp->spp_pathmaxrxt) {
6117 0 : net->dest_state &= ~SCTP_ADDR_REACHABLE;
6118 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
6119 : }
6120 : } else {
6121 0 : if (net->error_count <= paddrp->spp_pathmaxrxt) {
6122 0 : net->dest_state |= SCTP_ADDR_REACHABLE;
6123 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
6124 : }
6125 : }
6126 0 : net->failure_threshold = paddrp->spp_pathmaxrxt;
6127 : }
6128 : }
6129 :
6130 0 : if (paddrp->spp_flags & SPP_HB_ENABLE) {
6131 0 : if (paddrp->spp_hbinterval != 0) {
6132 0 : stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
6133 0 : } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
6134 0 : stcb->asoc.heart_beat_delay = 0;
6135 : }
6136 : /* Turn back on the timer */
6137 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6138 0 : if (paddrp->spp_hbinterval != 0) {
6139 0 : net->heart_beat_delay = paddrp->spp_hbinterval;
6140 0 : } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
6141 0 : net->heart_beat_delay = 0;
6142 : }
6143 0 : if (net->dest_state & SCTP_ADDR_NOHB) {
6144 0 : net->dest_state &= ~SCTP_ADDR_NOHB;
6145 : }
6146 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
6147 : SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
6148 0 : sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
6149 : }
6150 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
6151 : }
6152 0 : if (paddrp->spp_flags & SPP_HB_DISABLE) {
6153 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6154 0 : if (!(net->dest_state & SCTP_ADDR_NOHB)) {
6155 0 : net->dest_state |= SCTP_ADDR_NOHB;
6156 0 : if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
6157 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
6158 : }
6159 : }
6160 : }
6161 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
6162 : }
6163 0 : if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
6164 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6165 0 : if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
6166 0 : sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
6167 : SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
6168 : }
6169 0 : net->dest_state |= SCTP_ADDR_NO_PMTUD;
6170 0 : net->mtu = paddrp->spp_pathmtu + ovh;
6171 0 : if (net->mtu < stcb->asoc.smallest_mtu) {
6172 0 : sctp_pathmtu_adjustment(stcb, net->mtu);
6173 : }
6174 : }
6175 0 : sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
6176 : }
6177 0 : if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
6178 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6179 0 : if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
6180 0 : sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
6181 : }
6182 0 : net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
6183 : }
6184 0 : sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
6185 : }
6186 0 : if (paddrp->spp_flags & SPP_DSCP) {
6187 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6188 0 : net->dscp = paddrp->spp_dscp & 0xfc;
6189 0 : net->dscp |= 0x01;
6190 : }
6191 0 : stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc;
6192 0 : stcb->asoc.default_dscp |= 0x01;
6193 : }
6194 : #ifdef INET6
6195 : if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
6196 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6197 : if (net->ro._l_addr.sa.sa_family == AF_INET6) {
6198 : net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
6199 : net->flowlabel |= 0x80000000;
6200 : }
6201 : }
6202 : stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
6203 : stcb->asoc.default_flowlabel |= 0x80000000;
6204 : }
6205 : #endif
6206 : }
6207 0 : SCTP_TCB_UNLOCK(stcb);
6208 : } else {
6209 : /************************NO TCB, SET TO default stuff ******************/
6210 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6211 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6212 0 : (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
6213 0 : SCTP_INP_WLOCK(inp);
6214 : /*
6215 : * For the TOS/FLOWLABEL stuff you set it
6216 : * with the options on the socket
6217 : */
6218 0 : if (paddrp->spp_pathmaxrxt != 0) {
6219 0 : inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
6220 : }
6221 :
6222 0 : if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
6223 0 : inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
6224 0 : else if (paddrp->spp_hbinterval != 0) {
6225 0 : if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
6226 0 : paddrp->spp_hbinterval= SCTP_MAX_HB_INTERVAL;
6227 0 : inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
6228 : }
6229 :
6230 0 : if (paddrp->spp_flags & SPP_HB_ENABLE) {
6231 0 : if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
6232 0 : inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
6233 0 : } else if (paddrp->spp_hbinterval) {
6234 0 : inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
6235 : }
6236 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
6237 0 : } else if (paddrp->spp_flags & SPP_HB_DISABLE) {
6238 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
6239 : }
6240 0 : if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
6241 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
6242 0 : } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
6243 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
6244 : }
6245 0 : if (paddrp->spp_flags & SPP_DSCP) {
6246 0 : inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc;
6247 0 : inp->sctp_ep.default_dscp |= 0x01;
6248 : }
6249 : #ifdef INET6
6250 : if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
6251 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
6252 : inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
6253 : inp->sctp_ep.default_flowlabel |= 0x80000000;
6254 : }
6255 : }
6256 : #endif
6257 0 : SCTP_INP_WUNLOCK(inp);
6258 : } else {
6259 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6260 0 : error = EINVAL;
6261 : }
6262 : }
6263 0 : break;
6264 : }
6265 : case SCTP_RTOINFO:
6266 : {
6267 : struct sctp_rtoinfo *srto;
6268 : uint32_t new_init, new_min, new_max;
6269 :
6270 0 : SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
6271 0 : SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
6272 :
6273 0 : if (stcb) {
6274 0 : if (srto->srto_initial)
6275 0 : new_init = srto->srto_initial;
6276 : else
6277 0 : new_init = stcb->asoc.initial_rto;
6278 0 : if (srto->srto_max)
6279 0 : new_max = srto->srto_max;
6280 : else
6281 0 : new_max = stcb->asoc.maxrto;
6282 0 : if (srto->srto_min)
6283 0 : new_min = srto->srto_min;
6284 : else
6285 0 : new_min = stcb->asoc.minrto;
6286 0 : if ((new_min <= new_init) && (new_init <= new_max)) {
6287 0 : stcb->asoc.initial_rto = new_init;
6288 0 : stcb->asoc.maxrto = new_max;
6289 0 : stcb->asoc.minrto = new_min;
6290 : } else {
6291 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6292 0 : error = EINVAL;
6293 : }
6294 0 : SCTP_TCB_UNLOCK(stcb);
6295 : } else {
6296 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6297 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6298 0 : (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
6299 0 : SCTP_INP_WLOCK(inp);
6300 0 : if (srto->srto_initial)
6301 0 : new_init = srto->srto_initial;
6302 : else
6303 0 : new_init = inp->sctp_ep.initial_rto;
6304 0 : if (srto->srto_max)
6305 0 : new_max = srto->srto_max;
6306 : else
6307 0 : new_max = inp->sctp_ep.sctp_maxrto;
6308 0 : if (srto->srto_min)
6309 0 : new_min = srto->srto_min;
6310 : else
6311 0 : new_min = inp->sctp_ep.sctp_minrto;
6312 0 : if ((new_min <= new_init) && (new_init <= new_max)) {
6313 0 : inp->sctp_ep.initial_rto = new_init;
6314 0 : inp->sctp_ep.sctp_maxrto = new_max;
6315 0 : inp->sctp_ep.sctp_minrto = new_min;
6316 : } else {
6317 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6318 0 : error = EINVAL;
6319 : }
6320 0 : SCTP_INP_WUNLOCK(inp);
6321 : } else {
6322 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6323 0 : error = EINVAL;
6324 : }
6325 : }
6326 0 : break;
6327 : }
6328 : case SCTP_ASSOCINFO:
6329 : {
6330 : struct sctp_assocparams *sasoc;
6331 :
6332 0 : SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
6333 0 : SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
6334 0 : if (sasoc->sasoc_cookie_life) {
6335 : /* boundary check the cookie life */
6336 0 : if (sasoc->sasoc_cookie_life < 1000)
6337 0 : sasoc->sasoc_cookie_life = 1000;
6338 0 : if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
6339 0 : sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
6340 : }
6341 : }
6342 0 : if (stcb) {
6343 0 : if (sasoc->sasoc_asocmaxrxt)
6344 0 : stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
6345 0 : if (sasoc->sasoc_cookie_life) {
6346 0 : stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
6347 : }
6348 0 : SCTP_TCB_UNLOCK(stcb);
6349 : } else {
6350 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6351 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6352 0 : (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
6353 0 : SCTP_INP_WLOCK(inp);
6354 0 : if (sasoc->sasoc_asocmaxrxt)
6355 0 : inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
6356 0 : if (sasoc->sasoc_cookie_life) {
6357 0 : inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
6358 : }
6359 0 : SCTP_INP_WUNLOCK(inp);
6360 : } else {
6361 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6362 0 : error = EINVAL;
6363 : }
6364 : }
6365 0 : break;
6366 : }
6367 : case SCTP_INITMSG:
6368 : {
6369 : struct sctp_initmsg *sinit;
6370 :
6371 0 : SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
6372 0 : SCTP_INP_WLOCK(inp);
6373 0 : if (sinit->sinit_num_ostreams)
6374 0 : inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
6375 :
6376 0 : if (sinit->sinit_max_instreams)
6377 0 : inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
6378 :
6379 0 : if (sinit->sinit_max_attempts)
6380 0 : inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
6381 :
6382 0 : if (sinit->sinit_max_init_timeo)
6383 0 : inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
6384 0 : SCTP_INP_WUNLOCK(inp);
6385 0 : break;
6386 : }
6387 : case SCTP_PRIMARY_ADDR:
6388 : {
6389 : struct sctp_setprim *spa;
6390 : struct sctp_nets *net;
6391 : struct sockaddr *addr;
6392 : #if defined(INET) && defined(INET6)
6393 : struct sockaddr_in sin_store;
6394 : #endif
6395 :
6396 0 : SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
6397 0 : SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
6398 :
6399 : #if defined(INET) && defined(INET6)
6400 : if (spa->ssp_addr.ss_family == AF_INET6) {
6401 : struct sockaddr_in6 *sin6;
6402 :
6403 : sin6 = (struct sockaddr_in6 *)&spa->ssp_addr;
6404 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6405 : in6_sin6_2_sin(&sin_store, sin6);
6406 : addr = (struct sockaddr *)&sin_store;
6407 : } else {
6408 : addr = (struct sockaddr *)&spa->ssp_addr;
6409 : }
6410 : } else {
6411 : addr = (struct sockaddr *)&spa->ssp_addr;
6412 : }
6413 : #else
6414 0 : addr = (struct sockaddr *)&spa->ssp_addr;
6415 : #endif
6416 0 : if (stcb != NULL) {
6417 0 : net = sctp_findnet(stcb, addr);
6418 : } else {
6419 : /* We increment here since sctp_findassociation_ep_addr() wil
6420 : * do a decrement if it finds the stcb as long as the locked
6421 : * tcb (last argument) is NOT a TCB.. aka NULL.
6422 : */
6423 0 : net = NULL;
6424 0 : SCTP_INP_INCR_REF(inp);
6425 0 : stcb = sctp_findassociation_ep_addr(&inp, addr,
6426 : &net, NULL, NULL);
6427 0 : if (stcb == NULL) {
6428 0 : SCTP_INP_DECR_REF(inp);
6429 : }
6430 : }
6431 :
6432 0 : if ((stcb != NULL) && (net != NULL)) {
6433 0 : if ((net != stcb->asoc.primary_destination) &&
6434 0 : (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
6435 : /* Ok we need to set it */
6436 0 : if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
6437 0 : if ((stcb->asoc.alternate) &&
6438 0 : (!(net->dest_state & SCTP_ADDR_PF)) &&
6439 0 : (net->dest_state & SCTP_ADDR_REACHABLE)) {
6440 0 : sctp_free_remote_addr(stcb->asoc.alternate);
6441 0 : stcb->asoc.alternate = NULL;
6442 : }
6443 : }
6444 : }
6445 : } else {
6446 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6447 0 : error = EINVAL;
6448 : }
6449 0 : if (stcb != NULL) {
6450 0 : SCTP_TCB_UNLOCK(stcb);
6451 : }
6452 0 : break;
6453 : }
6454 : case SCTP_SET_DYNAMIC_PRIMARY:
6455 : {
6456 : union sctp_sockstore *ss;
6457 : #ifdef SCTP_MVRF
6458 : int i, fnd = 0;
6459 : #endif
6460 : #if !defined(__Windows__) && !defined(__Userspace__)
6461 : #if defined(__APPLE__)
6462 : struct proc *proc;
6463 : #endif
6464 : #ifdef __FreeBSD__
6465 : #if __FreeBSD_version > 602000
6466 : error = priv_check(curthread,
6467 : PRIV_NETINET_RESERVEDPORT);
6468 : #elif __FreeBSD_version >= 500000
6469 : error = suser((struct thread *)p);
6470 : #else
6471 : error = suser(p);
6472 : #endif
6473 : #elif defined(__APPLE__)
6474 : proc = (struct proc *)p;
6475 : if (p) {
6476 : error = suser(proc->p_ucred, &proc->p_acflag);
6477 : } else {
6478 : break;
6479 : }
6480 : #else
6481 : error = suser(p, 0);
6482 : #endif
6483 : #endif
6484 0 : if (error)
6485 0 : break;
6486 :
6487 0 : SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
6488 : /* SUPER USER CHECK? */
6489 : #ifdef SCTP_MVRF
6490 : for (i = 0; i < inp->num_vrfs; i++) {
6491 : if (vrf_id == inp->m_vrf_ids[i]) {
6492 : fnd = 1;
6493 : break;
6494 : }
6495 : }
6496 : if (!fnd) {
6497 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6498 : error = EINVAL;
6499 : break;
6500 : }
6501 : #endif
6502 0 : error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
6503 0 : break;
6504 : }
6505 : case SCTP_SET_PEER_PRIMARY_ADDR:
6506 : {
6507 : struct sctp_setpeerprim *sspp;
6508 : struct sockaddr *addr;
6509 : #if defined(INET) && defined(INET6)
6510 : struct sockaddr_in sin_store;
6511 : #endif
6512 :
6513 0 : SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
6514 0 : SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
6515 0 : if (stcb != NULL) {
6516 : struct sctp_ifa *ifa;
6517 :
6518 : #if defined(INET) && defined(INET6)
6519 : if (sspp->sspp_addr.ss_family == AF_INET6) {
6520 : struct sockaddr_in6 *sin6;
6521 :
6522 : sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr;
6523 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6524 : in6_sin6_2_sin(&sin_store, sin6);
6525 : addr = (struct sockaddr *)&sin_store;
6526 : } else {
6527 : addr = (struct sockaddr *)&sspp->sspp_addr;
6528 : }
6529 : } else {
6530 : addr = (struct sockaddr *)&sspp->sspp_addr;
6531 : }
6532 : #else
6533 0 : addr = (struct sockaddr *)&sspp->sspp_addr;
6534 : #endif
6535 0 : ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
6536 0 : if (ifa == NULL) {
6537 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6538 0 : error = EINVAL;
6539 0 : goto out_of_it;
6540 : }
6541 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
6542 : /* Must validate the ifa found is in our ep */
6543 : struct sctp_laddr *laddr;
6544 0 : int found = 0;
6545 :
6546 0 : LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
6547 0 : if (laddr->ifa == NULL) {
6548 0 : SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
6549 : __FUNCTION__);
6550 0 : continue;
6551 : }
6552 0 : if (laddr->ifa == ifa) {
6553 0 : found = 1;
6554 0 : break;
6555 : }
6556 : }
6557 0 : if (!found) {
6558 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6559 0 : error = EINVAL;
6560 0 : goto out_of_it;
6561 : }
6562 : #if defined(__FreeBSD__)
6563 : } else {
6564 : switch (addr->sa_family) {
6565 : #ifdef INET
6566 : case AF_INET:
6567 : {
6568 : struct sockaddr_in *sin;
6569 :
6570 : sin = (struct sockaddr_in *)addr;
6571 : if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
6572 : &sin->sin_addr) != 0) {
6573 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6574 : error = EINVAL;
6575 : goto out_of_it;
6576 : }
6577 : break;
6578 : }
6579 : #endif
6580 : #ifdef INET6
6581 : case AF_INET6:
6582 : {
6583 : struct sockaddr_in6 *sin6;
6584 :
6585 : sin6 = (struct sockaddr_in6 *)addr;
6586 : if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
6587 : &sin6->sin6_addr) != 0) {
6588 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6589 : error = EINVAL;
6590 : goto out_of_it;
6591 : }
6592 : break;
6593 : }
6594 : #endif
6595 : default:
6596 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6597 : error = EINVAL;
6598 : goto out_of_it;
6599 : }
6600 : #endif
6601 : }
6602 0 : if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) {
6603 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6604 0 : error = EINVAL;
6605 : }
6606 : out_of_it:
6607 0 : SCTP_TCB_UNLOCK(stcb);
6608 : } else {
6609 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6610 0 : error = EINVAL;
6611 : }
6612 0 : break;
6613 : }
6614 : case SCTP_BINDX_ADD_ADDR:
6615 : {
6616 : struct sctp_getaddresses *addrs;
6617 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
6618 : struct thread *td;
6619 :
6620 : td = (struct thread *)p;
6621 : #endif
6622 0 : SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
6623 : optsize);
6624 : #ifdef INET
6625 : if (addrs->addr->sa_family == AF_INET) {
6626 : if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
6627 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6628 : error = EINVAL;
6629 : break;
6630 : }
6631 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
6632 : if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
6633 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
6634 : break;
6635 : }
6636 : #endif
6637 : } else
6638 : #endif
6639 : #ifdef INET6
6640 : if (addrs->addr->sa_family == AF_INET6) {
6641 : if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
6642 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6643 : error = EINVAL;
6644 : break;
6645 : }
6646 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
6647 : if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
6648 : (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
6649 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
6650 : break;
6651 : }
6652 : #endif
6653 : } else
6654 : #endif
6655 : {
6656 0 : error = EAFNOSUPPORT;
6657 0 : break;
6658 : }
6659 : sctp_bindx_add_address(so, inp, addrs->addr,
6660 : addrs->sget_assoc_id, vrf_id,
6661 : &error, p);
6662 : break;
6663 : }
6664 : case SCTP_BINDX_REM_ADDR:
6665 : {
6666 : struct sctp_getaddresses *addrs;
6667 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
6668 : struct thread *td;
6669 : td = (struct thread *)p;
6670 :
6671 : #endif
6672 0 : SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
6673 : #ifdef INET
6674 : if (addrs->addr->sa_family == AF_INET) {
6675 : if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
6676 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6677 : error = EINVAL;
6678 : break;
6679 : }
6680 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
6681 : if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
6682 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
6683 : break;
6684 : }
6685 : #endif
6686 : } else
6687 : #endif
6688 : #ifdef INET6
6689 : if (addrs->addr->sa_family == AF_INET6) {
6690 : if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
6691 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6692 : error = EINVAL;
6693 : break;
6694 : }
6695 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
6696 : if (td != NULL &&
6697 : (error = prison_local_ip6(td->td_ucred,
6698 : &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
6699 : (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
6700 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
6701 : break;
6702 : }
6703 : #endif
6704 : } else
6705 : #endif
6706 : {
6707 0 : error = EAFNOSUPPORT;
6708 0 : break;
6709 : }
6710 : sctp_bindx_delete_address(inp, addrs->addr,
6711 : addrs->sget_assoc_id, vrf_id,
6712 : &error);
6713 : break;
6714 : }
6715 : #ifdef __APPLE__
6716 : case SCTP_LISTEN_FIX:
6717 : /* only applies to one-to-many sockets */
6718 : if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
6719 : /* make sure the ACCEPTCONN flag is OFF */
6720 : so->so_options &= ~SO_ACCEPTCONN;
6721 : } else {
6722 : /* otherwise, not allowed */
6723 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6724 : error = EINVAL;
6725 : }
6726 : break;
6727 : #endif /* __APPLE__ */
6728 : case SCTP_EVENT:
6729 : {
6730 : struct sctp_event *event;
6731 : uint32_t event_type;
6732 :
6733 0 : SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
6734 0 : SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
6735 0 : switch (event->se_type) {
6736 : case SCTP_ASSOC_CHANGE:
6737 0 : event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
6738 0 : break;
6739 : case SCTP_PEER_ADDR_CHANGE:
6740 0 : event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
6741 0 : break;
6742 : case SCTP_REMOTE_ERROR:
6743 0 : event_type = SCTP_PCB_FLAGS_RECVPEERERR;
6744 0 : break;
6745 : case SCTP_SEND_FAILED:
6746 0 : event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
6747 0 : break;
6748 : case SCTP_SHUTDOWN_EVENT:
6749 0 : event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
6750 0 : break;
6751 : case SCTP_ADAPTATION_INDICATION:
6752 0 : event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
6753 0 : break;
6754 : case SCTP_PARTIAL_DELIVERY_EVENT:
6755 0 : event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
6756 0 : break;
6757 : case SCTP_AUTHENTICATION_EVENT:
6758 0 : event_type = SCTP_PCB_FLAGS_AUTHEVNT;
6759 0 : break;
6760 : case SCTP_STREAM_RESET_EVENT:
6761 0 : event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
6762 0 : break;
6763 : case SCTP_SENDER_DRY_EVENT:
6764 0 : event_type = SCTP_PCB_FLAGS_DRYEVNT;
6765 0 : break;
6766 : case SCTP_NOTIFICATIONS_STOPPED_EVENT:
6767 0 : event_type = 0;
6768 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
6769 0 : error = ENOTSUP;
6770 0 : break;
6771 : case SCTP_ASSOC_RESET_EVENT:
6772 0 : event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
6773 0 : break;
6774 : case SCTP_STREAM_CHANGE_EVENT:
6775 0 : event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
6776 0 : break;
6777 : case SCTP_SEND_FAILED_EVENT:
6778 0 : event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
6779 0 : break;
6780 : default:
6781 0 : event_type = 0;
6782 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6783 0 : error = EINVAL;
6784 0 : break;
6785 : }
6786 0 : if (event_type > 0) {
6787 0 : if (stcb) {
6788 0 : if (event->se_on) {
6789 0 : sctp_stcb_feature_on(inp, stcb, event_type);
6790 0 : if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
6791 0 : if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
6792 0 : TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
6793 0 : (stcb->asoc.stream_queue_cnt == 0)) {
6794 0 : sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
6795 : }
6796 : }
6797 : } else {
6798 0 : sctp_stcb_feature_off(inp, stcb, event_type);
6799 : }
6800 0 : SCTP_TCB_UNLOCK(stcb);
6801 : } else {
6802 : /*
6803 : * We don't want to send up a storm of events,
6804 : * so return an error for sender dry events
6805 : */
6806 0 : if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
6807 0 : ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) &&
6808 0 : ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
6809 0 : ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
6810 0 : (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
6811 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
6812 0 : error = ENOTSUP;
6813 0 : break;
6814 : }
6815 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6816 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6817 0 : (event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
6818 0 : (event->se_assoc_id == SCTP_ALL_ASSOC)) {
6819 0 : SCTP_INP_WLOCK(inp);
6820 0 : if (event->se_on) {
6821 0 : sctp_feature_on(inp, event_type);
6822 : } else {
6823 0 : sctp_feature_off(inp, event_type);
6824 : }
6825 0 : SCTP_INP_WUNLOCK(inp);
6826 : }
6827 0 : if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
6828 0 : (event->se_assoc_id == SCTP_ALL_ASSOC)) {
6829 0 : SCTP_INP_RLOCK(inp);
6830 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6831 0 : SCTP_TCB_LOCK(stcb);
6832 0 : if (event->se_on) {
6833 0 : sctp_stcb_feature_on(inp, stcb, event_type);
6834 : } else {
6835 0 : sctp_stcb_feature_off(inp, stcb, event_type);
6836 : }
6837 0 : SCTP_TCB_UNLOCK(stcb);
6838 : }
6839 0 : SCTP_INP_RUNLOCK(inp);
6840 : }
6841 : }
6842 : }
6843 0 : break;
6844 : }
6845 : case SCTP_RECVRCVINFO:
6846 : {
6847 : int *onoff;
6848 :
6849 0 : SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
6850 0 : SCTP_INP_WLOCK(inp);
6851 0 : if (*onoff != 0) {
6852 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
6853 : } else {
6854 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
6855 : }
6856 0 : SCTP_INP_WUNLOCK(inp);
6857 0 : break;
6858 : }
6859 : case SCTP_RECVNXTINFO:
6860 : {
6861 : int *onoff;
6862 :
6863 0 : SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
6864 0 : SCTP_INP_WLOCK(inp);
6865 0 : if (*onoff != 0) {
6866 0 : sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
6867 : } else {
6868 0 : sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
6869 : }
6870 0 : SCTP_INP_WUNLOCK(inp);
6871 0 : break;
6872 : }
6873 : case SCTP_DEFAULT_SNDINFO:
6874 : {
6875 : struct sctp_sndinfo *info;
6876 : uint16_t policy;
6877 :
6878 0 : SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
6879 0 : SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
6880 :
6881 0 : if (stcb) {
6882 0 : if (info->snd_sid < stcb->asoc.streamoutcnt) {
6883 0 : stcb->asoc.def_send.sinfo_stream = info->snd_sid;
6884 0 : policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
6885 0 : stcb->asoc.def_send.sinfo_flags = info->snd_flags;
6886 0 : stcb->asoc.def_send.sinfo_flags |= policy;
6887 0 : stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
6888 0 : stcb->asoc.def_send.sinfo_context = info->snd_context;
6889 : } else {
6890 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6891 0 : error = EINVAL;
6892 : }
6893 0 : SCTP_TCB_UNLOCK(stcb);
6894 : } else {
6895 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6896 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6897 0 : (info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
6898 0 : (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
6899 0 : SCTP_INP_WLOCK(inp);
6900 0 : inp->def_send.sinfo_stream = info->snd_sid;
6901 0 : policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
6902 0 : inp->def_send.sinfo_flags = info->snd_flags;
6903 0 : inp->def_send.sinfo_flags |= policy;
6904 0 : inp->def_send.sinfo_ppid = info->snd_ppid;
6905 0 : inp->def_send.sinfo_context = info->snd_context;
6906 0 : SCTP_INP_WUNLOCK(inp);
6907 : }
6908 0 : if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
6909 0 : (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
6910 0 : SCTP_INP_RLOCK(inp);
6911 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6912 0 : SCTP_TCB_LOCK(stcb);
6913 0 : if (info->snd_sid < stcb->asoc.streamoutcnt) {
6914 0 : stcb->asoc.def_send.sinfo_stream = info->snd_sid;
6915 0 : policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
6916 0 : stcb->asoc.def_send.sinfo_flags = info->snd_flags;
6917 0 : stcb->asoc.def_send.sinfo_flags |= policy;
6918 0 : stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
6919 0 : stcb->asoc.def_send.sinfo_context = info->snd_context;
6920 : }
6921 0 : SCTP_TCB_UNLOCK(stcb);
6922 : }
6923 0 : SCTP_INP_RUNLOCK(inp);
6924 : }
6925 : }
6926 0 : break;
6927 : }
6928 : case SCTP_DEFAULT_PRINFO:
6929 : {
6930 : struct sctp_default_prinfo *info;
6931 :
6932 0 : SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize);
6933 0 : SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
6934 :
6935 0 : if (info->pr_policy > SCTP_PR_SCTP_MAX) {
6936 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6937 0 : error = EINVAL;
6938 0 : break;
6939 : }
6940 0 : if (stcb) {
6941 0 : stcb->asoc.def_send.sinfo_flags &= 0xfff0;
6942 0 : stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
6943 0 : stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
6944 0 : SCTP_TCB_UNLOCK(stcb);
6945 : } else {
6946 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6947 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6948 0 : (info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
6949 0 : (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
6950 0 : SCTP_INP_WLOCK(inp);
6951 0 : inp->def_send.sinfo_flags &= 0xfff0;
6952 0 : inp->def_send.sinfo_flags |= info->pr_policy;
6953 0 : inp->def_send.sinfo_timetolive = info->pr_value;
6954 0 : SCTP_INP_WUNLOCK(inp);
6955 : }
6956 0 : if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
6957 0 : (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
6958 0 : SCTP_INP_RLOCK(inp);
6959 0 : LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6960 0 : SCTP_TCB_LOCK(stcb);
6961 0 : stcb->asoc.def_send.sinfo_flags &= 0xfff0;
6962 0 : stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
6963 0 : stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
6964 0 : SCTP_TCB_UNLOCK(stcb);
6965 : }
6966 0 : SCTP_INP_RUNLOCK(inp);
6967 : }
6968 : }
6969 0 : break;
6970 : }
6971 : case SCTP_PEER_ADDR_THLDS:
6972 : /* Applies to the specific association */
6973 : {
6974 : struct sctp_paddrthlds *thlds;
6975 : struct sctp_nets *net;
6976 : struct sockaddr *addr;
6977 : #if defined(INET) && defined(INET6)
6978 : struct sockaddr_in sin_store;
6979 : #endif
6980 :
6981 0 : SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
6982 0 : SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
6983 :
6984 : #if defined(INET) && defined(INET6)
6985 : if (thlds->spt_address.ss_family == AF_INET6) {
6986 : struct sockaddr_in6 *sin6;
6987 :
6988 : sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
6989 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6990 : in6_sin6_2_sin(&sin_store, sin6);
6991 : addr = (struct sockaddr *)&sin_store;
6992 : } else {
6993 : addr = (struct sockaddr *)&thlds->spt_address;
6994 : }
6995 : } else {
6996 : addr = (struct sockaddr *)&thlds->spt_address;
6997 : }
6998 : #else
6999 0 : addr = (struct sockaddr *)&thlds->spt_address;
7000 : #endif
7001 0 : if (stcb != NULL) {
7002 0 : net = sctp_findnet(stcb, addr);
7003 : } else {
7004 : /* We increment here since sctp_findassociation_ep_addr() wil
7005 : * do a decrement if it finds the stcb as long as the locked
7006 : * tcb (last argument) is NOT a TCB.. aka NULL.
7007 : */
7008 0 : net = NULL;
7009 0 : SCTP_INP_INCR_REF(inp);
7010 0 : stcb = sctp_findassociation_ep_addr(&inp, addr,
7011 : &net, NULL, NULL);
7012 0 : if (stcb == NULL) {
7013 0 : SCTP_INP_DECR_REF(inp);
7014 : }
7015 : }
7016 0 : if ((stcb != NULL) && (net == NULL)) {
7017 : #ifdef INET
7018 : if (addr->sa_family == AF_INET) {
7019 :
7020 : struct sockaddr_in *sin;
7021 : sin = (struct sockaddr_in *)addr;
7022 : if (sin->sin_addr.s_addr != INADDR_ANY) {
7023 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7024 : SCTP_TCB_UNLOCK(stcb);
7025 : error = EINVAL;
7026 : break;
7027 : }
7028 : } else
7029 : #endif
7030 : #ifdef INET6
7031 : if (addr->sa_family == AF_INET6) {
7032 : struct sockaddr_in6 *sin6;
7033 :
7034 : sin6 = (struct sockaddr_in6 *)addr;
7035 : if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
7036 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7037 : SCTP_TCB_UNLOCK(stcb);
7038 : error = EINVAL;
7039 : break;
7040 : }
7041 : } else
7042 : #endif
7043 : #if defined(__Userspace__)
7044 0 : if (addr->sa_family == AF_CONN) {
7045 : struct sockaddr_conn *sconn;
7046 :
7047 0 : sconn = (struct sockaddr_conn *)addr;
7048 0 : if (sconn->sconn_addr != NULL) {
7049 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7050 0 : SCTP_TCB_UNLOCK(stcb);
7051 0 : error = EINVAL;
7052 0 : break;
7053 : }
7054 : } else
7055 : #endif
7056 : {
7057 0 : error = EAFNOSUPPORT;
7058 0 : SCTP_TCB_UNLOCK(stcb);
7059 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
7060 0 : break;
7061 : }
7062 : }
7063 0 : if (stcb != NULL) {
7064 0 : if (net != NULL) {
7065 0 : net->failure_threshold = thlds->spt_pathmaxrxt;
7066 0 : net->pf_threshold = thlds->spt_pathpfthld;
7067 0 : if (net->dest_state & SCTP_ADDR_PF) {
7068 0 : if ((net->error_count > net->failure_threshold) ||
7069 0 : (net->error_count <= net->pf_threshold)) {
7070 0 : net->dest_state &= ~SCTP_ADDR_PF;
7071 : }
7072 : } else {
7073 0 : if ((net->error_count > net->pf_threshold) &&
7074 0 : (net->error_count <= net->failure_threshold)) {
7075 0 : net->dest_state |= SCTP_ADDR_PF;
7076 0 : sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
7077 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
7078 0 : sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
7079 : }
7080 : }
7081 0 : if (net->dest_state & SCTP_ADDR_REACHABLE) {
7082 0 : if (net->error_count > net->failure_threshold) {
7083 0 : net->dest_state &= ~SCTP_ADDR_REACHABLE;
7084 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
7085 : }
7086 : } else {
7087 0 : if (net->error_count <= net->failure_threshold) {
7088 0 : net->dest_state |= SCTP_ADDR_REACHABLE;
7089 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
7090 : }
7091 : }
7092 : } else {
7093 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
7094 0 : net->failure_threshold = thlds->spt_pathmaxrxt;
7095 0 : net->pf_threshold = thlds->spt_pathpfthld;
7096 0 : if (net->dest_state & SCTP_ADDR_PF) {
7097 0 : if ((net->error_count > net->failure_threshold) ||
7098 0 : (net->error_count <= net->pf_threshold)) {
7099 0 : net->dest_state &= ~SCTP_ADDR_PF;
7100 : }
7101 : } else {
7102 0 : if ((net->error_count > net->pf_threshold) &&
7103 0 : (net->error_count <= net->failure_threshold)) {
7104 0 : net->dest_state |= SCTP_ADDR_PF;
7105 0 : sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
7106 0 : sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
7107 0 : sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
7108 : }
7109 : }
7110 0 : if (net->dest_state & SCTP_ADDR_REACHABLE) {
7111 0 : if (net->error_count > net->failure_threshold) {
7112 0 : net->dest_state &= ~SCTP_ADDR_REACHABLE;
7113 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
7114 : }
7115 : } else {
7116 0 : if (net->error_count <= net->failure_threshold) {
7117 0 : net->dest_state |= SCTP_ADDR_REACHABLE;
7118 0 : sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
7119 : }
7120 : }
7121 : }
7122 0 : stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
7123 0 : stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
7124 : }
7125 0 : SCTP_TCB_UNLOCK(stcb);
7126 : } else {
7127 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7128 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7129 0 : (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
7130 0 : SCTP_INP_WLOCK(inp);
7131 0 : inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
7132 0 : inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
7133 0 : SCTP_INP_WUNLOCK(inp);
7134 : } else {
7135 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7136 0 : error = EINVAL;
7137 : }
7138 : }
7139 0 : break;
7140 : }
7141 : case SCTP_REMOTE_UDP_ENCAPS_PORT:
7142 : {
7143 : struct sctp_udpencaps *encaps;
7144 : struct sctp_nets *net;
7145 : struct sockaddr *addr;
7146 : #if defined(INET) && defined(INET6)
7147 : struct sockaddr_in sin_store;
7148 : #endif
7149 :
7150 0 : SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
7151 0 : SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
7152 :
7153 : #if defined(INET) && defined(INET6)
7154 : if (encaps->sue_address.ss_family == AF_INET6) {
7155 : struct sockaddr_in6 *sin6;
7156 :
7157 : sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
7158 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
7159 : in6_sin6_2_sin(&sin_store, sin6);
7160 : addr = (struct sockaddr *)&sin_store;
7161 : } else {
7162 : addr = (struct sockaddr *)&encaps->sue_address;
7163 : }
7164 : } else {
7165 : addr = (struct sockaddr *)&encaps->sue_address;
7166 : }
7167 : #else
7168 0 : addr = (struct sockaddr *)&encaps->sue_address;
7169 : #endif
7170 0 : if (stcb != NULL) {
7171 0 : net = sctp_findnet(stcb, addr);
7172 : } else {
7173 : /* We increment here since sctp_findassociation_ep_addr() wil
7174 : * do a decrement if it finds the stcb as long as the locked
7175 : * tcb (last argument) is NOT a TCB.. aka NULL.
7176 : */
7177 0 : net = NULL;
7178 0 : SCTP_INP_INCR_REF(inp);
7179 0 : stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
7180 0 : if (stcb == NULL) {
7181 0 : SCTP_INP_DECR_REF(inp);
7182 : }
7183 : }
7184 0 : if ((stcb != NULL) && (net == NULL)) {
7185 : #ifdef INET
7186 : if (addr->sa_family == AF_INET) {
7187 :
7188 : struct sockaddr_in *sin;
7189 : sin = (struct sockaddr_in *)addr;
7190 : if (sin->sin_addr.s_addr != INADDR_ANY) {
7191 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7192 : SCTP_TCB_UNLOCK(stcb);
7193 : error = EINVAL;
7194 : break;
7195 : }
7196 : } else
7197 : #endif
7198 : #ifdef INET6
7199 : if (addr->sa_family == AF_INET6) {
7200 : struct sockaddr_in6 *sin6;
7201 :
7202 : sin6 = (struct sockaddr_in6 *)addr;
7203 : if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
7204 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7205 : SCTP_TCB_UNLOCK(stcb);
7206 : error = EINVAL;
7207 : break;
7208 : }
7209 : } else
7210 : #endif
7211 : #if defined(__Userspace__)
7212 0 : if (addr->sa_family == AF_CONN) {
7213 : struct sockaddr_conn *sconn;
7214 :
7215 0 : sconn = (struct sockaddr_conn *)addr;
7216 0 : if (sconn->sconn_addr != NULL) {
7217 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7218 0 : SCTP_TCB_UNLOCK(stcb);
7219 0 : error = EINVAL;
7220 0 : break;
7221 : }
7222 : } else
7223 : #endif
7224 : {
7225 0 : error = EAFNOSUPPORT;
7226 0 : SCTP_TCB_UNLOCK(stcb);
7227 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
7228 0 : break;
7229 : }
7230 : }
7231 :
7232 0 : if (stcb != NULL) {
7233 0 : if (net != NULL) {
7234 0 : net->port = encaps->sue_port;
7235 : } else {
7236 0 : stcb->asoc.port = encaps->sue_port;
7237 : }
7238 0 : SCTP_TCB_UNLOCK(stcb);
7239 : } else {
7240 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7241 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7242 0 : (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
7243 0 : SCTP_INP_WLOCK(inp);
7244 0 : inp->sctp_ep.port = encaps->sue_port;
7245 0 : SCTP_INP_WUNLOCK(inp);
7246 : } else {
7247 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7248 0 : error = EINVAL;
7249 : }
7250 : }
7251 0 : break;
7252 : }
7253 : case SCTP_ECN_SUPPORTED:
7254 : {
7255 : struct sctp_assoc_value *av;
7256 :
7257 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7258 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7259 :
7260 0 : if (stcb) {
7261 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7262 0 : error = EINVAL;
7263 0 : SCTP_TCB_UNLOCK(stcb);
7264 : } else {
7265 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7266 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7267 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7268 0 : SCTP_INP_WLOCK(inp);
7269 0 : if (av->assoc_value == 0) {
7270 0 : inp->ecn_supported = 0;
7271 : } else {
7272 0 : inp->ecn_supported = 1;
7273 : }
7274 0 : SCTP_INP_WUNLOCK(inp);
7275 : } else {
7276 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7277 0 : error = EINVAL;
7278 : }
7279 : }
7280 0 : break;
7281 : }
7282 : case SCTP_PR_SUPPORTED:
7283 : {
7284 : struct sctp_assoc_value *av;
7285 :
7286 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7287 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7288 :
7289 0 : if (stcb) {
7290 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7291 0 : error = EINVAL;
7292 0 : SCTP_TCB_UNLOCK(stcb);
7293 : } else {
7294 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7295 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7296 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7297 0 : SCTP_INP_WLOCK(inp);
7298 0 : if (av->assoc_value == 0) {
7299 0 : inp->prsctp_supported = 0;
7300 : } else {
7301 0 : inp->prsctp_supported = 1;
7302 : }
7303 0 : SCTP_INP_WUNLOCK(inp);
7304 : } else {
7305 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7306 0 : error = EINVAL;
7307 : }
7308 : }
7309 0 : break;
7310 : }
7311 : case SCTP_AUTH_SUPPORTED:
7312 : {
7313 : struct sctp_assoc_value *av;
7314 :
7315 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7316 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7317 :
7318 0 : if (stcb) {
7319 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7320 0 : error = EINVAL;
7321 0 : SCTP_TCB_UNLOCK(stcb);
7322 : } else {
7323 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7324 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7325 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7326 0 : if ((av->assoc_value == 0) &&
7327 0 : (inp->asconf_supported == 1)) {
7328 : /* AUTH is required for ASCONF */
7329 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7330 0 : error = EINVAL;
7331 : } else {
7332 0 : SCTP_INP_WLOCK(inp);
7333 0 : if (av->assoc_value == 0) {
7334 0 : inp->auth_supported = 0;
7335 : } else {
7336 0 : inp->auth_supported = 1;
7337 : }
7338 0 : SCTP_INP_WUNLOCK(inp);
7339 : }
7340 : } else {
7341 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7342 0 : error = EINVAL;
7343 : }
7344 : }
7345 0 : break;
7346 : }
7347 : case SCTP_ASCONF_SUPPORTED:
7348 : {
7349 : struct sctp_assoc_value *av;
7350 :
7351 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7352 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7353 :
7354 0 : if (stcb) {
7355 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7356 0 : error = EINVAL;
7357 0 : SCTP_TCB_UNLOCK(stcb);
7358 : } else {
7359 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7360 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7361 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7362 0 : if ((av->assoc_value != 0) &&
7363 0 : (inp->auth_supported == 0)) {
7364 : /* AUTH is required for ASCONF */
7365 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7366 0 : error = EINVAL;
7367 : } else {
7368 0 : SCTP_INP_WLOCK(inp);
7369 0 : if (av->assoc_value == 0) {
7370 0 : inp->asconf_supported = 0;
7371 0 : sctp_auth_delete_chunk(SCTP_ASCONF,
7372 0 : inp->sctp_ep.local_auth_chunks);
7373 0 : sctp_auth_delete_chunk(SCTP_ASCONF_ACK,
7374 0 : inp->sctp_ep.local_auth_chunks);
7375 : } else {
7376 0 : inp->asconf_supported = 1;
7377 0 : sctp_auth_add_chunk(SCTP_ASCONF,
7378 0 : inp->sctp_ep.local_auth_chunks);
7379 0 : sctp_auth_add_chunk(SCTP_ASCONF_ACK,
7380 0 : inp->sctp_ep.local_auth_chunks);
7381 : }
7382 0 : SCTP_INP_WUNLOCK(inp);
7383 : }
7384 : } else {
7385 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7386 0 : error = EINVAL;
7387 : }
7388 : }
7389 0 : break;
7390 : }
7391 : case SCTP_RECONFIG_SUPPORTED:
7392 : {
7393 : struct sctp_assoc_value *av;
7394 :
7395 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7396 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7397 :
7398 0 : if (stcb) {
7399 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7400 0 : error = EINVAL;
7401 0 : SCTP_TCB_UNLOCK(stcb);
7402 : } else {
7403 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7404 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7405 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7406 0 : SCTP_INP_WLOCK(inp);
7407 0 : if (av->assoc_value == 0) {
7408 0 : inp->reconfig_supported = 0;
7409 : } else {
7410 0 : inp->reconfig_supported = 1;
7411 : }
7412 0 : SCTP_INP_WUNLOCK(inp);
7413 : } else {
7414 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7415 0 : error = EINVAL;
7416 : }
7417 : }
7418 0 : break;
7419 : }
7420 : case SCTP_NRSACK_SUPPORTED:
7421 : {
7422 : struct sctp_assoc_value *av;
7423 :
7424 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7425 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7426 :
7427 0 : if (stcb) {
7428 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7429 0 : error = EINVAL;
7430 0 : SCTP_TCB_UNLOCK(stcb);
7431 : } else {
7432 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7433 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7434 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7435 0 : SCTP_INP_WLOCK(inp);
7436 0 : if (av->assoc_value == 0) {
7437 0 : inp->nrsack_supported = 0;
7438 : } else {
7439 0 : inp->nrsack_supported = 1;
7440 : }
7441 0 : SCTP_INP_WUNLOCK(inp);
7442 : } else {
7443 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7444 0 : error = EINVAL;
7445 : }
7446 : }
7447 0 : break;
7448 : }
7449 : case SCTP_PKTDROP_SUPPORTED:
7450 : {
7451 : struct sctp_assoc_value *av;
7452 :
7453 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7454 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7455 :
7456 0 : if (stcb) {
7457 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7458 0 : error = EINVAL;
7459 0 : SCTP_TCB_UNLOCK(stcb);
7460 : } else {
7461 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7462 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7463 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7464 0 : SCTP_INP_WLOCK(inp);
7465 0 : if (av->assoc_value == 0) {
7466 0 : inp->pktdrop_supported = 0;
7467 : } else {
7468 0 : inp->pktdrop_supported = 1;
7469 : }
7470 0 : SCTP_INP_WUNLOCK(inp);
7471 : } else {
7472 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7473 0 : error = EINVAL;
7474 : }
7475 : }
7476 0 : break;
7477 : }
7478 : case SCTP_MAX_CWND:
7479 : {
7480 : struct sctp_assoc_value *av;
7481 : struct sctp_nets *net;
7482 :
7483 0 : SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
7484 0 : SCTP_FIND_STCB(inp, stcb, av->assoc_id);
7485 :
7486 0 : if (stcb) {
7487 0 : stcb->asoc.max_cwnd = av->assoc_value;
7488 0 : if (stcb->asoc.max_cwnd > 0) {
7489 0 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
7490 0 : if ((net->cwnd > stcb->asoc.max_cwnd) &&
7491 0 : (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
7492 0 : net->cwnd = stcb->asoc.max_cwnd;
7493 0 : if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
7494 0 : net->cwnd = net->mtu - sizeof(struct sctphdr);
7495 : }
7496 : }
7497 : }
7498 : }
7499 0 : SCTP_TCB_UNLOCK(stcb);
7500 : } else {
7501 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
7502 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
7503 0 : (av->assoc_id == SCTP_FUTURE_ASSOC)) {
7504 0 : SCTP_INP_WLOCK(inp);
7505 0 : inp->max_cwnd = av->assoc_value;
7506 0 : SCTP_INP_WUNLOCK(inp);
7507 : } else {
7508 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7509 0 : error = EINVAL;
7510 : }
7511 : }
7512 0 : break;
7513 : }
7514 : default:
7515 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
7516 0 : error = ENOPROTOOPT;
7517 0 : break;
7518 : } /* end switch (opt) */
7519 0 : return (error);
7520 : }
7521 :
7522 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
7523 : int
7524 : sctp_ctloutput(struct socket *so, struct sockopt *sopt)
7525 : {
7526 : void *optval = NULL;
7527 : size_t optsize = 0;
7528 : void *p;
7529 : int error = 0;
7530 :
7531 : if (sopt->sopt_level != IPPROTO_SCTP) {
7532 : /* wrong proto level... send back up to IP */
7533 : #ifdef INET6
7534 : if (INP_CHECK_SOCKAF(so, AF_INET6))
7535 : error = ip6_ctloutput(so, sopt);
7536 : #endif /* INET6 */
7537 : #if defined(INET) && defined(INET6)
7538 : else
7539 : #endif
7540 : #ifdef INET
7541 : error = ip_ctloutput(so, sopt);
7542 : #endif
7543 : return (error);
7544 : }
7545 : optsize = sopt->sopt_valsize;
7546 : if (optsize) {
7547 : SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
7548 : if (optval == NULL) {
7549 : SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
7550 : return (ENOBUFS);
7551 : }
7552 : error = sooptcopyin(sopt, optval, optsize, optsize);
7553 : if (error) {
7554 : SCTP_FREE(optval, SCTP_M_SOCKOPT);
7555 : goto out;
7556 : }
7557 : }
7558 : #if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__Windows__)
7559 : p = (void *)sopt->sopt_td;
7560 : #else
7561 : p = (void *)sopt->sopt_p;
7562 : #endif
7563 : if (sopt->sopt_dir == SOPT_SET) {
7564 : error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
7565 : } else if (sopt->sopt_dir == SOPT_GET) {
7566 : error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
7567 : } else {
7568 : SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7569 : error = EINVAL;
7570 : }
7571 : if ((error == 0) && (optval != NULL)) {
7572 : error = sooptcopyout(sopt, optval, optsize);
7573 : SCTP_FREE(optval, SCTP_M_SOCKOPT);
7574 : } else if (optval != NULL) {
7575 : SCTP_FREE(optval, SCTP_M_SOCKOPT);
7576 : }
7577 : out:
7578 : return (error);
7579 : }
7580 : #endif
7581 :
7582 : #ifdef INET
7583 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
7584 : static int
7585 : sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
7586 : {
7587 : #else
7588 : #if defined(__FreeBSD__) || defined(__APPLE__)
7589 : static int
7590 : sctp_connect(struct socket *so, struct sockaddr *addr, struct proc *p)
7591 : {
7592 : #elif defined(__Panda__) || defined(__Userspace__)
7593 : int
7594 : sctp_connect(struct socket *so, struct sockaddr *addr)
7595 : {
7596 : void *p = NULL;
7597 : #elif defined(__Windows__)
7598 : static int
7599 : sctp_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p)
7600 : {
7601 : #else
7602 : static int
7603 : sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
7604 : {
7605 : struct sockaddr *addr = mtod(nam, struct sockaddr *);
7606 :
7607 : #endif
7608 : #endif
7609 : #ifdef SCTP_MVRF
7610 : int i, fnd = 0;
7611 : #endif
7612 : int error = 0;
7613 : int create_lock_on = 0;
7614 : uint32_t vrf_id;
7615 : struct sctp_inpcb *inp;
7616 : struct sctp_tcb *stcb = NULL;
7617 :
7618 : inp = (struct sctp_inpcb *)so->so_pcb;
7619 : if (inp == NULL) {
7620 : /* I made the same as TCP since we are not setup? */
7621 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7622 : return (ECONNRESET);
7623 : }
7624 : if (addr == NULL) {
7625 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7626 : return EINVAL;
7627 : }
7628 :
7629 : #if defined(__Userspace__)
7630 : /* TODO __Userspace__ falls into this code for IPv6 stuff at the moment... */
7631 : #endif
7632 : #if !defined(__Windows__) && !defined(__Userspace_os_Linux) && !defined(__Userspace_os_Windows)
7633 : switch (addr->sa_family) {
7634 : #ifdef INET6
7635 : case AF_INET6:
7636 : {
7637 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
7638 : struct sockaddr_in6 *sin6p;
7639 :
7640 : #endif
7641 : if (addr->sa_len != sizeof(struct sockaddr_in6)) {
7642 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7643 : return (EINVAL);
7644 : }
7645 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
7646 : sin6p = (struct sockaddr_in6 *)addr;
7647 : if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
7648 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
7649 : return (error);
7650 : }
7651 : #endif
7652 : break;
7653 : }
7654 : #endif
7655 : #ifdef INET
7656 : case AF_INET:
7657 : {
7658 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
7659 : struct sockaddr_in *sinp;
7660 :
7661 : #endif
7662 : #if !defined(__Userspace_os_Windows)
7663 : if (addr->sa_len != sizeof(struct sockaddr_in)) {
7664 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7665 : return (EINVAL);
7666 : }
7667 : #endif
7668 : #if defined(__FreeBSD__) && __FreeBSD_version >= 800000
7669 : sinp = (struct sockaddr_in *)addr;
7670 : if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
7671 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
7672 : return (error);
7673 : }
7674 : #endif
7675 : break;
7676 : }
7677 : #endif
7678 : default:
7679 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
7680 : return (EAFNOSUPPORT);
7681 : }
7682 : #endif
7683 : SCTP_INP_INCR_REF(inp);
7684 : SCTP_ASOC_CREATE_LOCK(inp);
7685 : create_lock_on = 1;
7686 :
7687 :
7688 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
7689 : (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
7690 : /* Should I really unlock ? */
7691 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
7692 : error = EFAULT;
7693 : goto out_now;
7694 : }
7695 : #ifdef INET6
7696 : if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
7697 : (addr->sa_family == AF_INET6)) {
7698 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7699 : error = EINVAL;
7700 : goto out_now;
7701 : }
7702 : #endif
7703 : #if defined(__Userspace__)
7704 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) &&
7705 : (addr->sa_family != AF_CONN)) {
7706 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7707 : error = EINVAL;
7708 : goto out_now;
7709 : }
7710 : #endif
7711 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
7712 : SCTP_PCB_FLAGS_UNBOUND) {
7713 : /* Bind a ephemeral port */
7714 : error = sctp_inpcb_bind(so, NULL, NULL, p);
7715 : if (error) {
7716 : goto out_now;
7717 : }
7718 : }
7719 : /* Now do we connect? */
7720 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
7721 : (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
7722 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7723 : error = EINVAL;
7724 : goto out_now;
7725 : }
7726 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
7727 : (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
7728 : /* We are already connected AND the TCP model */
7729 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
7730 : error = EADDRINUSE;
7731 : goto out_now;
7732 : }
7733 : if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
7734 : SCTP_INP_RLOCK(inp);
7735 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
7736 : SCTP_INP_RUNLOCK(inp);
7737 : } else {
7738 : /* We increment here since sctp_findassociation_ep_addr() will
7739 : * do a decrement if it finds the stcb as long as the locked
7740 : * tcb (last argument) is NOT a TCB.. aka NULL.
7741 : */
7742 : SCTP_INP_INCR_REF(inp);
7743 : stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
7744 : if (stcb == NULL) {
7745 : SCTP_INP_DECR_REF(inp);
7746 : } else {
7747 : SCTP_TCB_UNLOCK(stcb);
7748 : }
7749 : }
7750 : if (stcb != NULL) {
7751 : /* Already have or am bring up an association */
7752 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
7753 : error = EALREADY;
7754 : goto out_now;
7755 : }
7756 :
7757 : vrf_id = inp->def_vrf_id;
7758 : #ifdef SCTP_MVRF
7759 : for (i = 0; i < inp->num_vrfs; i++) {
7760 : if (vrf_id == inp->m_vrf_ids[i]) {
7761 : fnd = 1;
7762 : break;
7763 : }
7764 : }
7765 : if (!fnd) {
7766 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7767 : error = EINVAL;
7768 : goto out_now;
7769 : }
7770 : #endif
7771 : /* We are GOOD to go */
7772 : stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
7773 : if (stcb == NULL) {
7774 : /* Gak! no memory */
7775 : goto out_now;
7776 : }
7777 : if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
7778 : stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
7779 : /* Set the connected flag so we can queue data */
7780 : soisconnecting(so);
7781 : }
7782 : SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
7783 : (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
7784 :
7785 : /* initialize authentication parameters for the assoc */
7786 : sctp_initialize_auth_params(inp, stcb);
7787 :
7788 : sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
7789 : SCTP_TCB_UNLOCK(stcb);
7790 : out_now:
7791 : if (create_lock_on) {
7792 : SCTP_ASOC_CREATE_UNLOCK(inp);
7793 : }
7794 :
7795 : SCTP_INP_DECR_REF(inp);
7796 : return (error);
7797 : }
7798 : #endif
7799 :
7800 : #if defined(__Userspace__)
7801 : int
7802 0 : sctpconn_connect(struct socket *so, struct sockaddr *addr)
7803 : {
7804 : #ifdef SCTP_MVRF
7805 : int i, fnd = 0;
7806 : #endif
7807 0 : void *p = NULL;
7808 0 : int error = 0;
7809 0 : int create_lock_on = 0;
7810 : uint32_t vrf_id;
7811 : struct sctp_inpcb *inp;
7812 0 : struct sctp_tcb *stcb = NULL;
7813 :
7814 0 : inp = (struct sctp_inpcb *)so->so_pcb;
7815 0 : if (inp == NULL) {
7816 : /* I made the same as TCP since we are not setup? */
7817 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7818 0 : return (ECONNRESET);
7819 : }
7820 0 : if (addr == NULL) {
7821 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7822 0 : return EINVAL;
7823 : }
7824 0 : switch (addr->sa_family) {
7825 : #ifdef INET
7826 : case AF_INET:
7827 : #ifdef HAVE_SA_LEN
7828 : if (addr->sa_len != sizeof(struct sockaddr_in)) {
7829 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7830 : return (EINVAL);
7831 : }
7832 : #endif
7833 : break;
7834 : #endif
7835 : #ifdef INET6
7836 : case AF_INET6:
7837 : #ifdef HAVE_SA_LEN
7838 : if (addr->sa_len != sizeof(struct sockaddr_in6)) {
7839 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7840 : return (EINVAL);
7841 : }
7842 : #endif
7843 : break;
7844 : #endif
7845 : case AF_CONN:
7846 : #ifdef HAVE_SA_LEN
7847 : if (addr->sa_len != sizeof(struct sockaddr_conn)) {
7848 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7849 : return (EINVAL);
7850 : }
7851 : #endif
7852 0 : break;
7853 : default:
7854 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
7855 0 : return (EAFNOSUPPORT);
7856 : }
7857 0 : SCTP_INP_INCR_REF(inp);
7858 0 : SCTP_ASOC_CREATE_LOCK(inp);
7859 0 : create_lock_on = 1;
7860 :
7861 :
7862 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
7863 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
7864 : /* Should I really unlock ? */
7865 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
7866 0 : error = EFAULT;
7867 0 : goto out_now;
7868 : }
7869 : #ifdef INET6
7870 : if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
7871 : (addr->sa_family == AF_INET6)) {
7872 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7873 : error = EINVAL;
7874 : goto out_now;
7875 : }
7876 : #endif
7877 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == SCTP_PCB_FLAGS_UNBOUND) {
7878 : /* Bind a ephemeral port */
7879 0 : error = sctp_inpcb_bind(so, NULL, NULL, p);
7880 0 : if (error) {
7881 0 : goto out_now;
7882 : }
7883 : }
7884 : /* Now do we connect? */
7885 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
7886 0 : (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
7887 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7888 0 : error = EINVAL;
7889 0 : goto out_now;
7890 : }
7891 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
7892 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
7893 : /* We are already connected AND the TCP model */
7894 : SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
7895 0 : error = EADDRINUSE;
7896 0 : goto out_now;
7897 : }
7898 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
7899 0 : SCTP_INP_RLOCK(inp);
7900 0 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
7901 0 : SCTP_INP_RUNLOCK(inp);
7902 : } else {
7903 : /* We increment here since sctp_findassociation_ep_addr() will
7904 : * do a decrement if it finds the stcb as long as the locked
7905 : * tcb (last argument) is NOT a TCB.. aka NULL.
7906 : */
7907 0 : SCTP_INP_INCR_REF(inp);
7908 0 : stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
7909 0 : if (stcb == NULL) {
7910 0 : SCTP_INP_DECR_REF(inp);
7911 : } else {
7912 0 : SCTP_TCB_UNLOCK(stcb);
7913 : }
7914 : }
7915 0 : if (stcb != NULL) {
7916 : /* Already have or am bring up an association */
7917 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
7918 0 : error = EALREADY;
7919 0 : goto out_now;
7920 : }
7921 :
7922 0 : vrf_id = inp->def_vrf_id;
7923 : #ifdef SCTP_MVRF
7924 : for (i = 0; i < inp->num_vrfs; i++) {
7925 : if (vrf_id == inp->m_vrf_ids[i]) {
7926 : fnd = 1;
7927 : break;
7928 : }
7929 : }
7930 : if (!fnd) {
7931 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7932 : error = EINVAL;
7933 : goto out_now;
7934 : }
7935 : #endif
7936 : /* We are GOOD to go */
7937 0 : stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
7938 0 : if (stcb == NULL) {
7939 : /* Gak! no memory */
7940 0 : goto out_now;
7941 : }
7942 0 : if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
7943 0 : stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
7944 : /* Set the connected flag so we can queue data */
7945 0 : soisconnecting(so);
7946 : }
7947 0 : SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
7948 0 : (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
7949 :
7950 : /* initialize authentication parameters for the assoc */
7951 0 : sctp_initialize_auth_params(inp, stcb);
7952 :
7953 0 : sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
7954 0 : SCTP_TCB_UNLOCK(stcb);
7955 : out_now:
7956 0 : if (create_lock_on) {
7957 0 : SCTP_ASOC_CREATE_UNLOCK(inp);
7958 : }
7959 :
7960 0 : SCTP_INP_DECR_REF(inp);
7961 0 : return (error);
7962 : }
7963 : #endif
7964 : int
7965 : #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
7966 : #if __FreeBSD_version >= 700000
7967 : sctp_listen(struct socket *so, int backlog, struct thread *p)
7968 : #else
7969 : sctp_listen(struct socket *so, struct thread *p)
7970 : #endif
7971 : #elif defined(__Windows__)
7972 : sctp_listen(struct socket *so, int backlog, PKTHREAD p)
7973 : #elif defined(__Userspace__)
7974 0 : sctp_listen(struct socket *so, int backlog, struct proc *p)
7975 : #else
7976 : sctp_listen(struct socket *so, struct proc *p)
7977 : #endif
7978 : {
7979 : /*
7980 : * Note this module depends on the protocol processing being called
7981 : * AFTER any socket level flags and backlog are applied to the
7982 : * socket. The traditional way that the socket flags are applied is
7983 : * AFTER protocol processing. We have made a change to the
7984 : * sys/kern/uipc_socket.c module to reverse this but this MUST be in
7985 : * place if the socket API for SCTP is to work properly.
7986 : */
7987 :
7988 0 : int error = 0;
7989 : struct sctp_inpcb *inp;
7990 :
7991 0 : inp = (struct sctp_inpcb *)so->so_pcb;
7992 0 : if (inp == NULL) {
7993 : /* I made the same as TCP since we are not setup? */
7994 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7995 0 : return (ECONNRESET);
7996 : }
7997 0 : if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
7998 : /* See if we have a listener */
7999 : struct sctp_inpcb *tinp;
8000 : union sctp_sockstore store;
8001 :
8002 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
8003 : /* not bound all */
8004 : struct sctp_laddr *laddr;
8005 :
8006 0 : LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
8007 0 : memcpy(&store, &laddr->ifa->address, sizeof(store));
8008 0 : switch (store.sa.sa_family) {
8009 : #ifdef INET
8010 : case AF_INET:
8011 : store.sin.sin_port = inp->sctp_lport;
8012 : break;
8013 : #endif
8014 : #ifdef INET6
8015 : case AF_INET6:
8016 : store.sin6.sin6_port = inp->sctp_lport;
8017 : break;
8018 : #endif
8019 : #if defined(__Userspace__)
8020 : case AF_CONN:
8021 0 : store.sconn.sconn_port = inp->sctp_lport;
8022 0 : break;
8023 : #endif
8024 : default:
8025 0 : break;
8026 : }
8027 0 : tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
8028 0 : if (tinp && (tinp != inp) &&
8029 0 : ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
8030 0 : ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
8031 0 : (tinp->sctp_socket->so_qlimit)) {
8032 : /* we have a listener already and its not this inp. */
8033 0 : SCTP_INP_DECR_REF(tinp);
8034 0 : return (EADDRINUSE);
8035 0 : } else if (tinp) {
8036 0 : SCTP_INP_DECR_REF(tinp);
8037 : }
8038 : }
8039 : } else {
8040 : /* Setup a local addr bound all */
8041 0 : memset(&store, 0, sizeof(store));
8042 : #ifdef INET6
8043 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
8044 : store.sa.sa_family = AF_INET6;
8045 : #ifdef HAVE_SA_LEN
8046 : store.sa.sa_len = sizeof(struct sockaddr_in6);
8047 : #endif
8048 : }
8049 : #endif
8050 : #if defined(__Userspace__)
8051 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
8052 0 : store.sa.sa_family = AF_CONN;
8053 : #ifdef HAVE_SA_LEN
8054 : store.sa.sa_len = sizeof(struct sockaddr_conn);
8055 : #endif
8056 : }
8057 : #endif
8058 : #ifdef INET
8059 : #if defined(__Userspace__)
8060 : if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
8061 : ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) == 0)) {
8062 : #else
8063 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
8064 : #endif
8065 : store.sa.sa_family = AF_INET;
8066 : #ifdef HAVE_SA_LEN
8067 : store.sa.sa_len = sizeof(struct sockaddr_in);
8068 : #endif
8069 : }
8070 : #endif
8071 0 : switch (store.sa.sa_family) {
8072 : #ifdef INET
8073 : case AF_INET:
8074 : store.sin.sin_port = inp->sctp_lport;
8075 : break;
8076 : #endif
8077 : #ifdef INET6
8078 : case AF_INET6:
8079 : store.sin6.sin6_port = inp->sctp_lport;
8080 : break;
8081 : #endif
8082 : #if defined(__Userspace__)
8083 : case AF_CONN:
8084 0 : store.sconn.sconn_port = inp->sctp_lport;
8085 0 : break;
8086 : #endif
8087 : default:
8088 0 : break;
8089 : }
8090 0 : tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
8091 0 : if (tinp && (tinp != inp) &&
8092 0 : ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
8093 0 : ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
8094 0 : (tinp->sctp_socket->so_qlimit)) {
8095 : /* we have a listener already and its not this inp. */
8096 0 : SCTP_INP_DECR_REF(tinp);
8097 0 : return (EADDRINUSE);
8098 0 : } else if (tinp) {
8099 0 : SCTP_INP_DECR_REF(inp);
8100 : }
8101 : }
8102 : }
8103 0 : SCTP_INP_RLOCK(inp);
8104 : #ifdef SCTP_LOCK_LOGGING
8105 : if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
8106 : sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
8107 : }
8108 : #endif
8109 0 : SOCK_LOCK(so);
8110 : #if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Userspace__)
8111 0 : error = solisten_proto_check(so);
8112 0 : SOCK_UNLOCK(so);
8113 0 : if (error) {
8114 0 : SCTP_INP_RUNLOCK(inp);
8115 0 : return (error);
8116 : }
8117 : #endif
8118 0 : if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
8119 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
8120 : /* The unlucky case
8121 : * - We are in the tcp pool with this guy.
8122 : * - Someone else is in the main inp slot.
8123 : * - We must move this guy (the listener) to the main slot
8124 : * - We must then move the guy that was listener to the TCP Pool.
8125 : */
8126 0 : if (sctp_swap_inpcb_for_listen(inp)) {
8127 0 : SCTP_INP_RUNLOCK(inp);
8128 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
8129 0 : return (EADDRINUSE);
8130 : }
8131 : }
8132 :
8133 0 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
8134 0 : (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
8135 : /* We are already connected AND the TCP model */
8136 0 : SCTP_INP_RUNLOCK(inp);
8137 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
8138 0 : return (EADDRINUSE);
8139 : }
8140 0 : SCTP_INP_RUNLOCK(inp);
8141 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
8142 : /* We must do a bind. */
8143 0 : if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
8144 : /* bind error, probably perm */
8145 0 : return (error);
8146 : }
8147 : }
8148 0 : SOCK_LOCK(so);
8149 : #if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__) || defined(__Userspace__)
8150 : #if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__)
8151 : /* It appears for 7.0 and on, we must always call this. */
8152 0 : solisten_proto(so, backlog);
8153 : #else
8154 : if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) {
8155 : solisten_proto(so);
8156 : }
8157 : #endif
8158 : #endif
8159 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
8160 : /* remove the ACCEPTCONN flag for one-to-many sockets */
8161 : #if defined(__Userspace__)
8162 0 : so->so_options &= ~SCTP_SO_ACCEPTCONN;
8163 : #else
8164 : so->so_options &= ~SO_ACCEPTCONN;
8165 : #endif
8166 : }
8167 :
8168 : #if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__)
8169 0 : if (backlog == 0) {
8170 : /* turning off listen */
8171 : #if defined(__Userspace__)
8172 0 : so->so_options &= ~SCTP_SO_ACCEPTCONN;
8173 : #else
8174 : so->so_options &= ~SO_ACCEPTCONN;
8175 : #endif
8176 : }
8177 : #endif
8178 0 : SOCK_UNLOCK(so);
8179 0 : return (error);
8180 : }
8181 :
8182 : static int sctp_defered_wakeup_cnt = 0;
8183 :
8184 : int
8185 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
8186 0 : sctp_accept(struct socket *so, struct sockaddr **addr)
8187 : {
8188 : #elif defined(__Panda__)
8189 : sctp_accept(struct socket *so, struct sockaddr *addr, int *namelen,
8190 : void *accept_info, int *accept_info_len)
8191 : {
8192 : #else
8193 : sctp_accept(struct socket *so, struct mbuf *nam)
8194 : {
8195 : struct sockaddr *addr = mtod(nam, struct sockaddr *);
8196 : #endif
8197 : struct sctp_tcb *stcb;
8198 : struct sctp_inpcb *inp;
8199 : union sctp_sockstore store;
8200 : #ifdef INET6
8201 : #ifdef SCTP_KAME
8202 : int error;
8203 : #endif /* SCTP_KAME */
8204 : #endif
8205 0 : inp = (struct sctp_inpcb *)so->so_pcb;
8206 :
8207 0 : if (inp == NULL) {
8208 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
8209 0 : return (ECONNRESET);
8210 : }
8211 0 : SCTP_INP_RLOCK(inp);
8212 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
8213 0 : SCTP_INP_RUNLOCK(inp);
8214 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
8215 0 : return (EOPNOTSUPP);
8216 : }
8217 0 : if (so->so_state & SS_ISDISCONNECTED) {
8218 0 : SCTP_INP_RUNLOCK(inp);
8219 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
8220 0 : return (ECONNABORTED);
8221 : }
8222 0 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
8223 0 : if (stcb == NULL) {
8224 0 : SCTP_INP_RUNLOCK(inp);
8225 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
8226 0 : return (ECONNRESET);
8227 : }
8228 0 : SCTP_TCB_LOCK(stcb);
8229 0 : SCTP_INP_RUNLOCK(inp);
8230 0 : store = stcb->asoc.primary_destination->ro._l_addr;
8231 0 : stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
8232 0 : SCTP_TCB_UNLOCK(stcb);
8233 0 : switch (store.sa.sa_family) {
8234 : #ifdef INET
8235 : case AF_INET:
8236 : {
8237 : struct sockaddr_in *sin;
8238 :
8239 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
8240 : SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
8241 : if (sin == NULL)
8242 : return (ENOMEM);
8243 : #else
8244 : sin = (struct sockaddr_in *)addr;
8245 : bzero((caddr_t)sin, sizeof(*sin));
8246 : #endif
8247 : sin->sin_family = AF_INET;
8248 : #ifdef HAVE_SIN_LEN
8249 : sin->sin_len = sizeof(*sin);
8250 : #endif
8251 : sin->sin_port = store.sin.sin_port;
8252 : sin->sin_addr = store.sin.sin_addr;
8253 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
8254 : *addr = (struct sockaddr *)sin;
8255 : #elif !defined(__Panda__)
8256 : SCTP_BUF_LEN(nam) = sizeof(*sin);
8257 : #endif
8258 : break;
8259 : }
8260 : #endif
8261 : #ifdef INET6
8262 : case AF_INET6:
8263 : {
8264 : struct sockaddr_in6 *sin6;
8265 :
8266 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
8267 : SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
8268 : if (sin6 == NULL)
8269 : return (ENOMEM);
8270 : #else
8271 : sin6 = (struct sockaddr_in6 *)addr;
8272 : bzero((caddr_t)sin6, sizeof(*sin6));
8273 : #endif
8274 : sin6->sin6_family = AF_INET6;
8275 : #ifdef HAVE_SIN6_LEN
8276 : sin6->sin6_len = sizeof(*sin6);
8277 : #endif
8278 : sin6->sin6_port = store.sin6.sin6_port;
8279 : sin6->sin6_addr = store.sin6.sin6_addr;
8280 : #if defined(SCTP_EMBEDDED_V6_SCOPE)
8281 : #ifdef SCTP_KAME
8282 : if ((error = sa6_recoverscope(sin6)) != 0) {
8283 : SCTP_FREE_SONAME(sin6);
8284 : return (error);
8285 : }
8286 : #else
8287 : if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
8288 : /*
8289 : * sin6->sin6_scope_id =
8290 : * ntohs(sin6->sin6_addr.s6_addr16[1]);
8291 : */
8292 : in6_recoverscope(sin6, &sin6->sin6_addr, NULL); /* skip ifp check */
8293 : else
8294 : sin6->sin6_scope_id = 0; /* XXX */
8295 : #endif /* SCTP_KAME */
8296 : #endif /* SCTP_EMBEDDED_V6_SCOPE */
8297 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
8298 : *addr = (struct sockaddr *)sin6;
8299 : #elif !defined(__Panda__)
8300 : SCTP_BUF_LEN(nam) = sizeof(*sin6);
8301 : #endif
8302 : break;
8303 : }
8304 : #endif
8305 : #if defined(__Userspace__)
8306 : case AF_CONN:
8307 : {
8308 : struct sockaddr_conn *sconn;
8309 :
8310 0 : SCTP_MALLOC_SONAME(sconn, struct sockaddr_conn *, sizeof(struct sockaddr_conn));
8311 0 : if (sconn == NULL) {
8312 0 : return (ENOMEM);
8313 : }
8314 0 : sconn->sconn_family = AF_CONN;
8315 : #ifdef HAVE_SCONN_LEN
8316 : sconn->sconn_len = sizeof(struct sockaddr_conn);
8317 : #endif
8318 0 : sconn->sconn_port = store.sconn.sconn_port;
8319 0 : sconn->sconn_addr = store.sconn.sconn_addr;
8320 0 : *addr = (struct sockaddr *)sconn;
8321 0 : break;
8322 : }
8323 : #endif
8324 : default:
8325 : /* TSNH */
8326 0 : break;
8327 : }
8328 : /* Wake any delayed sleep action */
8329 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
8330 0 : SCTP_INP_WLOCK(inp);
8331 0 : inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
8332 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
8333 0 : inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
8334 0 : SCTP_INP_WUNLOCK(inp);
8335 0 : SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
8336 0 : if (sowriteable(inp->sctp_socket)) {
8337 : #if defined(__Userspace__)
8338 : /*__Userspace__ calling sowwakup_locked because of SOCKBUF_LOCK above. */
8339 : #endif
8340 : #if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
8341 0 : sowwakeup_locked(inp->sctp_socket);
8342 : #else
8343 : #if defined(__APPLE__)
8344 : /* socket is locked */
8345 : #endif
8346 : sowwakeup(inp->sctp_socket);
8347 : #endif
8348 : } else {
8349 0 : SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
8350 : }
8351 0 : SCTP_INP_WLOCK(inp);
8352 : }
8353 0 : if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
8354 0 : inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
8355 0 : SCTP_INP_WUNLOCK(inp);
8356 0 : SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
8357 0 : if (soreadable(inp->sctp_socket)) {
8358 0 : sctp_defered_wakeup_cnt++;
8359 : #if defined(__Userspace__)
8360 : /*__Userspace__ calling sorwakup_locked because of SOCKBUF_LOCK above */
8361 : #endif
8362 : #if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
8363 0 : sorwakeup_locked(inp->sctp_socket);
8364 : #else
8365 : #if defined(__APPLE__)
8366 : /* socket is locked */
8367 : #endif
8368 : sorwakeup(inp->sctp_socket);
8369 : #endif
8370 : } else {
8371 0 : SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
8372 : }
8373 0 : SCTP_INP_WLOCK(inp);
8374 : }
8375 0 : SCTP_INP_WUNLOCK(inp);
8376 : }
8377 0 : if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
8378 0 : SCTP_TCB_LOCK(stcb);
8379 0 : sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_7);
8380 : }
8381 0 : return (0);
8382 : }
8383 :
8384 : #ifdef INET
8385 : int
8386 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8387 : sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
8388 : {
8389 : struct sockaddr_in *sin;
8390 : #elif defined(__Panda__)
8391 : sctp_ingetaddr(struct socket *so, struct sockaddr *addr)
8392 : {
8393 : struct sockaddr_in *sin = (struct sockaddr_in *)addr;
8394 : #else
8395 : sctp_ingetaddr(struct socket *so, struct mbuf *nam)
8396 : {
8397 : struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
8398 : #endif
8399 : uint32_t vrf_id;
8400 : struct sctp_inpcb *inp;
8401 : struct sctp_ifa *sctp_ifa;
8402 :
8403 : /*
8404 : * Do the malloc first in case it blocks.
8405 : */
8406 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8407 : SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
8408 : if (sin == NULL)
8409 : return (ENOMEM);
8410 : #elif defined(__Panda__)
8411 : bzero(sin, sizeof(*sin));
8412 : #else
8413 : SCTP_BUF_LEN(nam) = sizeof(*sin);
8414 : memset(sin, 0, sizeof(*sin));
8415 : #endif
8416 : sin->sin_family = AF_INET;
8417 : #ifdef HAVE_SIN_LEN
8418 : sin->sin_len = sizeof(*sin);
8419 : #endif
8420 : inp = (struct sctp_inpcb *)so->so_pcb;
8421 : if (!inp) {
8422 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8423 : SCTP_FREE_SONAME(sin);
8424 : #endif
8425 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
8426 : return (ECONNRESET);
8427 : }
8428 : SCTP_INP_RLOCK(inp);
8429 : sin->sin_port = inp->sctp_lport;
8430 : if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
8431 : if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
8432 : struct sctp_tcb *stcb;
8433 : struct sockaddr_in *sin_a;
8434 : struct sctp_nets *net;
8435 : int fnd;
8436 :
8437 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
8438 : if (stcb == NULL) {
8439 : goto notConn;
8440 : }
8441 : fnd = 0;
8442 : sin_a = NULL;
8443 : SCTP_TCB_LOCK(stcb);
8444 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
8445 : sin_a = (struct sockaddr_in *)&net->ro._l_addr;
8446 : if (sin_a == NULL)
8447 : /* this will make coverity happy */
8448 : continue;
8449 :
8450 : if (sin_a->sin_family == AF_INET) {
8451 : fnd = 1;
8452 : break;
8453 : }
8454 : }
8455 : if ((!fnd) || (sin_a == NULL)) {
8456 : /* punt */
8457 : SCTP_TCB_UNLOCK(stcb);
8458 : goto notConn;
8459 : }
8460 :
8461 : vrf_id = inp->def_vrf_id;
8462 : sctp_ifa = sctp_source_address_selection(inp,
8463 : stcb,
8464 : (sctp_route_t *)&net->ro,
8465 : net, 0, vrf_id);
8466 : if (sctp_ifa) {
8467 : sin->sin_addr = sctp_ifa->address.sin.sin_addr;
8468 : sctp_free_ifa(sctp_ifa);
8469 : }
8470 : SCTP_TCB_UNLOCK(stcb);
8471 : } else {
8472 : /* For the bound all case you get back 0 */
8473 : notConn:
8474 : sin->sin_addr.s_addr = 0;
8475 : }
8476 :
8477 : } else {
8478 : /* Take the first IPv4 address in the list */
8479 : struct sctp_laddr *laddr;
8480 : int fnd = 0;
8481 :
8482 : LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
8483 : if (laddr->ifa->address.sa.sa_family == AF_INET) {
8484 : struct sockaddr_in *sin_a;
8485 :
8486 : sin_a = &laddr->ifa->address.sin;
8487 : sin->sin_addr = sin_a->sin_addr;
8488 : fnd = 1;
8489 : break;
8490 : }
8491 : }
8492 : if (!fnd) {
8493 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8494 : SCTP_FREE_SONAME(sin);
8495 : #endif
8496 : SCTP_INP_RUNLOCK(inp);
8497 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
8498 : return (ENOENT);
8499 : }
8500 : }
8501 : SCTP_INP_RUNLOCK(inp);
8502 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8503 : (*addr) = (struct sockaddr *)sin;
8504 : #endif
8505 : return (0);
8506 : }
8507 :
8508 : int
8509 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8510 : sctp_peeraddr(struct socket *so, struct sockaddr **addr)
8511 : {
8512 : struct sockaddr_in *sin;
8513 : #elif defined(__Panda__)
8514 : sctp_peeraddr(struct socket *so, struct sockaddr *addr)
8515 : {
8516 : struct sockaddr_in *sin = (struct sockaddr_in *)addr;
8517 : #else
8518 : sctp_peeraddr(struct socket *so, struct mbuf *nam)
8519 : {
8520 : struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
8521 :
8522 : #endif
8523 : int fnd;
8524 : struct sockaddr_in *sin_a;
8525 : struct sctp_inpcb *inp;
8526 : struct sctp_tcb *stcb;
8527 : struct sctp_nets *net;
8528 :
8529 : /* Do the malloc first in case it blocks. */
8530 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8531 : SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
8532 : if (sin == NULL)
8533 : return (ENOMEM);
8534 : #elif defined(__Panda__)
8535 : memset(sin, 0, sizeof(*sin));
8536 : #else
8537 : SCTP_BUF_LEN(nam) = sizeof(*sin);
8538 : memset(sin, 0, sizeof(*sin));
8539 : #endif
8540 : sin->sin_family = AF_INET;
8541 : #ifdef HAVE_SIN_LEN
8542 : sin->sin_len = sizeof(*sin);
8543 : #endif
8544 :
8545 : inp = (struct sctp_inpcb *)so->so_pcb;
8546 : if ((inp == NULL) ||
8547 : ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
8548 : /* UDP type and listeners will drop out here */
8549 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8550 : SCTP_FREE_SONAME(sin);
8551 : #endif
8552 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
8553 : return (ENOTCONN);
8554 : }
8555 : SCTP_INP_RLOCK(inp);
8556 : stcb = LIST_FIRST(&inp->sctp_asoc_list);
8557 : if (stcb) {
8558 : SCTP_TCB_LOCK(stcb);
8559 : }
8560 : SCTP_INP_RUNLOCK(inp);
8561 : if (stcb == NULL) {
8562 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8563 : SCTP_FREE_SONAME(sin);
8564 : #endif
8565 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
8566 : return (ECONNRESET);
8567 : }
8568 : fnd = 0;
8569 : TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
8570 : sin_a = (struct sockaddr_in *)&net->ro._l_addr;
8571 : if (sin_a->sin_family == AF_INET) {
8572 : fnd = 1;
8573 : sin->sin_port = stcb->rport;
8574 : sin->sin_addr = sin_a->sin_addr;
8575 : break;
8576 : }
8577 : }
8578 : SCTP_TCB_UNLOCK(stcb);
8579 : if (!fnd) {
8580 : /* No IPv4 address */
8581 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8582 : SCTP_FREE_SONAME(sin);
8583 : #endif
8584 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
8585 : return (ENOENT);
8586 : }
8587 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8588 : (*addr) = (struct sockaddr *)sin;
8589 : #endif
8590 : return (0);
8591 : }
8592 :
8593 : #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
8594 : struct pr_usrreqs sctp_usrreqs = {
8595 : #if defined(__FreeBSD__)
8596 : .pru_abort = sctp_abort,
8597 : .pru_accept = sctp_accept,
8598 : .pru_attach = sctp_attach,
8599 : .pru_bind = sctp_bind,
8600 : .pru_connect = sctp_connect,
8601 : .pru_control = in_control,
8602 : #if __FreeBSD_version >= 690000
8603 : .pru_close = sctp_close,
8604 : .pru_detach = sctp_close,
8605 : .pru_sopoll = sopoll_generic,
8606 : .pru_flush = sctp_flush,
8607 : #else
8608 : .pru_detach = sctp_detach,
8609 : .pru_sopoll = sopoll,
8610 : #endif
8611 : .pru_disconnect = sctp_disconnect,
8612 : .pru_listen = sctp_listen,
8613 : .pru_peeraddr = sctp_peeraddr,
8614 : .pru_send = sctp_sendm,
8615 : .pru_shutdown = sctp_shutdown,
8616 : .pru_sockaddr = sctp_ingetaddr,
8617 : .pru_sosend = sctp_sosend,
8618 : .pru_soreceive = sctp_soreceive
8619 : #elif defined(__APPLE__)
8620 : .pru_abort = sctp_abort,
8621 : .pru_accept = sctp_accept,
8622 : .pru_attach = sctp_attach,
8623 : .pru_bind = sctp_bind,
8624 : .pru_connect = sctp_connect,
8625 : .pru_connect2 = pru_connect2_notsupp,
8626 : .pru_control = in_control,
8627 : .pru_detach = sctp_detach,
8628 : .pru_disconnect = sctp_disconnect,
8629 : .pru_listen = sctp_listen,
8630 : .pru_peeraddr = sctp_peeraddr,
8631 : .pru_rcvd = NULL,
8632 : .pru_rcvoob = pru_rcvoob_notsupp,
8633 : .pru_send = sctp_sendm,
8634 : .pru_sense = pru_sense_null,
8635 : .pru_shutdown = sctp_shutdown,
8636 : .pru_sockaddr = sctp_ingetaddr,
8637 : .pru_sosend = sctp_sosend,
8638 : .pru_soreceive = sctp_soreceive,
8639 : .pru_sopoll = sopoll
8640 : #elif defined(__Windows__)
8641 : sctp_abort,
8642 : sctp_accept,
8643 : sctp_attach,
8644 : sctp_bind,
8645 : sctp_connect,
8646 : pru_connect2_notsupp,
8647 : NULL,
8648 : NULL,
8649 : sctp_disconnect,
8650 : sctp_listen,
8651 : sctp_peeraddr,
8652 : NULL,
8653 : pru_rcvoob_notsupp,
8654 : NULL,
8655 : pru_sense_null,
8656 : sctp_shutdown,
8657 : sctp_flush,
8658 : sctp_ingetaddr,
8659 : sctp_sosend,
8660 : sctp_soreceive,
8661 : sopoll_generic,
8662 : NULL,
8663 : sctp_close
8664 : #endif
8665 : };
8666 : #elif !defined(__Panda__) && !defined(__Userspace__)
8667 : int
8668 : sctp_usrreq(so, req, m, nam, control)
8669 : struct socket *so;
8670 : int req;
8671 : struct mbuf *m, *nam, *control;
8672 : {
8673 : struct proc *p = curproc;
8674 : uint32_t vrf_id;
8675 : struct sctp_vrf *vrf;
8676 : int error;
8677 : int family;
8678 : struct sctp_inpcb *inp = (struct sctp_inpcb *)so->so_pcb;
8679 :
8680 : error = 0;
8681 : family = so->so_proto->pr_domain->dom_family;
8682 : if (req == PRU_CONTROL) {
8683 : switch (family) {
8684 : case PF_INET:
8685 : error = in_control(so, (long)m, (caddr_t)nam,
8686 : (struct ifnet *)control);
8687 : break;
8688 : #ifdef INET6
8689 : case PF_INET6:
8690 : error = in6_control(so, (long)m, (caddr_t)nam,
8691 : (struct ifnet *)control, p);
8692 : break;
8693 : #endif
8694 : default:
8695 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
8696 : error = EAFNOSUPPORT;
8697 : }
8698 : return (error);
8699 : }
8700 : switch (req) {
8701 : case PRU_ATTACH:
8702 : error = sctp_attach(so, family, p);
8703 : break;
8704 : case PRU_DETACH:
8705 : error = sctp_detach(so);
8706 : break;
8707 : case PRU_BIND:
8708 : if (nam == NULL) {
8709 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
8710 : return (EINVAL);
8711 : }
8712 : error = sctp_bind(so, nam, p);
8713 : break;
8714 : case PRU_LISTEN:
8715 : error = sctp_listen(so, p);
8716 : break;
8717 : case PRU_CONNECT:
8718 : if (nam == NULL) {
8719 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
8720 : return (EINVAL);
8721 : }
8722 : error = sctp_connect(so, nam, p);
8723 : break;
8724 : case PRU_DISCONNECT:
8725 : error = sctp_disconnect(so);
8726 : break;
8727 : case PRU_ACCEPT:
8728 : if (nam == NULL) {
8729 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
8730 : return (EINVAL);
8731 : }
8732 : error = sctp_accept(so, nam);
8733 : break;
8734 : case PRU_SHUTDOWN:
8735 : error = sctp_shutdown(so);
8736 : break;
8737 :
8738 : case PRU_RCVD:
8739 : /*
8740 : * For Open and Net BSD, this is real ugly. The mbuf *nam
8741 : * that is passed (by soreceive()) is the int flags c ast as
8742 : * a (mbuf *) yuck!
8743 : */
8744 : break;
8745 :
8746 : case PRU_SEND:
8747 : /* Flags are ignored */
8748 : {
8749 : struct sockaddr *addr;
8750 :
8751 : if (nam == NULL)
8752 : addr = NULL;
8753 : else
8754 : addr = mtod(nam, struct sockaddr *);
8755 :
8756 : error = sctp_sendm(so, 0, m, addr, control, p);
8757 : }
8758 : break;
8759 : case PRU_ABORT:
8760 : error = sctp_abort(so);
8761 : break;
8762 :
8763 : case PRU_SENSE:
8764 : error = 0;
8765 : break;
8766 : case PRU_RCVOOB:
8767 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
8768 : error = EAFNOSUPPORT;
8769 : break;
8770 : case PRU_SENDOOB:
8771 : SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
8772 : error = EAFNOSUPPORT;
8773 : break;
8774 : case PRU_PEERADDR:
8775 : error = sctp_peeraddr(so, nam);
8776 : break;
8777 : case PRU_SOCKADDR:
8778 : error = sctp_ingetaddr(so, nam);
8779 : break;
8780 : case PRU_SLOWTIMO:
8781 : error = 0;
8782 : break;
8783 : default:
8784 : break;
8785 : }
8786 : return (error);
8787 : }
8788 :
8789 : #endif
8790 : #endif
8791 :
8792 : #if defined(__Userspace__)
8793 : int
8794 0 : register_recv_cb(struct socket *so,
8795 : int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
8796 : size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info))
8797 : {
8798 : struct sctp_inpcb *inp;
8799 :
8800 0 : inp = (struct sctp_inpcb *) so->so_pcb;
8801 0 : if (inp == NULL) {
8802 0 : return (0);
8803 : }
8804 0 : SCTP_INP_WLOCK(inp);
8805 0 : inp->recv_callback = receive_cb;
8806 0 : SCTP_INP_WUNLOCK(inp);
8807 0 : return (1);
8808 : }
8809 :
8810 : int
8811 0 : register_send_cb(struct socket *so, uint32_t sb_threshold, int (*send_cb)(struct socket *sock, uint32_t sb_free))
8812 : {
8813 : struct sctp_inpcb *inp;
8814 :
8815 0 : inp = (struct sctp_inpcb *) so->so_pcb;
8816 0 : if (inp == NULL) {
8817 0 : return (0);
8818 : }
8819 0 : SCTP_INP_WLOCK(inp);
8820 0 : inp->send_callback = send_cb;
8821 0 : inp->send_sb_threshold = sb_threshold;
8822 0 : SCTP_INP_WUNLOCK(inp);
8823 : /* FIXME change to current amount free. This will be the full buffer
8824 : * the first time this is registered but it could be only a portion
8825 : * of the send buffer if this is called a second time e.g. if the
8826 : * threshold changes.
8827 : */
8828 0 : return (1);
8829 : }
8830 :
8831 : int
8832 0 : register_ulp_info (struct socket *so, void *ulp_info)
8833 : {
8834 : struct sctp_inpcb *inp;
8835 :
8836 0 : inp = (struct sctp_inpcb *) so->so_pcb;
8837 0 : if (inp == NULL) {
8838 0 : return (0);
8839 : }
8840 0 : SCTP_INP_WLOCK(inp);
8841 0 : inp->ulp_info = ulp_info;
8842 0 : SCTP_INP_WUNLOCK(inp);
8843 0 : return (1);
8844 : }
8845 : #endif
|