netwerk/sctp/src/netinet/sctp_usrreq.c

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rwxr-xr-x

Correct small whitespace inconsistency, lost while renaming variables.

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

mercurial