18c2654abSrjs /* $KAME: sctp_usrreq.c,v 1.50 2005/06/16 20:45:29 jinmei Exp $ */ 2*76748ca4Srillig /* $NetBSD: sctp_usrreq.c,v 1.27 2024/09/08 17:28:37 rillig Exp $ */ 38c2654abSrjs 48c2654abSrjs /* 58c2654abSrjs * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc. 68c2654abSrjs * All rights reserved. 78c2654abSrjs * 88c2654abSrjs * Redistribution and use in source and binary forms, with or without 98c2654abSrjs * modification, are permitted provided that the following conditions 108c2654abSrjs * are met: 118c2654abSrjs * 1. Redistributions of source code must retain the above copyright 128c2654abSrjs * notice, this list of conditions and the following disclaimer. 138c2654abSrjs * 2. Redistributions in binary form must reproduce the above copyright 148c2654abSrjs * notice, this list of conditions and the following disclaimer in the 158c2654abSrjs * documentation and/or other materials provided with the distribution. 168c2654abSrjs * 3. All advertising materials mentioning features or use of this software 178c2654abSrjs * must display the following acknowledgement: 188c2654abSrjs * This product includes software developed by Cisco Systems, Inc. 198c2654abSrjs * 4. Neither the name of the project nor the names of its contributors 208c2654abSrjs * may be used to endorse or promote products derived from this software 218c2654abSrjs * without specific prior written permission. 228c2654abSrjs * 238c2654abSrjs * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS AND CONTRIBUTORS ``AS IS'' AND 248c2654abSrjs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 258c2654abSrjs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 268c2654abSrjs * ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS OR CONTRIBUTORS BE LIABLE 278c2654abSrjs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 288c2654abSrjs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 298c2654abSrjs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 308c2654abSrjs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 318c2654abSrjs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 328c2654abSrjs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 338c2654abSrjs * SUCH DAMAGE. 348c2654abSrjs */ 358c2654abSrjs #include <sys/cdefs.h> 36*76748ca4Srillig __KERNEL_RCSID(0, "$NetBSD: sctp_usrreq.c,v 1.27 2024/09/08 17:28:37 rillig Exp $"); 378c2654abSrjs 388c2654abSrjs #ifdef _KERNEL_OPT 398c2654abSrjs #include "opt_inet.h" 408c2654abSrjs #include "opt_sctp.h" 418c2654abSrjs #endif /* _KERNEL_OPT */ 428c2654abSrjs 438c2654abSrjs #include <sys/param.h> 448c2654abSrjs #include <sys/systm.h> 458c2654abSrjs #include <sys/kernel.h> 468c2654abSrjs #include <sys/malloc.h> 478c2654abSrjs #include <sys/mbuf.h> 488c2654abSrjs #include <sys/domain.h> 498c2654abSrjs #include <sys/proc.h> 508c2654abSrjs #include <sys/protosw.h> 518c2654abSrjs #include <sys/socket.h> 528c2654abSrjs #include <sys/socketvar.h> 538c2654abSrjs #include <sys/sysctl.h> 548c2654abSrjs #include <sys/syslog.h> 558c2654abSrjs #include <net/if.h> 568c2654abSrjs #include <net/if_types.h> 578c2654abSrjs #include <net/route.h> 588c2654abSrjs #include <netinet/in.h> 598c2654abSrjs #include <netinet/in_systm.h> 608c2654abSrjs #include <netinet/ip.h> 618c2654abSrjs #include <netinet/ip6.h> 628c2654abSrjs #include <netinet/in_pcb.h> 638c2654abSrjs #include <netinet/in_var.h> 648c2654abSrjs #include <netinet/ip_var.h> 658c2654abSrjs #include <netinet6/ip6_var.h> 668c2654abSrjs #include <netinet6/in6_var.h> 678c2654abSrjs #include <netinet6/scope6_var.h> 688c2654abSrjs 698c2654abSrjs #include <netinet/ip_icmp.h> 708c2654abSrjs #include <netinet/icmp_var.h> 718c2654abSrjs #include <netinet/sctp_pcb.h> 728c2654abSrjs #include <netinet/sctp_header.h> 738c2654abSrjs #include <netinet/sctp_var.h> 748c2654abSrjs #include <netinet/sctp_output.h> 758c2654abSrjs #include <netinet/sctp_uio.h> 768c2654abSrjs #include <netinet/sctp_asconf.h> 778e337251Srjs #include <netinet/sctp_route.h> 788c2654abSrjs #include <netinet/sctputil.h> 798c2654abSrjs #include <netinet/sctp_indata.h> 808c2654abSrjs #include <netinet/sctp_asconf.h> 818c2654abSrjs #ifdef IPSEC 82505ea976Srjs #include <netipsec/ipsec.h> 83505ea976Srjs #include <netipsec/key.h> 848c2654abSrjs #endif /* IPSEC */ 858c2654abSrjs 868c2654abSrjs #if defined(HAVE_NRL_INPCB) || defined(__FreeBSD__) 878c2654abSrjs #ifndef in6pcb 888c2654abSrjs #define in6pcb inpcb 898c2654abSrjs #endif 908c2654abSrjs #ifndef sotoin6pcb 918c2654abSrjs #define sotoin6pcb sotoinpcb 928c2654abSrjs #endif 938c2654abSrjs #endif 948c2654abSrjs 958c2654abSrjs #ifdef SCTP_DEBUG 968c2654abSrjs extern u_int32_t sctp_debug_on; 978c2654abSrjs #endif /* SCTP_DEBUG */ 988c2654abSrjs 998c2654abSrjs /* 1008c2654abSrjs * sysctl tunable variables 1018c2654abSrjs */ 1028c2654abSrjs int sctp_auto_asconf = SCTP_DEFAULT_AUTO_ASCONF; 1038c2654abSrjs int sctp_max_burst_default = SCTP_DEF_MAX_BURST; 1048c2654abSrjs int sctp_peer_chunk_oh = sizeof(struct mbuf); 1058c2654abSrjs int sctp_strict_init = 1; 1068c2654abSrjs int sctp_no_csum_on_loopback = 1; 1078c2654abSrjs unsigned int sctp_max_chunks_on_queue = SCTP_ASOC_MAX_CHUNKS_ON_QUEUE; 1088c2654abSrjs int sctp_sendspace = (128 * 1024); 1098c2654abSrjs int sctp_recvspace = 128 * (1024 + 1108c2654abSrjs #ifdef INET6 1118c2654abSrjs sizeof(struct sockaddr_in6) 1128c2654abSrjs #else 1138c2654abSrjs sizeof(struct sockaddr_in) 1148c2654abSrjs #endif 1158c2654abSrjs ); 1168c2654abSrjs int sctp_strict_sacks = 0; 1178c2654abSrjs int sctp_ecn = 1; 1188c2654abSrjs int sctp_ecn_nonce = 0; 1198c2654abSrjs 1208c2654abSrjs unsigned int sctp_delayed_sack_time_default = SCTP_RECV_MSEC; 1218c2654abSrjs unsigned int sctp_heartbeat_interval_default = SCTP_HB_DEFAULT_MSEC; 1228c2654abSrjs unsigned int sctp_pmtu_raise_time_default = SCTP_DEF_PMTU_RAISE_SEC; 1238c2654abSrjs unsigned int sctp_shutdown_guard_time_default = SCTP_DEF_MAX_SHUTDOWN_SEC; 1248c2654abSrjs unsigned int sctp_secret_lifetime_default = SCTP_DEFAULT_SECRET_LIFE_SEC; 1258c2654abSrjs unsigned int sctp_rto_max_default = SCTP_RTO_UPPER_BOUND; 1268c2654abSrjs unsigned int sctp_rto_min_default = SCTP_RTO_LOWER_BOUND; 1278c2654abSrjs unsigned int sctp_rto_initial_default = SCTP_RTO_INITIAL; 1288c2654abSrjs unsigned int sctp_init_rto_max_default = SCTP_RTO_UPPER_BOUND; 1298c2654abSrjs unsigned int sctp_valid_cookie_life_default = SCTP_DEFAULT_COOKIE_LIFE; 1308c2654abSrjs unsigned int sctp_init_rtx_max_default = SCTP_DEF_MAX_INIT; 1318c2654abSrjs unsigned int sctp_assoc_rtx_max_default = SCTP_DEF_MAX_SEND; 1328c2654abSrjs unsigned int sctp_path_rtx_max_default = SCTP_DEF_MAX_SEND/2; 1338c2654abSrjs unsigned int sctp_nr_outgoing_streams_default = SCTP_OSTREAM_INITIAL; 1348c2654abSrjs 135ad7c6453Srjs static void sysctl_net_inet_sctp_setup(struct sysctllog **); 136ad7c6453Srjs 1378c2654abSrjs void 1388c2654abSrjs sctp_init(void) 1398c2654abSrjs { 1408c2654abSrjs /* Init the SCTP pcb in sctp_pcb.c */ 1418c2654abSrjs u_long sb_max_adj; 1428c2654abSrjs 143ad7c6453Srjs sysctl_net_inet_sctp_setup(NULL); 144ad7c6453Srjs 1458c2654abSrjs sctp_pcb_init(); 1468c2654abSrjs 1478c2654abSrjs if (nmbclusters > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 1488c2654abSrjs sctp_max_chunks_on_queue = nmbclusters; 1498c2654abSrjs /* 1508c2654abSrjs * Allow a user to take no more than 1/2 the number of clusters 1518c2654abSrjs * or the SB_MAX whichever is smaller for the send window. 1528c2654abSrjs */ 1538c2654abSrjs sb_max_adj = (u_long)((u_quad_t)(SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); 154d1579b2dSriastradh sctp_sendspace = uimin((uimin(SB_MAX, sb_max_adj)), 1558c2654abSrjs ((nmbclusters/2) * SCTP_DEFAULT_MAXSEGMENT)); 1568c2654abSrjs /* 1578c2654abSrjs * Now for the recv window, should we take the same amount? 1588c2654abSrjs * or should I do 1/2 the SB_MAX instead in the SB_MAX min above. 1598c2654abSrjs * For now I will just copy. 1608c2654abSrjs */ 1618c2654abSrjs sctp_recvspace = sctp_sendspace; 1628c2654abSrjs } 1638c2654abSrjs 1648c2654abSrjs #ifdef INET6 1658c2654abSrjs void 1668c2654abSrjs ip_2_ip6_hdr(struct ip6_hdr *ip6, struct ip *ip) 1678c2654abSrjs { 1688c2654abSrjs memset(ip6, 0, sizeof(*ip6)); 1698c2654abSrjs 1708c2654abSrjs ip6->ip6_vfc = IPV6_VERSION; 1718c2654abSrjs ip6->ip6_plen = ip->ip_len; 1728c2654abSrjs ip6->ip6_nxt = ip->ip_p; 1738c2654abSrjs ip6->ip6_hlim = ip->ip_ttl; 1748c2654abSrjs ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] = 1758c2654abSrjs IPV6_ADDR_INT32_SMP; 1768c2654abSrjs ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr; 1778c2654abSrjs ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr; 1788c2654abSrjs } 1798c2654abSrjs #endif /* INET6 */ 1808c2654abSrjs 1818c2654abSrjs static void 1828c2654abSrjs sctp_split_chunks(struct sctp_association *asoc, 1838c2654abSrjs struct sctp_stream_out *strm, 1848c2654abSrjs struct sctp_tmit_chunk *chk) 1858c2654abSrjs { 1868c2654abSrjs struct sctp_tmit_chunk *new_chk; 1878c2654abSrjs 1888c2654abSrjs /* First we need a chunk */ 1898c2654abSrjs new_chk = (struct sctp_tmit_chunk *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_chunk); 1908c2654abSrjs if (new_chk == NULL) { 1918c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 1928c2654abSrjs return; 1938c2654abSrjs } 1948c2654abSrjs sctppcbinfo.ipi_count_chunk++; 1958c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 1968c2654abSrjs /* Copy it all */ 1978c2654abSrjs *new_chk = *chk; 1988c2654abSrjs /* split the data */ 1998c2654abSrjs new_chk->data = m_split(chk->data, (chk->send_size>>1), M_DONTWAIT); 2008c2654abSrjs if (new_chk->data == NULL) { 2018c2654abSrjs /* Can't split */ 2028c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2038c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, new_chk); 2048c2654abSrjs sctppcbinfo.ipi_count_chunk--; 2058c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) { 2068c2654abSrjs panic("Chunk count is negative"); 2078c2654abSrjs } 2088c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++; 2098c2654abSrjs return; 2108c2654abSrjs 2118c2654abSrjs } 2128c2654abSrjs /* Data is now split adjust sizes */ 2138c2654abSrjs chk->send_size >>= 1; 2148c2654abSrjs new_chk->send_size >>= 1; 2158c2654abSrjs 2168c2654abSrjs chk->book_size >>= 1; 2178c2654abSrjs new_chk->book_size >>= 1; 2188c2654abSrjs 2198c2654abSrjs /* now adjust the marks */ 2208c2654abSrjs chk->rec.data.rcv_flags |= SCTP_DATA_FIRST_FRAG; 2218c2654abSrjs chk->rec.data.rcv_flags &= ~SCTP_DATA_LAST_FRAG; 2228c2654abSrjs 2238c2654abSrjs new_chk->rec.data.rcv_flags &= ~SCTP_DATA_FIRST_FRAG; 2248c2654abSrjs new_chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; 2258c2654abSrjs 2268c2654abSrjs /* Increase ref count if dest is set */ 2278c2654abSrjs if (chk->whoTo) { 2288c2654abSrjs new_chk->whoTo->ref_count++; 2298c2654abSrjs } 2308c2654abSrjs /* now drop it on the end of the list*/ 2318c2654abSrjs asoc->stream_queue_cnt++; 2328c2654abSrjs TAILQ_INSERT_AFTER(&strm->outqueue, chk, new_chk, sctp_next); 2338c2654abSrjs } 2348c2654abSrjs 2358c2654abSrjs static void 2368c2654abSrjs sctp_notify_mbuf(struct sctp_inpcb *inp, 2378c2654abSrjs struct sctp_tcb *stcb, 2388c2654abSrjs struct sctp_nets *net, 2398c2654abSrjs struct ip *ip, 2408c2654abSrjs struct sctphdr *sh) 2418c2654abSrjs 2428c2654abSrjs { 2438c2654abSrjs struct icmp *icmph; 2448c2654abSrjs int totsz; 2458c2654abSrjs uint16_t nxtsz; 2468c2654abSrjs 2478c2654abSrjs /* protection */ 2488c2654abSrjs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 2498c2654abSrjs (ip == NULL) || (sh == NULL)) { 2508c2654abSrjs if (stcb != NULL) { 2518c2654abSrjs SCTP_TCB_UNLOCK(stcb); 2528c2654abSrjs } 2538c2654abSrjs return; 2548c2654abSrjs } 2558c2654abSrjs /* First job is to verify the vtag matches what I would send */ 2568c2654abSrjs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 2578c2654abSrjs SCTP_TCB_UNLOCK(stcb); 2588c2654abSrjs return; 2598c2654abSrjs } 2608c2654abSrjs icmph = (struct icmp *)((vaddr_t)ip - (sizeof(struct icmp) - 2618c2654abSrjs sizeof(struct ip))); 2628c2654abSrjs if (icmph->icmp_type != ICMP_UNREACH) { 2638c2654abSrjs /* We only care about unreachable */ 2648c2654abSrjs SCTP_TCB_UNLOCK(stcb); 2658c2654abSrjs return; 2668c2654abSrjs } 2678c2654abSrjs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 2688c2654abSrjs /* not a unreachable message due to frag. */ 2698c2654abSrjs SCTP_TCB_UNLOCK(stcb); 2708c2654abSrjs return; 2718c2654abSrjs } 2728c2654abSrjs totsz = ip->ip_len; 2738c2654abSrjs nxtsz = ntohs(icmph->icmp_seq); 2748c2654abSrjs if (nxtsz == 0) { 2758c2654abSrjs /* 2768c2654abSrjs * old type router that does not tell us what the next size 2778c2654abSrjs * mtu is. Rats we will have to guess (in a educated fashion 2788c2654abSrjs * of course) 2798c2654abSrjs */ 2808c2654abSrjs nxtsz = find_next_best_mtu(totsz); 2818c2654abSrjs } 2828c2654abSrjs 2838c2654abSrjs /* Stop any PMTU timer */ 2848c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 2858c2654abSrjs 2868c2654abSrjs /* Adjust destination size limit */ 2878c2654abSrjs if (net->mtu > nxtsz) { 2888c2654abSrjs net->mtu = nxtsz; 2898c2654abSrjs } 2908c2654abSrjs /* now what about the ep? */ 2918c2654abSrjs if (stcb->asoc.smallest_mtu > nxtsz) { 2928c2654abSrjs struct sctp_tmit_chunk *chk, *nchk; 2938c2654abSrjs struct sctp_stream_out *strm; 2948c2654abSrjs /* Adjust that too */ 2958c2654abSrjs stcb->asoc.smallest_mtu = nxtsz; 2968c2654abSrjs /* now off to subtract IP_DF flag if needed */ 2978c2654abSrjs 2988c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 2998c2654abSrjs if ((chk->send_size+IP_HDR_SIZE) > nxtsz) { 3008c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 3018c2654abSrjs } 3028c2654abSrjs } 3038c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 3048c2654abSrjs if ((chk->send_size+IP_HDR_SIZE) > nxtsz) { 3058c2654abSrjs /* 3068c2654abSrjs * For this guy we also mark for immediate 3078c2654abSrjs * resend since we sent to big of chunk 3088c2654abSrjs */ 3098c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 3108c2654abSrjs if (chk->sent != SCTP_DATAGRAM_RESEND) { 3118c2654abSrjs stcb->asoc.sent_queue_retran_cnt++; 3128c2654abSrjs } 3138c2654abSrjs chk->sent = SCTP_DATAGRAM_RESEND; 3148c2654abSrjs chk->rec.data.doing_fast_retransmit = 0; 3158c2654abSrjs 3168c2654abSrjs /* Clear any time so NO RTT is being done */ 3178c2654abSrjs chk->do_rtt = 0; 3188c2654abSrjs sctp_total_flight_decrease(stcb, chk); 3198c2654abSrjs if (net->flight_size >= chk->book_size) { 3208c2654abSrjs net->flight_size -= chk->book_size; 3218c2654abSrjs } else { 3228c2654abSrjs net->flight_size = 0; 3238c2654abSrjs } 3248c2654abSrjs } 3258c2654abSrjs } 3268c2654abSrjs TAILQ_FOREACH(strm, &stcb->asoc.out_wheel, next_spoke) { 3278c2654abSrjs chk = TAILQ_FIRST(&strm->outqueue); 3288c2654abSrjs while (chk) { 3298c2654abSrjs nchk = TAILQ_NEXT(chk, sctp_next); 3308c2654abSrjs if ((chk->send_size+SCTP_MED_OVERHEAD) > nxtsz) { 3318c2654abSrjs sctp_split_chunks(&stcb->asoc, strm, chk); 3328c2654abSrjs } 3338c2654abSrjs chk = nchk; 3348c2654abSrjs } 3358c2654abSrjs } 3368c2654abSrjs } 3378c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 3388c2654abSrjs SCTP_TCB_UNLOCK(stcb); 3398c2654abSrjs } 3408c2654abSrjs 3418c2654abSrjs 3428c2654abSrjs void 3438c2654abSrjs sctp_notify(struct sctp_inpcb *inp, 3448c2654abSrjs int errno, 3458c2654abSrjs struct sctphdr *sh, 3468c2654abSrjs struct sockaddr *to, 3478c2654abSrjs struct sctp_tcb *stcb, 3488c2654abSrjs struct sctp_nets *net) 3498c2654abSrjs { 3508c2654abSrjs /* protection */ 3518c2654abSrjs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 3528c2654abSrjs (sh == NULL) || (to == NULL)) { 3538c2654abSrjs #ifdef SCTP_DEBUG 3548c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 3558c2654abSrjs printf("sctp-notify, bad call\n"); 3568c2654abSrjs } 3578c2654abSrjs #endif /* SCTP_DEBUG */ 3588c2654abSrjs return; 3598c2654abSrjs } 3608c2654abSrjs /* First job is to verify the vtag matches what I would send */ 3618c2654abSrjs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 3628c2654abSrjs return; 3638c2654abSrjs } 3648c2654abSrjs 3658c2654abSrjs /* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */ 3668c2654abSrjs 3678c2654abSrjs if ((errno == EHOSTUNREACH) || /* Host is not reachable */ 3688c2654abSrjs (errno == EHOSTDOWN) || /* Host is down */ 3698c2654abSrjs (errno == ECONNREFUSED) || /* Host refused the connection, (not an abort?) */ 3708c2654abSrjs (errno == ENOPROTOOPT) /* SCTP is not present on host */ 3718c2654abSrjs ) { 3728c2654abSrjs /* 3736478b405Sandvar * Hmm reachability problems we must examine closely. 3748c2654abSrjs * If its not reachable, we may have lost a network. 3758c2654abSrjs * Or if there is NO protocol at the other end named SCTP. 3768c2654abSrjs * well we consider it a OOTB abort. 3778c2654abSrjs */ 3788c2654abSrjs if ((errno == EHOSTUNREACH) || (errno == EHOSTDOWN)) { 3798c2654abSrjs if (net->dest_state & SCTP_ADDR_REACHABLE) { 3808c2654abSrjs /* Ok that destination is NOT reachable */ 3818c2654abSrjs net->dest_state &= ~SCTP_ADDR_REACHABLE; 3828c2654abSrjs net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 3838c2654abSrjs net->error_count = net->failure_threshold + 1; 3848c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 3858c2654abSrjs stcb, SCTP_FAILED_THRESHOLD, 3868c2654abSrjs (void *)net); 3878c2654abSrjs } 3888c2654abSrjs if (stcb) { 3898c2654abSrjs SCTP_TCB_UNLOCK(stcb); 3908c2654abSrjs } 3918c2654abSrjs } else { 3928c2654abSrjs /* 3938c2654abSrjs * Here the peer is either playing tricks on us, 3948c2654abSrjs * including an address that belongs to someone who 3958c2654abSrjs * does not support SCTP OR was a userland 3968c2654abSrjs * implementation that shutdown and now is dead. In 3978c2654abSrjs * either case treat it like a OOTB abort with no TCB 3988c2654abSrjs */ 3998c2654abSrjs sctp_abort_notification(stcb, SCTP_PEER_FAULTY); 4008c2654abSrjs sctp_free_assoc(inp, stcb); 4018c2654abSrjs /* no need to unlock here, since the TCB is gone */ 4028c2654abSrjs } 4038c2654abSrjs } else { 4048c2654abSrjs /* Send all others to the app */ 4058c2654abSrjs if (inp->sctp_socket) { 4068c2654abSrjs inp->sctp_socket->so_error = errno; 4078c2654abSrjs sctp_sowwakeup(inp, inp->sctp_socket); 4088c2654abSrjs } 4098c2654abSrjs if (stcb) { 4108c2654abSrjs SCTP_TCB_UNLOCK(stcb); 4118c2654abSrjs } 4128c2654abSrjs } 4138c2654abSrjs } 4148c2654abSrjs 4158c2654abSrjs void * 4168c2654abSrjs sctp_ctlinput(int cmd, const struct sockaddr *sa, void *vip) 4178c2654abSrjs { 4188c2654abSrjs struct ip *ip = vip; 4198c2654abSrjs struct sctphdr *sh; 4208c2654abSrjs int s; 4218c2654abSrjs 4228c2654abSrjs if (sa->sa_family != AF_INET || 4238c2654abSrjs ((const struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 4248c2654abSrjs return (NULL); 4258c2654abSrjs } 4268c2654abSrjs 4278c2654abSrjs if (PRC_IS_REDIRECT(cmd)) { 4288c2654abSrjs ip = 0; 4298c2654abSrjs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 4308c2654abSrjs return (NULL); 4318c2654abSrjs } 4328c2654abSrjs if (ip) { 4338c2654abSrjs struct sctp_inpcb *inp; 4348c2654abSrjs struct sctp_tcb *stcb; 4358c2654abSrjs struct sctp_nets *net; 4368c2654abSrjs struct sockaddr_in to, from; 4378c2654abSrjs 4388c2654abSrjs sh = (struct sctphdr *)((vaddr_t)ip + (ip->ip_hl << 2)); 4398c2654abSrjs memset(&to, 0, sizeof(to)); 4408c2654abSrjs memset(&from, 0, sizeof(from)); 4418c2654abSrjs from.sin_family = to.sin_family = AF_INET; 4428c2654abSrjs from.sin_len = to.sin_len = sizeof(to); 4438c2654abSrjs from.sin_port = sh->src_port; 4448c2654abSrjs from.sin_addr = ip->ip_src; 4458c2654abSrjs to.sin_port = sh->dest_port; 4468c2654abSrjs to.sin_addr = ip->ip_dst; 4478c2654abSrjs 4488c2654abSrjs /* 4498c2654abSrjs * 'to' holds the dest of the packet that failed to be sent. 4508c2654abSrjs * 'from' holds our local endpoint address. 4518c2654abSrjs * Thus we reverse the to and the from in the lookup. 4528c2654abSrjs */ 4538c2654abSrjs s = splsoftnet(); 4548c2654abSrjs stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from, 4558c2654abSrjs (struct sockaddr *)&to, 4568c2654abSrjs &inp, &net, 1); 4578c2654abSrjs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 4588c2654abSrjs if (cmd != PRC_MSGSIZE) { 4598c2654abSrjs int cm; 4608c2654abSrjs if (cmd == PRC_HOSTDEAD) { 4618c2654abSrjs cm = EHOSTUNREACH; 4628c2654abSrjs } else { 4638c2654abSrjs cm = inetctlerrmap[cmd]; 4648c2654abSrjs } 4658c2654abSrjs sctp_notify(inp, cm, sh, 4668c2654abSrjs (struct sockaddr *)&to, stcb, 4678c2654abSrjs net); 4688c2654abSrjs } else { 4698c2654abSrjs /* handle possible ICMP size messages */ 4708c2654abSrjs sctp_notify_mbuf(inp, stcb, net, ip, sh); 4718c2654abSrjs } 4728c2654abSrjs } else { 4738c2654abSrjs #if defined(__FreeBSD__) && __FreeBSD_version < 500000 4748c2654abSrjs /* XXX must be fixed for 5.x and higher, leave for 4.x */ 4758c2654abSrjs if (PRC_IS_REDIRECT(cmd) && inp) { 4762ba9f052Sozaki-r inpcb_rtchange((struct inpcb *)inp, 4778c2654abSrjs inetctlerrmap[cmd]); 4788c2654abSrjs } 4798c2654abSrjs #endif 4808c2654abSrjs if ((stcb == NULL) && (inp != NULL)) { 4818c2654abSrjs /* reduce ref-count */ 4828c2654abSrjs SCTP_INP_WLOCK(inp); 4838c2654abSrjs SCTP_INP_DECR_REF(inp); 4848c2654abSrjs SCTP_INP_WUNLOCK(inp); 4858c2654abSrjs } 4868c2654abSrjs 4878c2654abSrjs } 4888c2654abSrjs splx(s); 4898c2654abSrjs } 4908c2654abSrjs return (NULL); 4918c2654abSrjs } 4928c2654abSrjs 4938c2654abSrjs static int 4948c2654abSrjs sctp_abort(struct socket *so) 4958c2654abSrjs { 4968c2654abSrjs struct sctp_inpcb *inp; 4978c2654abSrjs 4988c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 4998c2654abSrjs if (inp == 0) 5008c2654abSrjs return EINVAL; /* ??? possible? panic instead? */ 5018c2654abSrjs 5028c2654abSrjs sctp_inpcb_free(inp, 1); 5038c2654abSrjs return 0; 5048c2654abSrjs } 5058c2654abSrjs 5068c2654abSrjs static int 5078c2654abSrjs sctp_attach(struct socket *so, int proto) 5088c2654abSrjs { 5098c2654abSrjs struct sctp_inpcb *inp; 5108c2654abSrjs #ifdef IPSEC 5118c2654abSrjs struct inpcb *ip_inp; 5128c2654abSrjs #endif 5138c2654abSrjs int error; 5148c2654abSrjs 5158c2654abSrjs sosetlock(so); 5168c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 5178c2654abSrjs if (inp != 0) { 5188c2654abSrjs return EINVAL; 5198c2654abSrjs } 5208c2654abSrjs error = soreserve(so, sctp_sendspace, sctp_recvspace); 5218c2654abSrjs if (error) { 5228c2654abSrjs return error; 5238c2654abSrjs } 5248c2654abSrjs error = sctp_inpcb_alloc(so); 5258c2654abSrjs if (error) { 5268c2654abSrjs return error; 5278c2654abSrjs } 5288c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 5298c2654abSrjs SCTP_INP_WLOCK(inp); 5308c2654abSrjs 5318c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 5328c2654abSrjs #ifdef IPSEC 5338c2654abSrjs ip_inp = &inp->ip_inp.inp; 53401b82b52Srjs ip_inp->inp_af = proto; 5358c2654abSrjs #endif 5368c2654abSrjs inp->inp_vflag |= INP_IPV4; 5378c2654abSrjs inp->inp_ip_ttl = ip_defttl; 5388c2654abSrjs 5398c2654abSrjs #ifdef IPSEC 5408c2654abSrjs error = ipsec_init_pcbpolicy(so, &ip_inp->inp_sp); 5418c2654abSrjs if (error != 0) { 5428c2654abSrjs sctp_inpcb_free(inp, 1); 5438c2654abSrjs return error; 5448c2654abSrjs } 5458c2654abSrjs #endif /*IPSEC*/ 5468c2654abSrjs SCTP_INP_WUNLOCK(inp); 5478c2654abSrjs so->so_send = sctp_sosend; 5488c2654abSrjs return 0; 5498c2654abSrjs } 5508c2654abSrjs 5518c2654abSrjs static int 5528c2654abSrjs sctp_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 5538c2654abSrjs { 5548c2654abSrjs struct sctp_inpcb *inp; 5558c2654abSrjs int error; 5568c2654abSrjs 5578c2654abSrjs KASSERT(solocked(so)); 5588c2654abSrjs 5598c2654abSrjs #ifdef INET6 5608c2654abSrjs if (nam && nam->sa_family != AF_INET) 5618c2654abSrjs /* must be a v4 address! */ 5628c2654abSrjs return EINVAL; 5638c2654abSrjs #endif /* INET6 */ 5648c2654abSrjs 5658c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 5668c2654abSrjs if (inp == 0) 5678c2654abSrjs return EINVAL; 5688c2654abSrjs 5698c2654abSrjs error = sctp_inpcb_bind(so, nam, l); 5708c2654abSrjs return error; 5718c2654abSrjs } 5728c2654abSrjs 5738c2654abSrjs 5748c2654abSrjs static int 5758c2654abSrjs sctp_detach(struct socket *so) 5768c2654abSrjs { 5778c2654abSrjs struct sctp_inpcb *inp; 578ff49eadeSrjs 5798c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 5808c2654abSrjs if (inp == 0) 5818c2654abSrjs return EINVAL; 5828c2654abSrjs 5838c2654abSrjs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 5848c2654abSrjs (so->so_rcv.sb_cc > 0)) { 5858c2654abSrjs sctp_inpcb_free(inp, 1); 5868c2654abSrjs } else { 5878c2654abSrjs sctp_inpcb_free(inp, 0); 5888c2654abSrjs } 5898c2654abSrjs return 0; 5908c2654abSrjs } 5918c2654abSrjs 5928c2654abSrjs static int 5938c2654abSrjs sctp_recvoob(struct socket *so, struct mbuf *m, int flags) 5948c2654abSrjs { 5958c2654abSrjs KASSERT(solocked(so)); 5968c2654abSrjs 5978c2654abSrjs return EOPNOTSUPP; 5988c2654abSrjs } 5998c2654abSrjs 6008c2654abSrjs int 6018c2654abSrjs sctp_send(struct socket *so, struct mbuf *m, struct sockaddr *addr, 6028c2654abSrjs struct mbuf *control, struct lwp *l) 6038c2654abSrjs { 6048c2654abSrjs struct sctp_inpcb *inp; 6058c2654abSrjs int error; 6068c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 6078c2654abSrjs if (inp == 0) { 6088c2654abSrjs sctp_m_freem(control); 6098c2654abSrjs control = NULL; 6108c2654abSrjs sctp_m_freem(m); 6118c2654abSrjs return EINVAL; 6128c2654abSrjs } 6135b28f239Srillig /* Got to have a to address if we are NOT a connected socket */ 6148c2654abSrjs if ((addr == NULL) && 6158c2654abSrjs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 6168c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) 6178c2654abSrjs ) { 6188c2654abSrjs goto connected_type; 6198c2654abSrjs } else if (addr == NULL) { 6208c2654abSrjs error = EDESTADDRREQ; 6218c2654abSrjs sctp_m_freem(m); 6228c2654abSrjs sctp_m_freem(control); 6238c2654abSrjs control = NULL; 6248c2654abSrjs return (error); 6258c2654abSrjs } 6268c2654abSrjs #ifdef INET6 6278c2654abSrjs if (addr->sa_family != AF_INET) { 6288c2654abSrjs /* must be a v4 address! */ 6298c2654abSrjs sctp_m_freem(m); 6308c2654abSrjs sctp_m_freem(control); 6318c2654abSrjs control = NULL; 6328c2654abSrjs error = EDESTADDRREQ; 6338c2654abSrjs return EINVAL; 6348c2654abSrjs } 6358c2654abSrjs #endif /* INET6 */ 636d020c71cSmaxv 637d020c71cSmaxv /* 638d020c71cSmaxv * XXX XXX XXX Check addr->sa_len? 639d020c71cSmaxv */ 640d020c71cSmaxv 6418c2654abSrjs connected_type: 6428c2654abSrjs /* now what about control */ 6438c2654abSrjs if (control) { 6448c2654abSrjs if (inp->control) { 6458c2654abSrjs printf("huh? control set?\n"); 6468c2654abSrjs sctp_m_freem(inp->control); 6478c2654abSrjs inp->control = NULL; 6488c2654abSrjs } 6498c2654abSrjs inp->control = control; 6508c2654abSrjs } 6518c2654abSrjs /* add it in possibly */ 6528c2654abSrjs if ((inp->pkt) && (inp->pkt->m_flags & M_PKTHDR)) { 6538c2654abSrjs struct mbuf *x; 6548c2654abSrjs int c_len; 6558c2654abSrjs 6568c2654abSrjs c_len = 0; 6578c2654abSrjs /* How big is it */ 6588c2654abSrjs for (x=m;x;x = x->m_next) { 6598c2654abSrjs c_len += x->m_len; 6608c2654abSrjs } 6618c2654abSrjs inp->pkt->m_pkthdr.len += c_len; 6628c2654abSrjs } 6638c2654abSrjs /* Place the data */ 6648c2654abSrjs if (inp->pkt) { 6658c2654abSrjs inp->pkt_last->m_next = m; 6668c2654abSrjs inp->pkt_last = m; 6678c2654abSrjs } else { 6688c2654abSrjs inp->pkt_last = inp->pkt = m; 6698c2654abSrjs } 6708c2654abSrjs if ((so->so_state & SS_MORETOCOME) == 0) { 6718c2654abSrjs /* 6728c2654abSrjs * note with the current version this code will only be used 6738c2654abSrjs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 6748c2654abSrjs * re-defining sosend to use the sctp_sosend. One can 6758c2654abSrjs * optionally switch back to this code (by changing back the 6768c2654abSrjs * definitions) but this is not advisable. 6778c2654abSrjs */ 6788c2654abSrjs int ret; 6798c2654abSrjs ret = sctp_output(inp, inp->pkt, addr, inp->control, l, 0); 6808c2654abSrjs inp->pkt = NULL; 6818c2654abSrjs inp->control = NULL; 6828c2654abSrjs return (ret); 6838c2654abSrjs } else { 6848c2654abSrjs return (0); 6858c2654abSrjs } 6868c2654abSrjs } 6878c2654abSrjs 6888c2654abSrjs static int 6898c2654abSrjs sctp_disconnect(struct socket *so) 6908c2654abSrjs { 6918c2654abSrjs struct sctp_inpcb *inp; 692ff49eadeSrjs int s; 6938c2654abSrjs 6948c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 6958c2654abSrjs if (inp == NULL) { 6968c2654abSrjs return (ENOTCONN); 6978c2654abSrjs } 698ff49eadeSrjs s = splsoftnet(); 6998c2654abSrjs SCTP_INP_RLOCK(inp); 7008c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 7018c2654abSrjs if (LIST_EMPTY(&inp->sctp_asoc_list)) { 7028c2654abSrjs /* No connection */ 7038c2654abSrjs SCTP_INP_RUNLOCK(inp); 704ff49eadeSrjs splx(s); 7058c2654abSrjs return (0); 7068c2654abSrjs } else { 7078c2654abSrjs int some_on_streamwheel = 0; 7088c2654abSrjs struct sctp_association *asoc; 7098c2654abSrjs struct sctp_tcb *stcb; 7108c2654abSrjs 7118c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 7128c2654abSrjs if (stcb == NULL) { 7138c2654abSrjs SCTP_INP_RUNLOCK(inp); 714ff49eadeSrjs splx(s); 7158c2654abSrjs return (EINVAL); 7168c2654abSrjs } 7178c2654abSrjs asoc = &stcb->asoc; 7188c2654abSrjs SCTP_TCB_LOCK(stcb); 7198c2654abSrjs if (((so->so_options & SO_LINGER) && 7208c2654abSrjs (so->so_linger == 0)) || 7218c2654abSrjs (so->so_rcv.sb_cc > 0)) { 7228c2654abSrjs if (SCTP_GET_STATE(asoc) != 7238c2654abSrjs SCTP_STATE_COOKIE_WAIT) { 7248c2654abSrjs /* Left with Data unread */ 7258c2654abSrjs struct mbuf *err; 7268c2654abSrjs err = NULL; 7278c2654abSrjs MGET(err, M_DONTWAIT, MT_DATA); 7288c2654abSrjs if (err) { 7298c2654abSrjs /* Fill in the user initiated abort */ 7308c2654abSrjs struct sctp_paramhdr *ph; 7318c2654abSrjs ph = mtod(err, struct sctp_paramhdr *); 7328c2654abSrjs err->m_len = sizeof(struct sctp_paramhdr); 7338c2654abSrjs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 7348c2654abSrjs ph->param_length = htons(err->m_len); 7358c2654abSrjs } 7368c2654abSrjs sctp_send_abort_tcb(stcb, err); 7378c2654abSrjs } 7388c2654abSrjs SCTP_INP_RUNLOCK(inp); 7398c2654abSrjs sctp_free_assoc(inp, stcb); 7408c2654abSrjs /* No unlock tcb assoc is gone */ 741ff49eadeSrjs splx(s); 7428c2654abSrjs return (0); 7438c2654abSrjs } 7448c2654abSrjs if (!TAILQ_EMPTY(&asoc->out_wheel)) { 7458c2654abSrjs /* Check to see if some data queued */ 7468c2654abSrjs struct sctp_stream_out *outs; 7478c2654abSrjs TAILQ_FOREACH(outs, &asoc->out_wheel, 7488c2654abSrjs next_spoke) { 7498c2654abSrjs if (!TAILQ_EMPTY(&outs->outqueue)) { 7508c2654abSrjs some_on_streamwheel = 1; 7518c2654abSrjs break; 7528c2654abSrjs } 7538c2654abSrjs } 7548c2654abSrjs } 7558c2654abSrjs 7568c2654abSrjs if (TAILQ_EMPTY(&asoc->send_queue) && 7578c2654abSrjs TAILQ_EMPTY(&asoc->sent_queue) && 7588c2654abSrjs (some_on_streamwheel == 0)) { 7598c2654abSrjs /* there is nothing queued to send, so done */ 7608c2654abSrjs if ((SCTP_GET_STATE(asoc) != 7618c2654abSrjs SCTP_STATE_SHUTDOWN_SENT) && 7628c2654abSrjs (SCTP_GET_STATE(asoc) != 7638c2654abSrjs SCTP_STATE_SHUTDOWN_ACK_SENT)) { 7648c2654abSrjs /* only send SHUTDOWN 1st time thru */ 7658c2654abSrjs #ifdef SCTP_DEBUG 7668c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { 7678c2654abSrjs printf("%s:%d sends a shutdown\n", 7688c2654abSrjs __FILE__, 7698c2654abSrjs __LINE__ 7708c2654abSrjs ); 7718c2654abSrjs } 7728c2654abSrjs #endif 7738c2654abSrjs sctp_send_shutdown(stcb, 7748c2654abSrjs stcb->asoc.primary_destination); 7758c2654abSrjs sctp_chunk_output(stcb->sctp_ep, stcb, 1); 7768c2654abSrjs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 7778c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 7788c2654abSrjs stcb->sctp_ep, stcb, 7798c2654abSrjs asoc->primary_destination); 7808c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 7818c2654abSrjs stcb->sctp_ep, stcb, 7828c2654abSrjs asoc->primary_destination); 7838c2654abSrjs } 7848c2654abSrjs } else { 7858c2654abSrjs /* 7868c2654abSrjs * we still got (or just got) data to send, 7878c2654abSrjs * so set SHUTDOWN_PENDING 7888c2654abSrjs */ 7898c2654abSrjs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 7908c2654abSrjs } 7918c2654abSrjs SCTP_TCB_UNLOCK(stcb); 7928c2654abSrjs SCTP_INP_RUNLOCK(inp); 793ff49eadeSrjs splx(s); 7948c2654abSrjs return (0); 7958c2654abSrjs } 7968c2654abSrjs /* not reached */ 7978c2654abSrjs } else { 7988c2654abSrjs /* UDP model does not support this */ 7998c2654abSrjs SCTP_INP_RUNLOCK(inp); 800ff49eadeSrjs splx(s); 8018c2654abSrjs return EOPNOTSUPP; 8028c2654abSrjs } 8038c2654abSrjs } 8048c2654abSrjs 8058c2654abSrjs int 8068c2654abSrjs sctp_shutdown(struct socket *so) 8078c2654abSrjs { 8088c2654abSrjs struct sctp_inpcb *inp; 8098c2654abSrjs 8108c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 8118c2654abSrjs if (inp == 0) { 8128c2654abSrjs return EINVAL; 8138c2654abSrjs } 8148c2654abSrjs SCTP_INP_RLOCK(inp); 8158c2654abSrjs /* For UDP model this is a invalid call */ 8168c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 8178c2654abSrjs /* Restore the flags that the soshutdown took away. */ 8188c2654abSrjs so->so_state &= ~SS_CANTRCVMORE; 8198c2654abSrjs /* This proc will wakeup for read and do nothing (I hope) */ 8208c2654abSrjs SCTP_INP_RUNLOCK(inp); 8218c2654abSrjs return (EOPNOTSUPP); 8228c2654abSrjs } 8238c2654abSrjs /* 8248c2654abSrjs * Ok if we reach here its the TCP model and it is either a SHUT_WR 8258c2654abSrjs * or SHUT_RDWR. This means we put the shutdown flag against it. 8268c2654abSrjs */ 8278c2654abSrjs { 8288c2654abSrjs int some_on_streamwheel = 0; 8298c2654abSrjs struct sctp_tcb *stcb; 8308c2654abSrjs struct sctp_association *asoc; 8318c2654abSrjs socantsendmore(so); 8328c2654abSrjs 8338c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 8348c2654abSrjs if (stcb == NULL) { 8358c2654abSrjs /* 8368c2654abSrjs * Ok we hit the case that the shutdown call was made 8378c2654abSrjs * after an abort or something. Nothing to do now. 8388c2654abSrjs */ 8398c2654abSrjs return (0); 8408c2654abSrjs } 8418c2654abSrjs SCTP_TCB_LOCK(stcb); 8428c2654abSrjs asoc = &stcb->asoc; 8438c2654abSrjs 8448c2654abSrjs if (!TAILQ_EMPTY(&asoc->out_wheel)) { 8458c2654abSrjs /* Check to see if some data queued */ 8468c2654abSrjs struct sctp_stream_out *outs; 8478c2654abSrjs TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { 8488c2654abSrjs if (!TAILQ_EMPTY(&outs->outqueue)) { 8498c2654abSrjs some_on_streamwheel = 1; 8508c2654abSrjs break; 8518c2654abSrjs } 8528c2654abSrjs } 8538c2654abSrjs } 8548c2654abSrjs if (TAILQ_EMPTY(&asoc->send_queue) && 8558c2654abSrjs TAILQ_EMPTY(&asoc->sent_queue) && 8568c2654abSrjs (some_on_streamwheel == 0)) { 8578c2654abSrjs /* there is nothing queued to send, so I'm done... */ 8588c2654abSrjs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 8598c2654abSrjs /* only send SHUTDOWN the first time through */ 8608c2654abSrjs #ifdef SCTP_DEBUG 8618c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { 8628c2654abSrjs printf("%s:%d sends a shutdown\n", 8638c2654abSrjs __FILE__, 8648c2654abSrjs __LINE__ 8658c2654abSrjs ); 8668c2654abSrjs } 8678c2654abSrjs #endif 8688c2654abSrjs sctp_send_shutdown(stcb, 8698c2654abSrjs stcb->asoc.primary_destination); 8708c2654abSrjs sctp_chunk_output(stcb->sctp_ep, stcb, 1); 8718c2654abSrjs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 8728c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 8738c2654abSrjs stcb->sctp_ep, stcb, 8748c2654abSrjs asoc->primary_destination); 8758c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 8768c2654abSrjs stcb->sctp_ep, stcb, 8778c2654abSrjs asoc->primary_destination); 8788c2654abSrjs } 8798c2654abSrjs } else { 8808c2654abSrjs /* 8818c2654abSrjs * we still got (or just got) data to send, so 8828c2654abSrjs * set SHUTDOWN_PENDING 8838c2654abSrjs */ 8848c2654abSrjs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 8858c2654abSrjs } 8868c2654abSrjs SCTP_TCB_UNLOCK(stcb); 8878c2654abSrjs } 8888c2654abSrjs SCTP_INP_RUNLOCK(inp); 8898c2654abSrjs return 0; 8908c2654abSrjs } 8918c2654abSrjs 8928c2654abSrjs /* 8938c2654abSrjs * copies a "user" presentable address and removes embedded scope, etc. 8948c2654abSrjs * returns 0 on success, 1 on error 8958c2654abSrjs */ 8968c2654abSrjs static uint32_t 8978c2654abSrjs sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 8988c2654abSrjs { 8998c2654abSrjs struct sockaddr_in6 lsa6; 9008c2654abSrjs 9018c2654abSrjs sctp_recover_scope((struct sockaddr_in6 *)sa, &lsa6); 9028c2654abSrjs memcpy(ss, sa, sa->sa_len); 9038c2654abSrjs return (0); 9048c2654abSrjs } 9058c2654abSrjs 9068c2654abSrjs 9078c2654abSrjs static int 9088c2654abSrjs sctp_fill_up_addresses(struct sctp_inpcb *inp, 9098c2654abSrjs struct sctp_tcb *stcb, 9108c2654abSrjs int limit, 9118c2654abSrjs struct sockaddr_storage *sas) 9128c2654abSrjs { 9138c2654abSrjs struct ifnet *ifn; 9148c2654abSrjs struct ifaddr *ifa; 9158c2654abSrjs int loopback_scope, ipv4_local_scope, local_scope, site_scope, actual; 9168c2654abSrjs int ipv4_addr_legal, ipv6_addr_legal; 9178c2654abSrjs actual = 0; 9188c2654abSrjs if (limit <= 0) 9198c2654abSrjs return (actual); 9208c2654abSrjs 9218c2654abSrjs if (stcb) { 9228c2654abSrjs /* Turn on all the appropriate scope */ 9238c2654abSrjs loopback_scope = stcb->asoc.loopback_scope; 9248c2654abSrjs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 9258c2654abSrjs local_scope = stcb->asoc.local_scope; 9268c2654abSrjs site_scope = stcb->asoc.site_scope; 9278c2654abSrjs } else { 9288c2654abSrjs /* Turn on ALL scope, since we look at the EP */ 9298c2654abSrjs loopback_scope = ipv4_local_scope = local_scope = 9308c2654abSrjs site_scope = 1; 9318c2654abSrjs } 9328c2654abSrjs ipv4_addr_legal = ipv6_addr_legal = 0; 9338c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 9348c2654abSrjs ipv6_addr_legal = 1; 9358c2654abSrjs if ( 9368c2654abSrjs #if defined(__OpenBSD__) 9378c2654abSrjs (0) /* we always do dual bind */ 9388c2654abSrjs #elif defined (__NetBSD__) 9398c2654abSrjs (((struct in6pcb *)inp)->in6p_flags & IN6P_IPV6_V6ONLY) 9408c2654abSrjs #else 9418c2654abSrjs (((struct in6pcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY) 9428c2654abSrjs #endif 9438c2654abSrjs == 0) { 9448c2654abSrjs ipv4_addr_legal = 1; 9458c2654abSrjs } 9468c2654abSrjs } else { 9478c2654abSrjs ipv4_addr_legal = 1; 9488c2654abSrjs } 9498c2654abSrjs 9508c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 951040205aeSozaki-r int s = pserialize_read_enter(); 952040205aeSozaki-r IFNET_READER_FOREACH(ifn) { 9538c2654abSrjs if ((loopback_scope == 0) && 9548c2654abSrjs (ifn->if_type == IFT_LOOP)) { 9558c2654abSrjs /* Skip loopback if loopback_scope not set */ 9568c2654abSrjs continue; 9578c2654abSrjs } 9589e4c2bdaSozaki-r IFADDR_READER_FOREACH(ifa, ifn) { 9598c2654abSrjs if (stcb) { 9608c2654abSrjs /* 9618c2654abSrjs * For the BOUND-ALL case, the list 9628c2654abSrjs * associated with a TCB is Always 9638c2654abSrjs * considered a reverse list.. i.e. 9648c2654abSrjs * it lists addresses that are NOT 9658c2654abSrjs * part of the association. If this 9668c2654abSrjs * is one of those we must skip it. 9678c2654abSrjs */ 9688c2654abSrjs if (sctp_is_addr_restricted(stcb, 9698c2654abSrjs ifa->ifa_addr)) { 9708c2654abSrjs continue; 9718c2654abSrjs } 9728c2654abSrjs } 9738c2654abSrjs if ((ifa->ifa_addr->sa_family == AF_INET) && 9748c2654abSrjs (ipv4_addr_legal)) { 9758c2654abSrjs struct sockaddr_in *sin; 9768c2654abSrjs sin = (struct sockaddr_in *)ifa->ifa_addr; 9778c2654abSrjs if (sin->sin_addr.s_addr == 0) { 978100a3398Sandvar /* we skip unspecified addresses */ 9798c2654abSrjs continue; 9808c2654abSrjs } 9818c2654abSrjs if ((ipv4_local_scope == 0) && 9828c2654abSrjs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 9838c2654abSrjs continue; 9848c2654abSrjs } 9858c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) { 9868c2654abSrjs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 9878c2654abSrjs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 9888c2654abSrjs sas = (struct sockaddr_storage *)((vaddr_t)sas + sizeof(struct sockaddr_in6)); 9897273e27bSchristos actual += sizeof(struct sockaddr_in6); 9908c2654abSrjs } else { 9918c2654abSrjs memcpy(sas, sin, sizeof(*sin)); 9928c2654abSrjs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 9938c2654abSrjs sas = (struct sockaddr_storage *)((vaddr_t)sas + sizeof(*sin)); 9948c2654abSrjs actual += sizeof(*sin); 9958c2654abSrjs } 9968c2654abSrjs if (actual >= limit) { 997040205aeSozaki-r pserialize_read_exit(s); 9988c2654abSrjs return (actual); 9998c2654abSrjs } 10008c2654abSrjs } else if ((ifa->ifa_addr->sa_family == AF_INET6) && 10018c2654abSrjs (ipv6_addr_legal)) { 10028c2654abSrjs struct sockaddr_in6 *sin6; 10038c2654abSrjs sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 10048c2654abSrjs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 10058c2654abSrjs /* 10068c2654abSrjs * we skip unspecified 10078c2654abSrjs * addresses 10088c2654abSrjs */ 10098c2654abSrjs continue; 10108c2654abSrjs } 10118c2654abSrjs if ((site_scope == 0) && 10128c2654abSrjs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 10138c2654abSrjs continue; 10148c2654abSrjs } 10158c2654abSrjs memcpy(sas, sin6, sizeof(*sin6)); 10168c2654abSrjs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 10178c2654abSrjs sas = (struct sockaddr_storage *)((vaddr_t)sas + sizeof(*sin6)); 10188c2654abSrjs actual += sizeof(*sin6); 10198c2654abSrjs if (actual >= limit) { 1020040205aeSozaki-r pserialize_read_exit(s); 10218c2654abSrjs return (actual); 10228c2654abSrjs } 10238c2654abSrjs } 10248c2654abSrjs } 10258c2654abSrjs } 1026040205aeSozaki-r pserialize_read_exit(s); 10278c2654abSrjs } else { 10288c2654abSrjs struct sctp_laddr *laddr; 10298c2654abSrjs /* 10308c2654abSrjs * If we have a TCB and we do NOT support ASCONF (it's 10318c2654abSrjs * turned off or otherwise) then the list is always the 10328c2654abSrjs * true list of addresses (the else case below). Otherwise 10338c2654abSrjs * the list on the association is a list of addresses that 10348c2654abSrjs * are NOT part of the association. 10358c2654abSrjs */ 10368c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_DO_ASCONF) { 10378c2654abSrjs /* The list is a NEGATIVE list */ 10388c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 10398c2654abSrjs if (stcb) { 10408c2654abSrjs if (sctp_is_addr_restricted(stcb, laddr->ifa->ifa_addr)) { 10418c2654abSrjs continue; 10428c2654abSrjs } 10438c2654abSrjs } 10448c2654abSrjs if (sctp_fill_user_address(sas, laddr->ifa->ifa_addr)) 10458c2654abSrjs continue; 10468c2654abSrjs 10478c2654abSrjs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 10488c2654abSrjs sas = (struct sockaddr_storage *)((vaddr_t)sas + 10498c2654abSrjs laddr->ifa->ifa_addr->sa_len); 10508c2654abSrjs actual += laddr->ifa->ifa_addr->sa_len; 10518c2654abSrjs if (actual >= limit) { 10528c2654abSrjs return (actual); 10538c2654abSrjs } 10548c2654abSrjs } 10558c2654abSrjs } else { 10568c2654abSrjs /* The list is a positive list if present */ 10578c2654abSrjs if (stcb) { 10588c2654abSrjs /* Must use the specific association list */ 10598c2654abSrjs LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, 10608c2654abSrjs sctp_nxt_addr) { 10618c2654abSrjs if (sctp_fill_user_address(sas, 10628c2654abSrjs laddr->ifa->ifa_addr)) 10638c2654abSrjs continue; 10648c2654abSrjs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 10658c2654abSrjs sas = (struct sockaddr_storage *)((vaddr_t)sas + 10668c2654abSrjs laddr->ifa->ifa_addr->sa_len); 10678c2654abSrjs actual += laddr->ifa->ifa_addr->sa_len; 10688c2654abSrjs if (actual >= limit) { 10698c2654abSrjs return (actual); 10708c2654abSrjs } 10718c2654abSrjs } 10728c2654abSrjs } else { 10738c2654abSrjs /* No endpoint so use the endpoints individual list */ 10748c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, 10758c2654abSrjs sctp_nxt_addr) { 10768c2654abSrjs if (sctp_fill_user_address(sas, 10778c2654abSrjs laddr->ifa->ifa_addr)) 10788c2654abSrjs continue; 10798c2654abSrjs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 10808c2654abSrjs sas = (struct sockaddr_storage *)((vaddr_t)sas + 10818c2654abSrjs laddr->ifa->ifa_addr->sa_len); 10828c2654abSrjs actual += laddr->ifa->ifa_addr->sa_len; 10838c2654abSrjs if (actual >= limit) { 10848c2654abSrjs return (actual); 10858c2654abSrjs } 10868c2654abSrjs } 10878c2654abSrjs } 10888c2654abSrjs } 10898c2654abSrjs } 10908c2654abSrjs return (actual); 10918c2654abSrjs } 10928c2654abSrjs 10938c2654abSrjs static int 10948c2654abSrjs sctp_count_max_addresses(struct sctp_inpcb *inp) 10958c2654abSrjs { 10968c2654abSrjs int cnt = 0; 10978c2654abSrjs /* 10985b28f239Srillig * In both sub-set bound and bound_all cases we return the MAXIMUM 10998c2654abSrjs * number of addresses that you COULD get. In reality the sub-set 11008c2654abSrjs * bound may have an exclusion list for a given TCB OR in the 11018c2654abSrjs * bound-all case a TCB may NOT include the loopback or other 11028c2654abSrjs * addresses as well. 11038c2654abSrjs */ 11048c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 11058c2654abSrjs struct ifnet *ifn; 11068c2654abSrjs struct ifaddr *ifa; 1107040205aeSozaki-r int s; 11088c2654abSrjs 1109040205aeSozaki-r s = pserialize_read_enter(); 1110040205aeSozaki-r IFNET_READER_FOREACH(ifn) { 11119e4c2bdaSozaki-r IFADDR_READER_FOREACH(ifa, ifn) { 11128c2654abSrjs /* Count them if they are the right type */ 11138c2654abSrjs if (ifa->ifa_addr->sa_family == AF_INET) { 11148c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 11158c2654abSrjs cnt += sizeof(struct sockaddr_in6); 11168c2654abSrjs else 11178c2654abSrjs cnt += sizeof(struct sockaddr_in); 11188c2654abSrjs 11198c2654abSrjs } else if (ifa->ifa_addr->sa_family == AF_INET6) 11208c2654abSrjs cnt += sizeof(struct sockaddr_in6); 11218c2654abSrjs } 11228c2654abSrjs } 1123040205aeSozaki-r pserialize_read_exit(s); 11248c2654abSrjs } else { 11258c2654abSrjs struct sctp_laddr *laddr; 11268c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 11278c2654abSrjs if (laddr->ifa->ifa_addr->sa_family == AF_INET) { 11288c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 11298c2654abSrjs cnt += sizeof(struct sockaddr_in6); 11308c2654abSrjs else 11318c2654abSrjs cnt += sizeof(struct sockaddr_in); 11328c2654abSrjs 11338c2654abSrjs } else if (laddr->ifa->ifa_addr->sa_family == AF_INET6) 11348c2654abSrjs cnt += sizeof(struct sockaddr_in6); 11358c2654abSrjs } 11368c2654abSrjs } 11378c2654abSrjs return (cnt); 11388c2654abSrjs } 11398c2654abSrjs 11407cd04cafSrjs int 11413917a6f0Srjs sctp_do_connect_x(struct socket *so, struct sctp_connectx_addrs *sca, 11428c2654abSrjs struct lwp *l, int delay) 11438c2654abSrjs { 11448c2654abSrjs int error = 0; 11453917a6f0Srjs struct sctp_inpcb *inp; 11468c2654abSrjs struct sctp_tcb *stcb = NULL; 11478c2654abSrjs struct sockaddr *sa; 11483917a6f0Srjs int num_v6=0, num_v4=0, totaddr, i, incr, at; 11493917a6f0Srjs char buf[2048]; 11503917a6f0Srjs size_t len; 11513917a6f0Srjs sctp_assoc_t id; 11528c2654abSrjs #ifdef SCTP_DEBUG 11538c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) { 11548c2654abSrjs printf("Connectx called\n"); 11558c2654abSrjs } 11568c2654abSrjs #endif /* SCTP_DEBUG */ 11578c2654abSrjs 11583917a6f0Srjs inp = (struct sctp_inpcb *)so->so_pcb; 11593917a6f0Srjs if (inp == 0) 11603917a6f0Srjs return EINVAL; 11613917a6f0Srjs 11628c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 11638c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 11648c2654abSrjs /* We are already connected AND the TCP model */ 11658c2654abSrjs return (EADDRINUSE); 11668c2654abSrjs } 11678c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 11688c2654abSrjs SCTP_INP_RLOCK(inp); 11698c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 11708c2654abSrjs SCTP_INP_RUNLOCK(inp); 11718c2654abSrjs } 11728c2654abSrjs if (stcb) { 11738c2654abSrjs return (EALREADY); 11748c2654abSrjs 11758c2654abSrjs } 11768c2654abSrjs SCTP_ASOC_CREATE_LOCK(inp); 11778c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 11788c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 11798c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 11808c2654abSrjs return (EFAULT); 11818c2654abSrjs } 11828c2654abSrjs 11833917a6f0Srjs len = sca->cx_len; 11843917a6f0Srjs totaddr = sca->cx_num; 11853917a6f0Srjs if (len > sizeof(buf)) { 11863917a6f0Srjs return E2BIG; 11873917a6f0Srjs } 11883917a6f0Srjs error = copyin(sca->cx_addrs, buf, len); 11893917a6f0Srjs if (error) { 11903917a6f0Srjs return error; 11913917a6f0Srjs } 11923917a6f0Srjs sa = (struct sockaddr *)buf; 11938c2654abSrjs at = incr = 0; 11948c2654abSrjs /* account and validate addresses */ 11958c2654abSrjs SCTP_INP_WLOCK(inp); 11968c2654abSrjs SCTP_INP_INCR_REF(inp); 11978c2654abSrjs SCTP_INP_WUNLOCK(inp); 11988c2654abSrjs for (i = 0; i < totaddr; i++) { 11998c2654abSrjs if (sa->sa_family == AF_INET) { 12008c2654abSrjs num_v4++; 12018c2654abSrjs incr = sizeof(struct sockaddr_in); 12028c2654abSrjs } else if (sa->sa_family == AF_INET6) { 12038c2654abSrjs struct sockaddr_in6 *sin6; 12048c2654abSrjs sin6 = (struct sockaddr_in6 *)sa; 12058c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 12068c2654abSrjs /* Must be non-mapped for connectx */ 12078c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12088c2654abSrjs return EINVAL; 12098c2654abSrjs } 12108c2654abSrjs num_v6++; 12118c2654abSrjs incr = sizeof(struct sockaddr_in6); 12128c2654abSrjs } else { 12138c2654abSrjs totaddr = i; 12148c2654abSrjs break; 12158c2654abSrjs } 12168c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 12178c2654abSrjs if (stcb != NULL) { 12188c2654abSrjs /* Already have or am bring up an association */ 12198c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12208c2654abSrjs SCTP_TCB_UNLOCK(stcb); 12218c2654abSrjs return (EALREADY); 12228c2654abSrjs } 12233917a6f0Srjs if ((at + incr) > len) { 12248c2654abSrjs totaddr = i; 12258c2654abSrjs break; 12268c2654abSrjs } 12278c2654abSrjs sa = (struct sockaddr *)((vaddr_t)sa + incr); 12288c2654abSrjs } 12293917a6f0Srjs sa = (struct sockaddr *)buf; 12308c2654abSrjs SCTP_INP_WLOCK(inp); 12318c2654abSrjs SCTP_INP_DECR_REF(inp); 12328c2654abSrjs SCTP_INP_WUNLOCK(inp); 12338c2654abSrjs #ifdef INET6 12348c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 12358c2654abSrjs (num_v6 > 0)) { 12368c2654abSrjs SCTP_INP_WUNLOCK(inp); 12378c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12388c2654abSrjs return (EINVAL); 12398c2654abSrjs } 12408c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 12418c2654abSrjs (num_v4 > 0)) { 12428c2654abSrjs struct in6pcb *inp6; 12438c2654abSrjs inp6 = (struct in6pcb *)inp; 12448c2654abSrjs if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) { 12458c2654abSrjs /* 12468c2654abSrjs * if IPV6_V6ONLY flag, ignore connections 12478c2654abSrjs * destined to a v4 addr or v4-mapped addr 12488c2654abSrjs */ 12498c2654abSrjs SCTP_INP_WUNLOCK(inp); 12508c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12518c2654abSrjs return EINVAL; 12528c2654abSrjs } 12538c2654abSrjs } 12548c2654abSrjs #endif /* INET6 */ 12558c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 12568c2654abSrjs SCTP_PCB_FLAGS_UNBOUND) { 12578c2654abSrjs /* Bind a ephemeral port */ 12588c2654abSrjs SCTP_INP_WUNLOCK(inp); 12598c2654abSrjs error = sctp_inpcb_bind(so, NULL, l); 12608c2654abSrjs if (error) { 12618c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12628c2654abSrjs return (error); 12638c2654abSrjs } 12648c2654abSrjs } else { 12658c2654abSrjs SCTP_INP_WUNLOCK(inp); 12668c2654abSrjs } 12678c2654abSrjs /* We are GOOD to go */ 12688c2654abSrjs stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0); 12698c2654abSrjs if (stcb == NULL) { 12708c2654abSrjs /* Gak! no memory */ 12718c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12728c2654abSrjs return (error); 12738c2654abSrjs } 12743917a6f0Srjs 12758c2654abSrjs /* move to second address */ 12768c2654abSrjs if (sa->sa_family == AF_INET) 12778c2654abSrjs sa = (struct sockaddr *)((vaddr_t)sa + sizeof(struct sockaddr_in)); 12788c2654abSrjs else 12798c2654abSrjs sa = (struct sockaddr *)((vaddr_t)sa + sizeof(struct sockaddr_in6)); 12808c2654abSrjs 12818c2654abSrjs for (i = 1; i < totaddr; i++) { 12828c2654abSrjs if (sa->sa_family == AF_INET) { 12838c2654abSrjs incr = sizeof(struct sockaddr_in); 12848c2654abSrjs if (sctp_add_remote_addr(stcb, sa, 0, 8)) { 12858c2654abSrjs /* assoc gone no un-lock */ 12868c2654abSrjs sctp_free_assoc(inp, stcb); 12878c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12888c2654abSrjs return (ENOBUFS); 12898c2654abSrjs } 12908c2654abSrjs 12918c2654abSrjs } else if (sa->sa_family == AF_INET6) { 12928c2654abSrjs incr = sizeof(struct sockaddr_in6); 12938c2654abSrjs if (sctp_add_remote_addr(stcb, sa, 0, 8)) { 12948c2654abSrjs /* assoc gone no un-lock */ 12958c2654abSrjs sctp_free_assoc(inp, stcb); 12968c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 12978c2654abSrjs return (ENOBUFS); 12988c2654abSrjs } 12998c2654abSrjs } 13008c2654abSrjs sa = (struct sockaddr *)((vaddr_t)sa + incr); 13018c2654abSrjs } 13028c2654abSrjs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 13033917a6f0Srjs 13043917a6f0Srjs id = sctp_get_associd(stcb); 13053917a6f0Srjs memcpy(&sca->cx_num, &id, sizeof(sctp_assoc_t)); 13063917a6f0Srjs 13078c2654abSrjs if (delay) { 13088c2654abSrjs /* doing delayed connection */ 13098c2654abSrjs stcb->asoc.delayed_connection = 1; 13108c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 13118c2654abSrjs } else { 13128c2654abSrjs SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 13138c2654abSrjs sctp_send_initiate(inp, stcb); 13148c2654abSrjs } 13158c2654abSrjs SCTP_TCB_UNLOCK(stcb); 13168c2654abSrjs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 13178c2654abSrjs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 13188c2654abSrjs /* Set the connected flag so we can queue data */ 13198c2654abSrjs soisconnecting(so); 13208c2654abSrjs } 13218c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 13228c2654abSrjs return error; 13238c2654abSrjs } 13248c2654abSrjs 13258c2654abSrjs 13268c2654abSrjs static int 13278c2654abSrjs sctp_optsget(struct socket *so, struct sockopt *sopt) 13288c2654abSrjs { 13298c2654abSrjs struct sctp_inpcb *inp; 13308c2654abSrjs int error, optval=0; 13318c2654abSrjs int *ovp; 13328c2654abSrjs struct sctp_tcb *stcb = NULL; 13338c2654abSrjs 13348c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 13358c2654abSrjs if (inp == 0) 13368c2654abSrjs return EINVAL; 13378c2654abSrjs error = 0; 13388c2654abSrjs 13398c2654abSrjs #ifdef SCTP_DEBUG 13408c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) { 13418c2654abSrjs printf("optsget opt:%x sz:%zu\n", sopt->sopt_name, 13428c2654abSrjs sopt->sopt_size); 13438c2654abSrjs } 13448c2654abSrjs #endif /* SCTP_DEBUG */ 13458c2654abSrjs 13468c2654abSrjs switch (sopt->sopt_name) { 13478c2654abSrjs case SCTP_NODELAY: 13488c2654abSrjs case SCTP_AUTOCLOSE: 13498c2654abSrjs case SCTP_AUTO_ASCONF: 13508c2654abSrjs case SCTP_DISABLE_FRAGMENTS: 13518c2654abSrjs case SCTP_I_WANT_MAPPED_V4_ADDR: 13528c2654abSrjs #ifdef SCTP_DEBUG 13538c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) { 13548c2654abSrjs printf("other stuff\n"); 13558c2654abSrjs } 13568c2654abSrjs #endif /* SCTP_DEBUG */ 13578c2654abSrjs SCTP_INP_RLOCK(inp); 13588c2654abSrjs switch (sopt->sopt_name) { 13598c2654abSrjs case SCTP_DISABLE_FRAGMENTS: 13608c2654abSrjs optval = inp->sctp_flags & SCTP_PCB_FLAGS_NO_FRAGMENT; 13618c2654abSrjs break; 13628c2654abSrjs case SCTP_I_WANT_MAPPED_V4_ADDR: 13638c2654abSrjs optval = inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 13648c2654abSrjs break; 13658c2654abSrjs case SCTP_AUTO_ASCONF: 13668c2654abSrjs optval = inp->sctp_flags & SCTP_PCB_FLAGS_AUTO_ASCONF; 13678c2654abSrjs break; 13688c2654abSrjs case SCTP_NODELAY: 13698c2654abSrjs optval = inp->sctp_flags & SCTP_PCB_FLAGS_NODELAY; 13708c2654abSrjs break; 13718c2654abSrjs case SCTP_AUTOCLOSE: 13728c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_AUTOCLOSE) == 13738c2654abSrjs SCTP_PCB_FLAGS_AUTOCLOSE) 13748c2654abSrjs optval = inp->sctp_ep.auto_close_time; 13758c2654abSrjs else 13768c2654abSrjs optval = 0; 13778c2654abSrjs break; 13788c2654abSrjs 13798c2654abSrjs default: 13808c2654abSrjs error = ENOPROTOOPT; 13818c2654abSrjs } /* end switch (sopt->sopt_name) */ 13828c2654abSrjs if (sopt->sopt_name != SCTP_AUTOCLOSE) { 13838c2654abSrjs /* make it an "on/off" value */ 13848c2654abSrjs optval = (optval != 0); 13858c2654abSrjs } 13868c2654abSrjs if (sopt->sopt_size < sizeof(int)) { 13878c2654abSrjs error = EINVAL; 13888c2654abSrjs } 13898c2654abSrjs SCTP_INP_RUNLOCK(inp); 13908c2654abSrjs if (error == 0) { 13918c2654abSrjs /* return the option value */ 13928c2654abSrjs ovp = sopt->sopt_data; 13938c2654abSrjs *ovp = optval; 13948c2654abSrjs sopt->sopt_size = sizeof(optval); 13958c2654abSrjs } 13968c2654abSrjs break; 13978c2654abSrjs case SCTP_GET_ASOC_ID_LIST: 13988c2654abSrjs { 13998c2654abSrjs struct sctp_assoc_ids *ids; 14008c2654abSrjs int cnt, at; 14018c2654abSrjs u_int16_t orig; 14028c2654abSrjs 14038c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_assoc_ids)) { 14048c2654abSrjs error = EINVAL; 14058c2654abSrjs break; 14068c2654abSrjs } 14078c2654abSrjs ids = sopt->sopt_data; 14088c2654abSrjs cnt = 0; 14098c2654abSrjs SCTP_INP_RLOCK(inp); 14108c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 14118c2654abSrjs if (stcb == NULL) { 14128c2654abSrjs none_out_now: 14138c2654abSrjs ids->asls_numb_present = 0; 14148c2654abSrjs ids->asls_more_to_get = 0; 14158c2654abSrjs SCTP_INP_RUNLOCK(inp); 14168c2654abSrjs break; 14178c2654abSrjs } 14188c2654abSrjs orig = ids->asls_assoc_start; 14198c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 14208c2654abSrjs while( orig ) { 14218c2654abSrjs stcb = LIST_NEXT(stcb , sctp_tcblist); 14228c2654abSrjs orig--; 14238c2654abSrjs cnt--; 14248c2654abSrjs } 14258c2654abSrjs if ( stcb == NULL) 14268c2654abSrjs goto none_out_now; 14278c2654abSrjs 14288c2654abSrjs at = 0; 14298c2654abSrjs ids->asls_numb_present = 0; 14308c2654abSrjs ids->asls_more_to_get = 1; 14318c2654abSrjs while(at < MAX_ASOC_IDS_RET) { 14328c2654abSrjs ids->asls_assoc_id[at] = sctp_get_associd(stcb); 14338c2654abSrjs at++; 14348c2654abSrjs ids->asls_numb_present++; 14358c2654abSrjs stcb = LIST_NEXT(stcb , sctp_tcblist); 14368c2654abSrjs if (stcb == NULL) { 14378c2654abSrjs ids->asls_more_to_get = 0; 14388c2654abSrjs break; 14398c2654abSrjs } 14408c2654abSrjs } 14418c2654abSrjs SCTP_INP_RUNLOCK(inp); 14428c2654abSrjs } 14438c2654abSrjs break; 14448c2654abSrjs case SCTP_GET_NONCE_VALUES: 14458c2654abSrjs { 14468c2654abSrjs struct sctp_get_nonce_values *gnv; 14478c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_get_nonce_values)) { 14488c2654abSrjs error = EINVAL; 14498c2654abSrjs break; 14508c2654abSrjs } 14518c2654abSrjs gnv = sopt->sopt_data; 14528c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, gnv->gn_assoc_id); 14538c2654abSrjs if (stcb == NULL) { 14548c2654abSrjs error = ENOTCONN; 14558c2654abSrjs } else { 14568c2654abSrjs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 14578c2654abSrjs gnv->gn_local_tag = stcb->asoc.my_vtag; 14588c2654abSrjs SCTP_TCB_UNLOCK(stcb); 14598c2654abSrjs } 14608c2654abSrjs 14618c2654abSrjs } 14628c2654abSrjs break; 14638c2654abSrjs case SCTP_PEER_PUBLIC_KEY: 14648c2654abSrjs case SCTP_MY_PUBLIC_KEY: 14658c2654abSrjs case SCTP_SET_AUTH_CHUNKS: 14668c2654abSrjs case SCTP_SET_AUTH_SECRET: 14678c2654abSrjs /* not supported yet and until we refine the draft */ 14688c2654abSrjs error = EOPNOTSUPP; 14698c2654abSrjs break; 14708c2654abSrjs 14718c2654abSrjs case SCTP_DELAYED_ACK_TIME: 14728c2654abSrjs { 14738c2654abSrjs int32_t *tm; 14748c2654abSrjs if (sopt->sopt_size < sizeof(int32_t)) { 14758c2654abSrjs error = EINVAL; 14768c2654abSrjs break; 14778c2654abSrjs } 14788c2654abSrjs tm = sopt->sopt_data; 14798c2654abSrjs 14808c2654abSrjs *tm = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 14818c2654abSrjs } 14828c2654abSrjs break; 14838c2654abSrjs 14848c2654abSrjs case SCTP_GET_SNDBUF_USE: 14858c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_sockstat)) { 14868c2654abSrjs error = EINVAL; 14878c2654abSrjs } else { 14888c2654abSrjs struct sctp_sockstat *ss; 14898c2654abSrjs struct sctp_association *asoc; 14908c2654abSrjs ss = sopt->sopt_data; 14918c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, ss->ss_assoc_id); 14928c2654abSrjs if (stcb == NULL) { 14938c2654abSrjs error = ENOTCONN; 14948c2654abSrjs } else { 14958c2654abSrjs asoc = &stcb->asoc; 14968c2654abSrjs ss->ss_total_sndbuf = (u_int32_t)asoc->total_output_queue_size; 14978c2654abSrjs ss->ss_total_mbuf_sndbuf = (u_int32_t)asoc->total_output_mbuf_queue_size; 14988c2654abSrjs ss->ss_total_recv_buf = (u_int32_t)(asoc->size_on_delivery_queue + 14998c2654abSrjs asoc->size_on_reasm_queue + 15008c2654abSrjs asoc->size_on_all_streams); 15018c2654abSrjs SCTP_TCB_UNLOCK(stcb); 15028c2654abSrjs error = 0; 15038c2654abSrjs sopt->sopt_size = sizeof(struct sctp_sockstat); 15048c2654abSrjs } 15058c2654abSrjs } 15068c2654abSrjs break; 15078c2654abSrjs case SCTP_MAXBURST: 15088c2654abSrjs { 15098c2654abSrjs u_int8_t *burst; 15108c2654abSrjs burst = sopt->sopt_data; 15118c2654abSrjs SCTP_INP_RLOCK(inp); 15128c2654abSrjs *burst = inp->sctp_ep.max_burst; 15138c2654abSrjs SCTP_INP_RUNLOCK(inp); 15148c2654abSrjs sopt->sopt_size = sizeof(u_int8_t); 15158c2654abSrjs } 15168c2654abSrjs break; 15178c2654abSrjs case SCTP_MAXSEG: 15188c2654abSrjs { 15198c2654abSrjs u_int32_t *segsize; 15208c2654abSrjs sctp_assoc_t *assoc_id; 15218c2654abSrjs int ovh; 15228c2654abSrjs 15238c2654abSrjs if (sopt->sopt_size < sizeof(u_int32_t)) { 15248c2654abSrjs error = EINVAL; 15258c2654abSrjs break; 15268c2654abSrjs } 15278c2654abSrjs if (sopt->sopt_size < sizeof(sctp_assoc_t)) { 15288c2654abSrjs error = EINVAL; 15298c2654abSrjs break; 15308c2654abSrjs } 15318c2654abSrjs assoc_id = sopt->sopt_data; 15328c2654abSrjs segsize = sopt->sopt_data; 15338c2654abSrjs sopt->sopt_size = sizeof(u_int32_t); 15348c2654abSrjs 15358c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 15368c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) || 15378c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 15388c2654abSrjs SCTP_INP_RLOCK(inp); 15398c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 15408c2654abSrjs if (stcb) { 15418c2654abSrjs SCTP_TCB_LOCK(stcb); 15428c2654abSrjs SCTP_INP_RUNLOCK(inp); 15438c2654abSrjs *segsize = sctp_get_frag_point(stcb, &stcb->asoc); 15448c2654abSrjs SCTP_TCB_UNLOCK(stcb); 15458c2654abSrjs } else { 15468c2654abSrjs SCTP_INP_RUNLOCK(inp); 15478c2654abSrjs goto skipit; 15488c2654abSrjs } 15498c2654abSrjs } else { 15508c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, *assoc_id); 15518c2654abSrjs if (stcb) { 15528c2654abSrjs *segsize = sctp_get_frag_point(stcb, &stcb->asoc); 15538c2654abSrjs SCTP_TCB_UNLOCK(stcb); 15548c2654abSrjs break; 15558c2654abSrjs } 15568c2654abSrjs skipit: 15578c2654abSrjs /* default is to get the max, if I 15588c2654abSrjs * can't calculate from an existing association. 15598c2654abSrjs */ 15608c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 15618c2654abSrjs ovh = SCTP_MED_OVERHEAD; 15628c2654abSrjs } else { 15638c2654abSrjs ovh = SCTP_MED_V4_OVERHEAD; 15648c2654abSrjs } 15658c2654abSrjs *segsize = inp->sctp_frag_point - ovh; 15668c2654abSrjs } 15678c2654abSrjs } 15688c2654abSrjs break; 15698c2654abSrjs 15708c2654abSrjs case SCTP_SET_DEBUG_LEVEL: 15718c2654abSrjs #ifdef SCTP_DEBUG 15728c2654abSrjs { 15738c2654abSrjs u_int32_t *level; 15748c2654abSrjs if (sopt->sopt_size < sizeof(u_int32_t)) { 15758c2654abSrjs error = EINVAL; 15768c2654abSrjs break; 15778c2654abSrjs } 15788c2654abSrjs level = sopt->sopt_data; 15798c2654abSrjs error = 0; 15808c2654abSrjs *level = sctp_debug_on; 15818c2654abSrjs sopt->sopt_size = sizeof(u_int32_t); 15828c2654abSrjs printf("Returning DEBUG LEVEL %x is set\n", 15838c2654abSrjs (u_int)sctp_debug_on); 15848c2654abSrjs } 15858c2654abSrjs #else /* SCTP_DEBUG */ 15868c2654abSrjs error = EOPNOTSUPP; 15878c2654abSrjs #endif 15888c2654abSrjs break; 15898c2654abSrjs case SCTP_GET_STAT_LOG: 15908c2654abSrjs #ifdef SCTP_STAT_LOGGING 15918c2654abSrjs error = sctp_fill_stat_log(m); 15928c2654abSrjs #else /* SCTP_DEBUG */ 15938c2654abSrjs error = EOPNOTSUPP; 15948c2654abSrjs #endif 15958c2654abSrjs break; 15968c2654abSrjs case SCTP_GET_PEGS: 15978c2654abSrjs { 15988c2654abSrjs u_int32_t *pt; 15998c2654abSrjs if (sopt->sopt_size < sizeof(sctp_pegs)) { 16008c2654abSrjs error = EINVAL; 16018c2654abSrjs break; 16028c2654abSrjs } 16038c2654abSrjs pt = sopt->sopt_data; 16048c2654abSrjs memcpy(pt, sctp_pegs, sizeof(sctp_pegs)); 16058c2654abSrjs sopt->sopt_size = sizeof(sctp_pegs); 16068c2654abSrjs } 16078c2654abSrjs break; 16088c2654abSrjs case SCTP_EVENTS: 16098c2654abSrjs { 16108c2654abSrjs struct sctp_event_subscribe *events; 16118c2654abSrjs #ifdef SCTP_DEBUG 16128c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) { 16138c2654abSrjs printf("get events\n"); 16148c2654abSrjs } 16158c2654abSrjs #endif /* SCTP_DEBUG */ 16168c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_event_subscribe)) { 16178c2654abSrjs #ifdef SCTP_DEBUG 16188c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) { 16198c2654abSrjs printf("sopt->sopt_size is %d not %d\n", 16208c2654abSrjs (int)sopt->sopt_size, 16218c2654abSrjs (int)sizeof(struct sctp_event_subscribe)); 16228c2654abSrjs } 16238c2654abSrjs #endif /* SCTP_DEBUG */ 16248c2654abSrjs error = EINVAL; 16258c2654abSrjs break; 16268c2654abSrjs } 16278c2654abSrjs events = sopt->sopt_data; 16288c2654abSrjs memset(events, 0, sopt->sopt_size); 16298c2654abSrjs SCTP_INP_RLOCK(inp); 16308c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT) 16318c2654abSrjs events->sctp_data_io_event = 1; 16328c2654abSrjs 16338c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVASSOCEVNT) 16348c2654abSrjs events->sctp_association_event = 1; 16358c2654abSrjs 16368c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVPADDREVNT) 16378c2654abSrjs events->sctp_address_event = 1; 16388c2654abSrjs 16398c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVSENDFAILEVNT) 16408c2654abSrjs events->sctp_send_failure_event = 1; 16418c2654abSrjs 16428c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVPEERERR) 16438c2654abSrjs events->sctp_peer_error_event = 1; 16448c2654abSrjs 16458c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT) 16468c2654abSrjs events->sctp_shutdown_event = 1; 16478c2654abSrjs 16488c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_PDAPIEVNT) 16498c2654abSrjs events->sctp_partial_delivery_event = 1; 16508c2654abSrjs 16518c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_ADAPTIONEVNT) 16528c2654abSrjs events->sctp_adaption_layer_event = 1; 16538c2654abSrjs 16548c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_STREAM_RESETEVNT) 16558c2654abSrjs events->sctp_stream_reset_events = 1; 16568c2654abSrjs SCTP_INP_RUNLOCK(inp); 16578c2654abSrjs sopt->sopt_size = sizeof(struct sctp_event_subscribe); 16588c2654abSrjs 16598c2654abSrjs } 16608c2654abSrjs break; 16618c2654abSrjs 16628c2654abSrjs case SCTP_ADAPTION_LAYER: 16638c2654abSrjs if (sopt->sopt_size < sizeof(int)) { 16648c2654abSrjs error = EINVAL; 16658c2654abSrjs break; 16668c2654abSrjs } 16678c2654abSrjs #ifdef SCTP_DEBUG 16688c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 16698c2654abSrjs printf("getadaption ind\n"); 16708c2654abSrjs } 16718c2654abSrjs #endif /* SCTP_DEBUG */ 16728c2654abSrjs SCTP_INP_RLOCK(inp); 16738c2654abSrjs ovp = sopt->sopt_data; 16748c2654abSrjs *ovp = inp->sctp_ep.adaption_layer_indicator; 16758c2654abSrjs SCTP_INP_RUNLOCK(inp); 16768c2654abSrjs sopt->sopt_size = sizeof(int); 16778c2654abSrjs break; 16788c2654abSrjs case SCTP_SET_INITIAL_DBG_SEQ: 16798c2654abSrjs if (sopt->sopt_size < sizeof(int)) { 16808c2654abSrjs error = EINVAL; 16818c2654abSrjs break; 16828c2654abSrjs } 16838c2654abSrjs #ifdef SCTP_DEBUG 16848c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 16858c2654abSrjs printf("get initial dbg seq\n"); 16868c2654abSrjs } 16878c2654abSrjs #endif /* SCTP_DEBUG */ 16888c2654abSrjs SCTP_INP_RLOCK(inp); 16898c2654abSrjs ovp = sopt->sopt_data; 16908c2654abSrjs *ovp = inp->sctp_ep.initial_sequence_debug; 16918c2654abSrjs SCTP_INP_RUNLOCK(inp); 16928c2654abSrjs sopt->sopt_size = sizeof(int); 16938c2654abSrjs break; 16948c2654abSrjs case SCTP_GET_LOCAL_ADDR_SIZE: 16958c2654abSrjs if (sopt->sopt_size < sizeof(int)) { 16968c2654abSrjs error = EINVAL; 16978c2654abSrjs break; 16988c2654abSrjs } 16998c2654abSrjs #ifdef SCTP_DEBUG 17008c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 17018c2654abSrjs printf("get local sizes\n"); 17028c2654abSrjs } 17038c2654abSrjs #endif /* SCTP_DEBUG */ 17048c2654abSrjs SCTP_INP_RLOCK(inp); 17058c2654abSrjs ovp = sopt->sopt_data; 17068c2654abSrjs *ovp = sctp_count_max_addresses(inp); 17078c2654abSrjs SCTP_INP_RUNLOCK(inp); 17088c2654abSrjs sopt->sopt_size = sizeof(int); 17098c2654abSrjs break; 17108c2654abSrjs case SCTP_GET_REMOTE_ADDR_SIZE: 17118c2654abSrjs { 17128c2654abSrjs sctp_assoc_t *assoc_id; 17138c2654abSrjs u_int32_t *val, sz; 17148c2654abSrjs struct sctp_nets *net; 17158c2654abSrjs #ifdef SCTP_DEBUG 17168c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 17178c2654abSrjs printf("get remote size\n"); 17188c2654abSrjs } 17198c2654abSrjs #endif /* SCTP_DEBUG */ 17208c2654abSrjs if (sopt->sopt_size < sizeof(sctp_assoc_t)) { 17218c2654abSrjs #ifdef SCTP_DEBUG 17228c2654abSrjs printf("sopt->sopt_size:%zu not %zu\n", 17238c2654abSrjs sopt->sopt_size, sizeof(sctp_assoc_t)); 17248c2654abSrjs #endif /* SCTP_DEBUG */ 17258c2654abSrjs error = EINVAL; 17268c2654abSrjs break; 17278c2654abSrjs } 17288c2654abSrjs stcb = NULL; 17298c2654abSrjs val = sopt->sopt_data; 17308c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 17318c2654abSrjs SCTP_INP_RLOCK(inp); 17328c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 17338c2654abSrjs if (stcb) { 17348c2654abSrjs SCTP_TCB_LOCK(stcb); 17358c2654abSrjs } 17368c2654abSrjs SCTP_INP_RUNLOCK(inp); 17378c2654abSrjs } 17388c2654abSrjs if (stcb == NULL) { 17398c2654abSrjs assoc_id = sopt->sopt_data; 17408c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, *assoc_id); 17418c2654abSrjs } 17428c2654abSrjs 17438c2654abSrjs if (stcb == NULL) { 17448c2654abSrjs error = EINVAL; 17458c2654abSrjs break; 17468c2654abSrjs } 17478c2654abSrjs *val = 0; 17488c2654abSrjs sz = 0; 17498c2654abSrjs /* Count the sizes */ 17508c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 17518c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 17528c2654abSrjs (rtcache_getdst(&net->ro)->sa_family == AF_INET6)) { 17538c2654abSrjs sz += sizeof(struct sockaddr_in6); 17548c2654abSrjs } else if (rtcache_getdst(&net->ro)->sa_family == AF_INET) { 17558c2654abSrjs sz += sizeof(struct sockaddr_in); 17568c2654abSrjs } else { 17578c2654abSrjs /* huh */ 17588c2654abSrjs break; 17598c2654abSrjs } 17608c2654abSrjs } 17618c2654abSrjs SCTP_TCB_UNLOCK(stcb); 17628c2654abSrjs *val = sz; 17638c2654abSrjs sopt->sopt_size = sizeof(u_int32_t); 17648c2654abSrjs } 17658c2654abSrjs break; 17668c2654abSrjs case SCTP_GET_PEER_ADDRESSES: 17678c2654abSrjs /* 17688c2654abSrjs * Get the address information, an array 17698c2654abSrjs * is passed in to fill up we pack it. 17708c2654abSrjs */ 17718c2654abSrjs { 17728c2654abSrjs int cpsz, left; 17738c2654abSrjs struct sockaddr_storage *sas; 17748c2654abSrjs struct sctp_nets *net; 17758c2654abSrjs struct sctp_getaddresses *saddr; 17768c2654abSrjs #ifdef SCTP_DEBUG 17778c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 17788c2654abSrjs printf("get peer addresses\n"); 17798c2654abSrjs } 17808c2654abSrjs #endif /* SCTP_DEBUG */ 17818c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) { 17828c2654abSrjs error = EINVAL; 17838c2654abSrjs break; 17848c2654abSrjs } 17858c2654abSrjs left = sopt->sopt_size - sizeof(struct sctp_getaddresses); 17868c2654abSrjs saddr = sopt->sopt_data; 17878c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 17888c2654abSrjs SCTP_INP_RLOCK(inp); 17898c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 17908c2654abSrjs if (stcb) { 17918c2654abSrjs SCTP_TCB_LOCK(stcb); 17928c2654abSrjs } 17938c2654abSrjs SCTP_INP_RUNLOCK(inp); 17948c2654abSrjs } else 17958c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, 17968c2654abSrjs saddr->sget_assoc_id); 17978c2654abSrjs if (stcb == NULL) { 17988c2654abSrjs error = ENOENT; 17998c2654abSrjs break; 18008c2654abSrjs } 18018c2654abSrjs sopt->sopt_size = sizeof(struct sctp_getaddresses); 18028c2654abSrjs sas = (struct sockaddr_storage *)&saddr->addr[0]; 18038c2654abSrjs 18048c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 18058c2654abSrjs sa_family_t family; 18068c2654abSrjs 18078c2654abSrjs family = rtcache_getdst(&net->ro)->sa_family; 18088c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 18098c2654abSrjs (family == AF_INET6)) { 18108c2654abSrjs cpsz = sizeof(struct sockaddr_in6); 18118c2654abSrjs } else if (family == AF_INET) { 18128c2654abSrjs cpsz = sizeof(struct sockaddr_in); 18138c2654abSrjs } else { 18148c2654abSrjs /* huh */ 18158c2654abSrjs break; 18168c2654abSrjs } 18178c2654abSrjs if (left < cpsz) { 18188c2654abSrjs /* not enough room. */ 18198c2654abSrjs #ifdef SCTP_DEBUG 18208c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 18218c2654abSrjs printf("Out of room\n"); 18228c2654abSrjs } 18238c2654abSrjs #endif /* SCTP_DEBUG */ 18248c2654abSrjs break; 18258c2654abSrjs } 18268c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 18278c2654abSrjs (family == AF_INET)) { 18288c2654abSrjs /* Must map the address */ 18298c2654abSrjs in6_sin_2_v4mapsin6((const struct sockaddr_in *) rtcache_getdst(&net->ro), 18308c2654abSrjs (struct sockaddr_in6 *)sas); 18318c2654abSrjs } else { 18328c2654abSrjs memcpy(sas, rtcache_getdst(&net->ro), cpsz); 18338c2654abSrjs } 18348c2654abSrjs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 18358c2654abSrjs 18368c2654abSrjs sas = (struct sockaddr_storage *)((vaddr_t)sas + cpsz); 18378c2654abSrjs left -= cpsz; 18388c2654abSrjs sopt->sopt_size += cpsz; 18398c2654abSrjs #ifdef SCTP_DEBUG 18408c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) { 18418c2654abSrjs printf("left now:%d mlen:%zu\n", 18428c2654abSrjs left, sopt->sopt_size); 18438c2654abSrjs } 18448c2654abSrjs #endif /* SCTP_DEBUG */ 18458c2654abSrjs } 18468c2654abSrjs SCTP_TCB_UNLOCK(stcb); 18478c2654abSrjs } 18488c2654abSrjs #ifdef SCTP_DEBUG 18498c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 18508c2654abSrjs printf("All done\n"); 18518c2654abSrjs } 18528c2654abSrjs #endif /* SCTP_DEBUG */ 18538c2654abSrjs break; 18548c2654abSrjs case SCTP_GET_LOCAL_ADDRESSES: 18558c2654abSrjs { 18568c2654abSrjs int limit, actual; 18578c2654abSrjs struct sockaddr_storage *sas; 18588c2654abSrjs struct sctp_getaddresses *saddr; 18598c2654abSrjs #ifdef SCTP_DEBUG 18608c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 18618c2654abSrjs printf("get local addresses\n"); 18628c2654abSrjs } 18638c2654abSrjs #endif /* SCTP_DEBUG */ 18648c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) { 18658c2654abSrjs error = EINVAL; 18668c2654abSrjs break; 18678c2654abSrjs } 18688c2654abSrjs saddr = sopt->sopt_data; 18698c2654abSrjs 18708c2654abSrjs if (saddr->sget_assoc_id) { 18718c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 18728c2654abSrjs SCTP_INP_RLOCK(inp); 18738c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 18748c2654abSrjs if (stcb) { 18758c2654abSrjs SCTP_TCB_LOCK(stcb); 18768c2654abSrjs } 18778c2654abSrjs SCTP_INP_RUNLOCK(inp); 18788c2654abSrjs } else 18798c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, saddr->sget_assoc_id); 18808c2654abSrjs 18818c2654abSrjs } else { 18828c2654abSrjs stcb = NULL; 18838c2654abSrjs } 18848c2654abSrjs /* 18858c2654abSrjs * assure that the TCP model does not need a assoc id 18868c2654abSrjs * once connected. 18878c2654abSrjs */ 18888c2654abSrjs if ( (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && 18898c2654abSrjs (stcb == NULL) ) { 18908c2654abSrjs SCTP_INP_RLOCK(inp); 18918c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 18928c2654abSrjs if (stcb) { 18938c2654abSrjs SCTP_TCB_LOCK(stcb); 18948c2654abSrjs } 18958c2654abSrjs SCTP_INP_RUNLOCK(inp); 18968c2654abSrjs } 18978c2654abSrjs sas = (struct sockaddr_storage *)&saddr->addr[0]; 18988c2654abSrjs limit = sopt->sopt_size - sizeof(sctp_assoc_t); 18998c2654abSrjs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 19008c2654abSrjs SCTP_TCB_UNLOCK(stcb); 19018c2654abSrjs sopt->sopt_size = sizeof(struct sockaddr_storage) + actual; 19028c2654abSrjs } 19038c2654abSrjs break; 19048c2654abSrjs case SCTP_PEER_ADDR_PARAMS: 19058c2654abSrjs { 19068c2654abSrjs struct sctp_paddrparams *paddrp; 19078c2654abSrjs struct sctp_nets *net; 19088c2654abSrjs 19098c2654abSrjs #ifdef SCTP_DEBUG 19108c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 19118c2654abSrjs printf("Getting peer_addr_params\n"); 19128c2654abSrjs } 19138c2654abSrjs #endif /* SCTP_DEBUG */ 19148c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_paddrparams)) { 19158c2654abSrjs #ifdef SCTP_DEBUG 19168c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) { 19178c2654abSrjs printf("Hmm m->m_len:%zu is to small\n", 19188c2654abSrjs sopt->sopt_size); 19198c2654abSrjs } 19208c2654abSrjs #endif /* SCTP_DEBUG */ 19218c2654abSrjs error = EINVAL; 19228c2654abSrjs break; 19238c2654abSrjs } 19248c2654abSrjs paddrp = sopt->sopt_data; 19258c2654abSrjs 19268c2654abSrjs net = NULL; 19278c2654abSrjs if (paddrp->spp_assoc_id) { 19288c2654abSrjs #ifdef SCTP_DEBUG 19298c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 19308c2654abSrjs printf("In spp_assoc_id find type\n"); 19318c2654abSrjs } 19328c2654abSrjs #endif /* SCTP_DEBUG */ 19338c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 19348c2654abSrjs SCTP_INP_RLOCK(inp); 19358c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 19368c2654abSrjs if (stcb) { 19378c2654abSrjs SCTP_TCB_LOCK(stcb); 19388c2654abSrjs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 19398c2654abSrjs } 19408c2654abSrjs SCTP_INP_RLOCK(inp); 19418c2654abSrjs } else { 19428c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id); 19438c2654abSrjs } 19448c2654abSrjs if (stcb == NULL) { 19458c2654abSrjs error = ENOENT; 19468c2654abSrjs break; 19478c2654abSrjs } 19488c2654abSrjs } 19498c2654abSrjs if ((stcb == NULL) && 19508c2654abSrjs ((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) || 19518c2654abSrjs (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) { 19528c2654abSrjs /* Lookup via address */ 19538c2654abSrjs #ifdef SCTP_DEBUG 19548c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 19558c2654abSrjs printf("Ok we need to lookup a param\n"); 19568c2654abSrjs } 19578c2654abSrjs #endif /* SCTP_DEBUG */ 19588c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 19598c2654abSrjs SCTP_INP_RLOCK(inp); 19608c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 19618c2654abSrjs if (stcb) { 19628c2654abSrjs SCTP_TCB_LOCK(stcb); 19638c2654abSrjs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 19648c2654abSrjs } 19658c2654abSrjs SCTP_INP_RUNLOCK(inp); 19668c2654abSrjs } else { 19678c2654abSrjs SCTP_INP_WLOCK(inp); 19688c2654abSrjs SCTP_INP_INCR_REF(inp); 19698c2654abSrjs SCTP_INP_WUNLOCK(inp); 19708c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, 19718c2654abSrjs (struct sockaddr *)&paddrp->spp_address, 19728c2654abSrjs &net, NULL, NULL); 19738c2654abSrjs if (stcb == NULL) { 19748c2654abSrjs SCTP_INP_WLOCK(inp); 19758c2654abSrjs SCTP_INP_DECR_REF(inp); 19768c2654abSrjs SCTP_INP_WUNLOCK(inp); 19778c2654abSrjs } 19788c2654abSrjs } 19798c2654abSrjs 19808c2654abSrjs if (stcb == NULL) { 19818c2654abSrjs error = ENOENT; 19828c2654abSrjs break; 19838c2654abSrjs } 19848c2654abSrjs } else { 19858c2654abSrjs /* Effects the Endpoint */ 19868c2654abSrjs #ifdef SCTP_DEBUG 19878c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 19888c2654abSrjs printf("User wants EP level info\n"); 19898c2654abSrjs } 19908c2654abSrjs #endif /* SCTP_DEBUG */ 19918c2654abSrjs stcb = NULL; 19928c2654abSrjs } 19938c2654abSrjs if (stcb) { 19948c2654abSrjs /* Applys to the specific association */ 19958c2654abSrjs #ifdef SCTP_DEBUG 19968c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 19978c2654abSrjs printf("In TCB side\n"); 19988c2654abSrjs } 19998c2654abSrjs #endif /* SCTP_DEBUG */ 20008c2654abSrjs if (net) { 20018c2654abSrjs paddrp->spp_pathmaxrxt = net->failure_threshold; 20028c2654abSrjs } else { 20038c2654abSrjs /* No destination so return default value */ 20048c2654abSrjs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 20058c2654abSrjs } 20068c2654abSrjs paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 20078c2654abSrjs paddrp->spp_assoc_id = sctp_get_associd(stcb); 20088c2654abSrjs SCTP_TCB_UNLOCK(stcb); 20098c2654abSrjs } else { 20108c2654abSrjs /* Use endpoint defaults */ 20118c2654abSrjs SCTP_INP_RLOCK(inp); 20128c2654abSrjs #ifdef SCTP_DEBUG 20138c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 20145fb5f516Sandvar printf("In EP level info\n"); 20158c2654abSrjs } 20168c2654abSrjs #endif /* SCTP_DEBUG */ 20178c2654abSrjs paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 20188c2654abSrjs paddrp->spp_hbinterval = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]; 20198c2654abSrjs paddrp->spp_assoc_id = (sctp_assoc_t)0; 20208c2654abSrjs SCTP_INP_RUNLOCK(inp); 20218c2654abSrjs } 20228c2654abSrjs sopt->sopt_size = sizeof(struct sctp_paddrparams); 20238c2654abSrjs } 20248c2654abSrjs break; 20258c2654abSrjs case SCTP_GET_PEER_ADDR_INFO: 20268c2654abSrjs { 20278c2654abSrjs struct sctp_paddrinfo *paddri; 20288c2654abSrjs struct sctp_nets *net; 20298c2654abSrjs #ifdef SCTP_DEBUG 20308c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 20318c2654abSrjs printf("GetPEER ADDR_INFO\n"); 20328c2654abSrjs } 20338c2654abSrjs #endif /* SCTP_DEBUG */ 20348c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_paddrinfo)) { 20358c2654abSrjs error = EINVAL; 20368c2654abSrjs break; 20378c2654abSrjs } 20388c2654abSrjs paddri = sopt->sopt_data; 20398c2654abSrjs net = NULL; 20408c2654abSrjs if ((((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET) || 20418c2654abSrjs (((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET6)) { 20428c2654abSrjs /* Lookup via address */ 20438c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 20448c2654abSrjs SCTP_INP_RLOCK(inp); 20458c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 20468c2654abSrjs if (stcb) { 20478c2654abSrjs SCTP_TCB_LOCK(stcb); 20488c2654abSrjs net = sctp_findnet(stcb, 20498c2654abSrjs (struct sockaddr *)&paddri->spinfo_address); 20508c2654abSrjs } 20518c2654abSrjs SCTP_INP_RUNLOCK(inp); 20528c2654abSrjs } else { 20538c2654abSrjs SCTP_INP_WLOCK(inp); 20548c2654abSrjs SCTP_INP_INCR_REF(inp); 20558c2654abSrjs SCTP_INP_WUNLOCK(inp); 20568c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, 20578c2654abSrjs (struct sockaddr *)&paddri->spinfo_address, 20588c2654abSrjs &net, NULL, NULL); 20598c2654abSrjs if (stcb == NULL) { 20608c2654abSrjs SCTP_INP_WLOCK(inp); 20618c2654abSrjs SCTP_INP_DECR_REF(inp); 20628c2654abSrjs SCTP_INP_WUNLOCK(inp); 20638c2654abSrjs } 20648c2654abSrjs } 20658c2654abSrjs 20668c2654abSrjs } else { 20678c2654abSrjs stcb = NULL; 20688c2654abSrjs } 20698c2654abSrjs if ((stcb == NULL) || (net == NULL)) { 20708c2654abSrjs error = ENOENT; 20718c2654abSrjs break; 20728c2654abSrjs } 20738c2654abSrjs sopt->sopt_size = sizeof(struct sctp_paddrinfo); 20748c2654abSrjs paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK|SCTP_ADDR_NOHB); 20758c2654abSrjs paddri->spinfo_cwnd = net->cwnd; 20768c2654abSrjs paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 20778c2654abSrjs paddri->spinfo_rto = net->RTO; 20788c2654abSrjs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 20798c2654abSrjs SCTP_TCB_UNLOCK(stcb); 20808c2654abSrjs } 20818c2654abSrjs break; 20828c2654abSrjs case SCTP_PCB_STATUS: 20838c2654abSrjs { 20848c2654abSrjs struct sctp_pcbinfo *spcb; 20858c2654abSrjs #ifdef SCTP_DEBUG 20868c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 20878c2654abSrjs printf("PCB status\n"); 20888c2654abSrjs } 20898c2654abSrjs #endif /* SCTP_DEBUG */ 20908c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_pcbinfo)) { 20918c2654abSrjs error = EINVAL; 20928c2654abSrjs break; 20938c2654abSrjs } 20948c2654abSrjs spcb = sopt->sopt_data; 20958c2654abSrjs sctp_fill_pcbinfo(spcb); 20968c2654abSrjs sopt->sopt_size = sizeof(struct sctp_pcbinfo); 20978c2654abSrjs } 20988c2654abSrjs break; 20998c2654abSrjs case SCTP_STATUS: 21008c2654abSrjs { 21018c2654abSrjs struct sctp_nets *net; 21028c2654abSrjs struct sctp_status *sstat; 21038c2654abSrjs #ifdef SCTP_DEBUG 21048c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 21058c2654abSrjs printf("SCTP status\n"); 21068c2654abSrjs } 21078c2654abSrjs #endif /* SCTP_DEBUG */ 21088c2654abSrjs 21098c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_status)) { 21108c2654abSrjs error = EINVAL; 21118c2654abSrjs break; 21128c2654abSrjs } 21138c2654abSrjs sstat = sopt->sopt_data; 21148c2654abSrjs 21158c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 21168c2654abSrjs SCTP_INP_RLOCK(inp); 21178c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 21188c2654abSrjs if (stcb) { 21198c2654abSrjs SCTP_TCB_LOCK(stcb); 21208c2654abSrjs } 21218c2654abSrjs SCTP_INP_RUNLOCK(inp); 21228c2654abSrjs } else 21238c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, sstat->sstat_assoc_id); 21248c2654abSrjs 21258c2654abSrjs if (stcb == NULL) { 21263917a6f0Srjs printf("SCTP status, no stcb\n"); 21278c2654abSrjs error = EINVAL; 21288c2654abSrjs break; 21298c2654abSrjs } 21308c2654abSrjs /* 21318c2654abSrjs * I think passing the state is fine since 21328c2654abSrjs * sctp_constants.h will be available to the user 21338c2654abSrjs * land. 21348c2654abSrjs */ 21358c2654abSrjs sstat->sstat_state = stcb->asoc.state; 21368c2654abSrjs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 21378c2654abSrjs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 21388c2654abSrjs /* 21398c2654abSrjs * We can't include chunks that have been passed 21408c2654abSrjs * to the socket layer. Only things in queue. 21418c2654abSrjs */ 21428c2654abSrjs sstat->sstat_penddata = (stcb->asoc.cnt_on_delivery_queue + 21438c2654abSrjs stcb->asoc.cnt_on_reasm_queue + 21448c2654abSrjs stcb->asoc.cnt_on_all_streams); 21458c2654abSrjs 21468c2654abSrjs 21478c2654abSrjs sstat->sstat_instrms = stcb->asoc.streamincnt; 21488c2654abSrjs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 21498c2654abSrjs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 21508c2654abSrjs memcpy(&sstat->sstat_primary.spinfo_address, 21518c2654abSrjs rtcache_getdst(&stcb->asoc.primary_destination->ro), 21528c2654abSrjs (rtcache_getdst(&stcb->asoc.primary_destination->ro))->sa_len); 21538c2654abSrjs net = stcb->asoc.primary_destination; 21548c2654abSrjs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 21558c2654abSrjs /* 21568c2654abSrjs * Again the user can get info from sctp_constants.h 21578c2654abSrjs * for what the state of the network is. 21588c2654abSrjs */ 21598c2654abSrjs sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK; 21608c2654abSrjs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 21618c2654abSrjs sstat->sstat_primary.spinfo_srtt = net->lastsa; 21628c2654abSrjs sstat->sstat_primary.spinfo_rto = net->RTO; 21638c2654abSrjs sstat->sstat_primary.spinfo_mtu = net->mtu; 21648c2654abSrjs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 21658c2654abSrjs SCTP_TCB_UNLOCK(stcb); 21668c2654abSrjs sopt->sopt_size = sizeof(*sstat); 21678c2654abSrjs } 21688c2654abSrjs break; 21698c2654abSrjs case SCTP_RTOINFO: 21708c2654abSrjs { 21718c2654abSrjs struct sctp_rtoinfo *srto; 21728c2654abSrjs #ifdef SCTP_DEBUG 21738c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 21748c2654abSrjs printf("RTO Info\n"); 21758c2654abSrjs } 21768c2654abSrjs #endif /* SCTP_DEBUG */ 21778c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_rtoinfo)) { 21788c2654abSrjs error = EINVAL; 21798c2654abSrjs break; 21808c2654abSrjs } 21818c2654abSrjs srto = sopt->sopt_data; 21828c2654abSrjs if (srto->srto_assoc_id == 0) { 21838c2654abSrjs /* Endpoint only please */ 21848c2654abSrjs SCTP_INP_RLOCK(inp); 21858c2654abSrjs srto->srto_initial = inp->sctp_ep.initial_rto; 21868c2654abSrjs srto->srto_max = inp->sctp_ep.sctp_maxrto; 21878c2654abSrjs srto->srto_min = inp->sctp_ep.sctp_minrto; 21888c2654abSrjs SCTP_INP_RUNLOCK(inp); 21898c2654abSrjs break; 21908c2654abSrjs } 21918c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 21928c2654abSrjs SCTP_INP_RLOCK(inp); 21938c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 21948c2654abSrjs if (stcb) { 21958c2654abSrjs SCTP_TCB_LOCK(stcb); 21968c2654abSrjs } 21978c2654abSrjs SCTP_INP_RUNLOCK(inp); 21988c2654abSrjs } else 21998c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id); 22008c2654abSrjs 22018c2654abSrjs if (stcb == NULL) { 22028c2654abSrjs error = EINVAL; 22038c2654abSrjs break; 22048c2654abSrjs } 22058c2654abSrjs srto->srto_initial = stcb->asoc.initial_rto; 22068c2654abSrjs srto->srto_max = stcb->asoc.maxrto; 22078c2654abSrjs srto->srto_min = stcb->asoc.minrto; 22088c2654abSrjs SCTP_TCB_UNLOCK(stcb); 22098c2654abSrjs sopt->sopt_size = sizeof(*srto); 22108c2654abSrjs } 22118c2654abSrjs break; 22128c2654abSrjs case SCTP_ASSOCINFO: 22138c2654abSrjs { 22148c2654abSrjs struct sctp_assocparams *sasoc; 22158c2654abSrjs #ifdef SCTP_DEBUG 22168c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 22178c2654abSrjs printf("Associnfo\n"); 22188c2654abSrjs } 22198c2654abSrjs #endif /* SCTP_DEBUG */ 22208c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_assocparams)) { 22218c2654abSrjs error = EINVAL; 22228c2654abSrjs break; 22238c2654abSrjs } 22248c2654abSrjs sasoc = sopt->sopt_data; 22258c2654abSrjs stcb = NULL; 22268c2654abSrjs 22278c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 22288c2654abSrjs SCTP_INP_RLOCK(inp); 22298c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 22308c2654abSrjs if (stcb) { 22318c2654abSrjs SCTP_TCB_LOCK(stcb); 22328c2654abSrjs } 22338c2654abSrjs SCTP_INP_RUNLOCK(inp); 22348c2654abSrjs } 22358c2654abSrjs if ((sasoc->sasoc_assoc_id) && (stcb == NULL)) { 22368c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, 22378c2654abSrjs sasoc->sasoc_assoc_id); 22388c2654abSrjs if (stcb == NULL) { 22398c2654abSrjs error = ENOENT; 22408c2654abSrjs break; 22418c2654abSrjs } 22428c2654abSrjs } else { 22438c2654abSrjs stcb = NULL; 22448c2654abSrjs } 22458c2654abSrjs 22468c2654abSrjs if (stcb) { 22478c2654abSrjs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 22488c2654abSrjs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 22498c2654abSrjs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 22508c2654abSrjs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 22518c2654abSrjs sasoc->sasoc_cookie_life = stcb->asoc.cookie_life; 22528c2654abSrjs SCTP_TCB_UNLOCK(stcb); 22538c2654abSrjs } else { 22548c2654abSrjs SCTP_INP_RLOCK(inp); 22558c2654abSrjs sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 22568c2654abSrjs sasoc->sasoc_number_peer_destinations = 0; 22578c2654abSrjs sasoc->sasoc_peer_rwnd = 0; 22588c2654abSrjs sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 22598c2654abSrjs sasoc->sasoc_cookie_life = inp->sctp_ep.def_cookie_life; 22608c2654abSrjs SCTP_INP_RUNLOCK(inp); 22618c2654abSrjs } 22628c2654abSrjs sopt->sopt_size = sizeof(*sasoc); 22638c2654abSrjs } 22648c2654abSrjs break; 22658c2654abSrjs case SCTP_DEFAULT_SEND_PARAM: 22668c2654abSrjs { 22678c2654abSrjs struct sctp_sndrcvinfo *s_info; 22688c2654abSrjs 22698c2654abSrjs if (sopt->sopt_size != sizeof(struct sctp_sndrcvinfo)) { 22708c2654abSrjs error = EINVAL; 22718c2654abSrjs break; 22728c2654abSrjs } 22738c2654abSrjs s_info = sopt->sopt_data; 22748c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 22758c2654abSrjs SCTP_INP_RLOCK(inp); 22768c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 22778c2654abSrjs if (stcb) { 22788c2654abSrjs SCTP_TCB_LOCK(stcb); 22798c2654abSrjs } 22808c2654abSrjs SCTP_INP_RUNLOCK(inp); 22818c2654abSrjs } else 22828c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id); 22838c2654abSrjs 22848c2654abSrjs if (stcb == NULL) { 22858c2654abSrjs error = ENOENT; 22868c2654abSrjs break; 22878c2654abSrjs } 22888c2654abSrjs /* Copy it out */ 22898c2654abSrjs *s_info = stcb->asoc.def_send; 22908c2654abSrjs SCTP_TCB_UNLOCK(stcb); 22918c2654abSrjs sopt->sopt_size = sizeof(*s_info); 2292786ba994Srjs } 2293786ba994Srjs break; 22948c2654abSrjs case SCTP_INITMSG: 22958c2654abSrjs { 22968c2654abSrjs struct sctp_initmsg *sinit; 22978c2654abSrjs #ifdef SCTP_DEBUG 22988c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 22998c2654abSrjs printf("initmsg\n"); 23008c2654abSrjs } 23018c2654abSrjs #endif /* SCTP_DEBUG */ 23028c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_initmsg)) { 23038c2654abSrjs error = EINVAL; 23048c2654abSrjs break; 23058c2654abSrjs } 23068c2654abSrjs sinit = sopt->sopt_data; 23078c2654abSrjs SCTP_INP_RLOCK(inp); 23088c2654abSrjs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 23098c2654abSrjs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 23108c2654abSrjs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 23118c2654abSrjs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 23128c2654abSrjs SCTP_INP_RUNLOCK(inp); 23138c2654abSrjs sopt->sopt_size = sizeof(*sinit); 23148c2654abSrjs } 23158c2654abSrjs break; 23168c2654abSrjs case SCTP_PRIMARY_ADDR: 23178c2654abSrjs /* we allow a "get" operation on this */ 23188c2654abSrjs { 23198c2654abSrjs struct sctp_setprim *ssp; 23208c2654abSrjs 23218c2654abSrjs #ifdef SCTP_DEBUG 23228c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 23238c2654abSrjs printf("setprimary\n"); 23248c2654abSrjs } 23258c2654abSrjs #endif /* SCTP_DEBUG */ 23268c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_setprim)) { 23278c2654abSrjs error = EINVAL; 23288c2654abSrjs break; 23298c2654abSrjs } 23308c2654abSrjs ssp = sopt->sopt_data; 23318c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 23328c2654abSrjs SCTP_INP_RLOCK(inp); 23338c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 23348c2654abSrjs if (stcb) { 23358c2654abSrjs SCTP_TCB_LOCK(stcb); 23368c2654abSrjs } 23378c2654abSrjs SCTP_INP_RUNLOCK(inp); 23388c2654abSrjs } else { 23398c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, ssp->ssp_assoc_id); 23408c2654abSrjs if (stcb == NULL) { 23418c2654abSrjs /* one last shot, try it by the address in */ 23428c2654abSrjs struct sctp_nets *net; 23438c2654abSrjs 23448c2654abSrjs SCTP_INP_WLOCK(inp); 23458c2654abSrjs SCTP_INP_INCR_REF(inp); 23468c2654abSrjs SCTP_INP_WUNLOCK(inp); 23478c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, 23488c2654abSrjs (struct sockaddr *)&ssp->ssp_addr, 23498c2654abSrjs &net, NULL, NULL); 23508c2654abSrjs if (stcb == NULL) { 23518c2654abSrjs SCTP_INP_WLOCK(inp); 23528c2654abSrjs SCTP_INP_DECR_REF(inp); 23538c2654abSrjs SCTP_INP_WUNLOCK(inp); 23548c2654abSrjs } 23558c2654abSrjs } 23568c2654abSrjs if (stcb == NULL) { 23578c2654abSrjs error = EINVAL; 23588c2654abSrjs break; 23598c2654abSrjs } 23608c2654abSrjs } 23618c2654abSrjs /* simply copy out the sockaddr_storage... */ 23628c2654abSrjs memcpy(&ssp->ssp_addr, 23638c2654abSrjs rtcache_getdst(&stcb->asoc.primary_destination->ro), 23648c2654abSrjs (rtcache_getdst(&stcb->asoc.primary_destination->ro))->sa_len); 23658c2654abSrjs SCTP_TCB_UNLOCK(stcb); 23668c2654abSrjs sopt->sopt_size = sizeof(*ssp); 23678c2654abSrjs } 23688c2654abSrjs break; 23698c2654abSrjs default: 23708c2654abSrjs error = ENOPROTOOPT; 23718c2654abSrjs sopt->sopt_size = 0; 23728c2654abSrjs break; 23738c2654abSrjs } /* end switch (sopt->sopt_name) */ 23748c2654abSrjs return (error); 23758c2654abSrjs } 23768c2654abSrjs 23778c2654abSrjs static int 23788c2654abSrjs sctp_optsset(struct socket *so, struct sockopt *sopt) 23798c2654abSrjs { 23808c2654abSrjs int error, *mopt, set_opt; 23818c2654abSrjs struct sctp_tcb *stcb = NULL; 23828c2654abSrjs struct sctp_inpcb *inp; 23838c2654abSrjs 23848c2654abSrjs if (sopt->sopt_data == NULL) { 23858c2654abSrjs #ifdef SCTP_DEBUG 23868c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ1) { 23878c2654abSrjs printf("optsset:MP is NULL EINVAL\n"); 23888c2654abSrjs } 23898c2654abSrjs #endif /* SCTP_DEBUG */ 23908c2654abSrjs return (EINVAL); 23918c2654abSrjs } 23928c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 23938c2654abSrjs if (inp == 0) 23948c2654abSrjs return EINVAL; 23958c2654abSrjs 23968c2654abSrjs error = 0; 23978c2654abSrjs switch (sopt->sopt_name) { 23988c2654abSrjs case SCTP_NODELAY: 23998c2654abSrjs case SCTP_AUTOCLOSE: 24008c2654abSrjs case SCTP_AUTO_ASCONF: 24018c2654abSrjs case SCTP_DISABLE_FRAGMENTS: 24028c2654abSrjs case SCTP_I_WANT_MAPPED_V4_ADDR: 24038c2654abSrjs /* copy in the option value */ 24048c2654abSrjs if (sopt->sopt_size < sizeof(int)) { 24058c2654abSrjs error = EINVAL; 24068c2654abSrjs break; 24078c2654abSrjs } 24088c2654abSrjs mopt = sopt->sopt_data; 24098c2654abSrjs set_opt = 0; 24108c2654abSrjs if (error) 24118c2654abSrjs break; 24128c2654abSrjs switch (sopt->sopt_name) { 24138c2654abSrjs case SCTP_DISABLE_FRAGMENTS: 24148c2654abSrjs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 24158c2654abSrjs break; 24168c2654abSrjs case SCTP_AUTO_ASCONF: 24178c2654abSrjs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 24188c2654abSrjs break; 24198c2654abSrjs 24208c2654abSrjs case SCTP_I_WANT_MAPPED_V4_ADDR: 24218c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 24228c2654abSrjs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 24238c2654abSrjs } else { 24248c2654abSrjs return (EINVAL); 24258c2654abSrjs } 24268c2654abSrjs break; 24278c2654abSrjs case SCTP_NODELAY: 24288c2654abSrjs set_opt = SCTP_PCB_FLAGS_NODELAY; 24298c2654abSrjs break; 24308c2654abSrjs case SCTP_AUTOCLOSE: 24318c2654abSrjs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 24328c2654abSrjs /* 24338c2654abSrjs * The value is in ticks. 2434*76748ca4Srillig * Note this does not affect old associations, only 24358c2654abSrjs * new ones. 24368c2654abSrjs */ 24378c2654abSrjs inp->sctp_ep.auto_close_time = (*mopt * hz); 24388c2654abSrjs break; 24398c2654abSrjs } 24408c2654abSrjs SCTP_INP_WLOCK(inp); 24418c2654abSrjs if (*mopt != 0) { 24428c2654abSrjs inp->sctp_flags |= set_opt; 24438c2654abSrjs } else { 24448c2654abSrjs inp->sctp_flags &= ~set_opt; 24458c2654abSrjs } 24468c2654abSrjs SCTP_INP_WUNLOCK(inp); 24478c2654abSrjs break; 24488c2654abSrjs case SCTP_MY_PUBLIC_KEY: /* set my public key */ 24498c2654abSrjs case SCTP_SET_AUTH_CHUNKS: /* set the authenticated chunks required */ 24508c2654abSrjs case SCTP_SET_AUTH_SECRET: /* set the actual secret for the endpoint */ 24518c2654abSrjs /* not supported yet and until we refine the draft */ 24528c2654abSrjs error = EOPNOTSUPP; 24538c2654abSrjs break; 24548c2654abSrjs 24558c2654abSrjs case SCTP_CLR_STAT_LOG: 24568c2654abSrjs #ifdef SCTP_STAT_LOGGING 24578c2654abSrjs sctp_clr_stat_log(); 24588c2654abSrjs #else 24598c2654abSrjs error = EOPNOTSUPP; 24608c2654abSrjs #endif 24618c2654abSrjs break; 24628c2654abSrjs case SCTP_DELAYED_ACK_TIME: 24638c2654abSrjs { 24648c2654abSrjs int32_t *tm; 24658c2654abSrjs if (sopt->sopt_size < sizeof(int32_t)) { 24668c2654abSrjs error = EINVAL; 24678c2654abSrjs break; 24688c2654abSrjs } 24698c2654abSrjs tm = sopt->sopt_data; 24708c2654abSrjs 24718c2654abSrjs if ((*tm < 10) || (*tm > 500)) { 24728c2654abSrjs /* can't be smaller than 10ms */ 24738c2654abSrjs /* MUST NOT be larger than 500ms */ 24748c2654abSrjs error = EINVAL; 24758c2654abSrjs break; 24768c2654abSrjs } 24778c2654abSrjs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(*tm); 24788c2654abSrjs } 24798c2654abSrjs break; 24808c2654abSrjs case SCTP_RESET_STREAMS: 24818c2654abSrjs { 24828c2654abSrjs struct sctp_stream_reset *strrst; 24838c2654abSrjs uint8_t two_way, not_peer; 24848c2654abSrjs 24858c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_stream_reset)) { 24868c2654abSrjs error = EINVAL; 24878c2654abSrjs break; 24888c2654abSrjs } 24898c2654abSrjs strrst = sopt->sopt_data; 24908c2654abSrjs 24918c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 24928c2654abSrjs SCTP_INP_RLOCK(inp); 24938c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 24948c2654abSrjs if (stcb) { 24958c2654abSrjs SCTP_TCB_LOCK(stcb); 24968c2654abSrjs } 24978c2654abSrjs SCTP_INP_RUNLOCK(inp); 24988c2654abSrjs } else 24998c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, strrst->strrst_assoc_id); 25008c2654abSrjs if (stcb == NULL) { 25018c2654abSrjs error = ENOENT; 25028c2654abSrjs break; 25038c2654abSrjs } 25048c2654abSrjs if (stcb->asoc.peer_supports_strreset == 0) { 25058c2654abSrjs /* Peer does not support it, 25068c2654abSrjs * we return protocol not supported since 25078c2654abSrjs * this is true for this feature and this 25088c2654abSrjs * peer, not the socket request in general. 25098c2654abSrjs */ 25108c2654abSrjs error = EPROTONOSUPPORT; 25118c2654abSrjs SCTP_TCB_UNLOCK(stcb); 25128c2654abSrjs break; 25138c2654abSrjs } 25148c2654abSrjs 25158c2654abSrjs /* Having re-thought this code I added as I write the I-D there 25168c2654abSrjs * is NO need for it. The peer, if we are requesting a stream-reset 25178c2654abSrjs * will send a request to us but will itself do what we do, take 25188c2654abSrjs * and copy off the "reset information" we send and queue TSN's 25198c2654abSrjs * larger than the send-next in our response message. Thus they 25208c2654abSrjs * will handle it. 25218c2654abSrjs */ 25228c2654abSrjs /* if (stcb->asoc.sending_seq != (stcb->asoc.last_acked_seq + 1)) {*/ 25238c2654abSrjs /* Must have all sending data ack'd before we 25248c2654abSrjs * start this procedure. This is a bit restrictive 25258c2654abSrjs * and we SHOULD work on changing this so ONLY the 25268c2654abSrjs * streams being RESET get held up. So, a reset-all 25278c2654abSrjs * would require this.. but a reset specific just 25288c2654abSrjs * needs to be sure that the ones being reset have 25298c2654abSrjs * nothing on the send_queue. For now we will 25308c2654abSrjs * skip this more detailed method and do a course 25318c2654abSrjs * way.. i.e. nothing pending ... for future FIX ME! 25328c2654abSrjs */ 25338c2654abSrjs /* error = EBUSY;*/ 25348c2654abSrjs /* break;*/ 25358c2654abSrjs /* }*/ 25368c2654abSrjs 25378c2654abSrjs if (stcb->asoc.stream_reset_outstanding) { 25388c2654abSrjs error = EALREADY; 25398c2654abSrjs SCTP_TCB_UNLOCK(stcb); 25408c2654abSrjs break; 25418c2654abSrjs } 25428c2654abSrjs if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) { 25438c2654abSrjs two_way = 0; 25448c2654abSrjs not_peer = 0; 25458c2654abSrjs } else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) { 25468c2654abSrjs two_way = 1; 25478c2654abSrjs not_peer = 1; 25488c2654abSrjs } else if (strrst->strrst_flags == SCTP_RESET_BOTH) { 25498c2654abSrjs two_way = 1; 25508c2654abSrjs not_peer = 0; 25518c2654abSrjs } else { 25528c2654abSrjs error = EINVAL; 25538c2654abSrjs SCTP_TCB_UNLOCK(stcb); 25548c2654abSrjs break; 25558c2654abSrjs } 25568c2654abSrjs sctp_send_str_reset_req(stcb, strrst->strrst_num_streams, 25578c2654abSrjs strrst->strrst_list, two_way, not_peer); 25588c2654abSrjs sctp_chunk_output(inp, stcb, 12); 25598c2654abSrjs SCTP_TCB_UNLOCK(stcb); 25608c2654abSrjs 25618c2654abSrjs } 25628c2654abSrjs break; 25638c2654abSrjs case SCTP_RESET_PEGS: 25648c2654abSrjs memset(sctp_pegs, 0, sizeof(sctp_pegs)); 25658c2654abSrjs error = 0; 25668c2654abSrjs break; 25678c2654abSrjs case SCTP_CONNECT_X_COMPLETE: 25688c2654abSrjs { 25698c2654abSrjs struct sockaddr *sa; 25708c2654abSrjs struct sctp_nets *net; 25718c2654abSrjs if (sopt->sopt_size < sizeof(struct sockaddr_in)) { 25728c2654abSrjs error = EINVAL; 25738c2654abSrjs break; 25748c2654abSrjs } 25758c2654abSrjs sa = sopt->sopt_data; 25768c2654abSrjs /* find tcb */ 25778c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 25788c2654abSrjs SCTP_INP_RLOCK(inp); 25798c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 25808c2654abSrjs if (stcb) { 25818c2654abSrjs SCTP_TCB_LOCK(stcb); 25828c2654abSrjs net = sctp_findnet(stcb, sa); 25838c2654abSrjs } 25848c2654abSrjs SCTP_INP_RUNLOCK(inp); 25858c2654abSrjs } else { 25868c2654abSrjs SCTP_INP_WLOCK(inp); 25878c2654abSrjs SCTP_INP_INCR_REF(inp); 25888c2654abSrjs SCTP_INP_WUNLOCK(inp); 25898c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 25908c2654abSrjs if (stcb == NULL) { 25918c2654abSrjs SCTP_INP_WLOCK(inp); 25928c2654abSrjs SCTP_INP_DECR_REF(inp); 25938c2654abSrjs SCTP_INP_WUNLOCK(inp); 25948c2654abSrjs } 25958c2654abSrjs } 25968c2654abSrjs 25978c2654abSrjs if (stcb == NULL) { 25988c2654abSrjs error = ENOENT; 25998c2654abSrjs break; 26008c2654abSrjs } 26018c2654abSrjs if (stcb->asoc.delayed_connection == 1) { 26028c2654abSrjs stcb->asoc.delayed_connection = 0; 26038c2654abSrjs SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 26048c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 26058c2654abSrjs sctp_send_initiate(inp, stcb); 26068c2654abSrjs } else { 26078c2654abSrjs /* already expired or did not use delayed connectx */ 26088c2654abSrjs error = EALREADY; 26098c2654abSrjs } 26108c2654abSrjs SCTP_TCB_UNLOCK(stcb); 26118c2654abSrjs } 26128c2654abSrjs break; 26138c2654abSrjs case SCTP_MAXBURST: 26148c2654abSrjs { 26158c2654abSrjs u_int8_t *burst; 26168c2654abSrjs SCTP_INP_WLOCK(inp); 26178c2654abSrjs burst = sopt->sopt_data; 26188c2654abSrjs if (*burst) { 26198c2654abSrjs inp->sctp_ep.max_burst = *burst; 26208c2654abSrjs } 26218c2654abSrjs SCTP_INP_WUNLOCK(inp); 26228c2654abSrjs } 26238c2654abSrjs break; 26248c2654abSrjs case SCTP_MAXSEG: 26258c2654abSrjs { 26268c2654abSrjs u_int32_t *segsize; 26278c2654abSrjs int ovh; 26288c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 26298c2654abSrjs ovh = SCTP_MED_OVERHEAD; 26308c2654abSrjs } else { 26318c2654abSrjs ovh = SCTP_MED_V4_OVERHEAD; 26328c2654abSrjs } 26338c2654abSrjs segsize = sopt->sopt_data; 26348c2654abSrjs if (*segsize < 1) { 26358c2654abSrjs error = EINVAL; 26368c2654abSrjs break; 26378c2654abSrjs } 26388c2654abSrjs SCTP_INP_WLOCK(inp); 26398c2654abSrjs inp->sctp_frag_point = (*segsize+ovh); 26408c2654abSrjs if (inp->sctp_frag_point < MHLEN) { 26418c2654abSrjs inp->sctp_frag_point = MHLEN; 26428c2654abSrjs } 26438c2654abSrjs SCTP_INP_WUNLOCK(inp); 26448c2654abSrjs } 26458c2654abSrjs break; 26468c2654abSrjs case SCTP_SET_DEBUG_LEVEL: 26478c2654abSrjs #ifdef SCTP_DEBUG 26488c2654abSrjs { 26498c2654abSrjs u_int32_t *level; 26508c2654abSrjs if (sopt->sopt_size < sizeof(u_int32_t)) { 26518c2654abSrjs error = EINVAL; 26528c2654abSrjs break; 26538c2654abSrjs } 26548c2654abSrjs level = sopt->sopt_data; 26558c2654abSrjs error = 0; 26568c2654abSrjs sctp_debug_on = (*level & (SCTP_DEBUG_ALL | 26578c2654abSrjs SCTP_DEBUG_NOISY)); 26588c2654abSrjs printf("SETTING DEBUG LEVEL to %x\n", 26598c2654abSrjs (u_int)sctp_debug_on); 26608c2654abSrjs 26618c2654abSrjs } 26628c2654abSrjs #else 26638c2654abSrjs error = EOPNOTSUPP; 26648c2654abSrjs #endif /* SCTP_DEBUG */ 26658c2654abSrjs break; 26668c2654abSrjs case SCTP_EVENTS: 26678c2654abSrjs { 26688c2654abSrjs struct sctp_event_subscribe *events; 26698c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_event_subscribe)) { 26708c2654abSrjs error = EINVAL; 26718c2654abSrjs break; 26728c2654abSrjs } 26738c2654abSrjs SCTP_INP_WLOCK(inp); 26748c2654abSrjs events = sopt->sopt_data; 26758c2654abSrjs if (events->sctp_data_io_event) { 26768c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_RECVDATAIOEVNT; 26778c2654abSrjs } else { 26788c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVDATAIOEVNT; 26798c2654abSrjs } 26808c2654abSrjs 26818c2654abSrjs if (events->sctp_association_event) { 26828c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_RECVASSOCEVNT; 26838c2654abSrjs } else { 26848c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVASSOCEVNT; 26858c2654abSrjs } 26868c2654abSrjs 26878c2654abSrjs if (events->sctp_address_event) { 26888c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_RECVPADDREVNT; 26898c2654abSrjs } else { 26908c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVPADDREVNT; 26918c2654abSrjs } 26928c2654abSrjs 26938c2654abSrjs if (events->sctp_send_failure_event) { 26948c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 26958c2654abSrjs } else { 26968c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 26978c2654abSrjs } 26988c2654abSrjs 26998c2654abSrjs if (events->sctp_peer_error_event) { 27008c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_RECVPEERERR; 27018c2654abSrjs } else { 27028c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVPEERERR; 27038c2654abSrjs } 27048c2654abSrjs 27058c2654abSrjs if (events->sctp_shutdown_event) { 27068c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 27078c2654abSrjs } else { 27088c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 27098c2654abSrjs } 27108c2654abSrjs 27118c2654abSrjs if (events->sctp_partial_delivery_event) { 27128c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_PDAPIEVNT; 27138c2654abSrjs } else { 27148c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_PDAPIEVNT; 27158c2654abSrjs } 27168c2654abSrjs 27178c2654abSrjs if (events->sctp_adaption_layer_event) { 27188c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_ADAPTIONEVNT; 27198c2654abSrjs } else { 27208c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_ADAPTIONEVNT; 27218c2654abSrjs } 27228c2654abSrjs 27238c2654abSrjs if (events->sctp_stream_reset_events) { 27248c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_STREAM_RESETEVNT; 27258c2654abSrjs } else { 27268c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_STREAM_RESETEVNT; 27278c2654abSrjs } 27288c2654abSrjs SCTP_INP_WUNLOCK(inp); 27298c2654abSrjs } 27308c2654abSrjs break; 27318c2654abSrjs 27328c2654abSrjs case SCTP_ADAPTION_LAYER: 27338c2654abSrjs { 27348c2654abSrjs struct sctp_setadaption *adap_bits; 27358c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_setadaption)) { 27368c2654abSrjs error = EINVAL; 27378c2654abSrjs break; 27388c2654abSrjs } 27398c2654abSrjs SCTP_INP_WLOCK(inp); 27408c2654abSrjs adap_bits = sopt->sopt_data; 27418c2654abSrjs inp->sctp_ep.adaption_layer_indicator = adap_bits->ssb_adaption_ind; 27428c2654abSrjs SCTP_INP_WUNLOCK(inp); 27438c2654abSrjs } 27448c2654abSrjs break; 27458c2654abSrjs case SCTP_SET_INITIAL_DBG_SEQ: 27468c2654abSrjs { 27478c2654abSrjs u_int32_t *vvv; 27488c2654abSrjs if (sopt->sopt_size < sizeof(u_int32_t)) { 27498c2654abSrjs error = EINVAL; 27508c2654abSrjs break; 27518c2654abSrjs } 27528c2654abSrjs SCTP_INP_WLOCK(inp); 27538c2654abSrjs vvv = sopt->sopt_data; 27548c2654abSrjs inp->sctp_ep.initial_sequence_debug = *vvv; 27558c2654abSrjs SCTP_INP_WUNLOCK(inp); 27568c2654abSrjs } 27578c2654abSrjs break; 27588c2654abSrjs case SCTP_DEFAULT_SEND_PARAM: 27598c2654abSrjs { 27608c2654abSrjs struct sctp_sndrcvinfo *s_info; 27618c2654abSrjs 27628c2654abSrjs if (sopt->sopt_size != sizeof(struct sctp_sndrcvinfo)) { 27638c2654abSrjs error = EINVAL; 27648c2654abSrjs break; 27658c2654abSrjs } 27668c2654abSrjs s_info = sopt->sopt_data; 27678c2654abSrjs 27688c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 27698c2654abSrjs SCTP_INP_RLOCK(inp); 27708c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 27718c2654abSrjs if (stcb) { 27728c2654abSrjs SCTP_TCB_LOCK(stcb); 27738c2654abSrjs } 27748c2654abSrjs SCTP_INP_RUNLOCK(inp); 27758c2654abSrjs } else 27768c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id); 27778c2654abSrjs 27788c2654abSrjs if (stcb == NULL) { 27798c2654abSrjs error = ENOENT; 27808c2654abSrjs break; 27818c2654abSrjs } 27828c2654abSrjs /* Validate things */ 27838c2654abSrjs if (s_info->sinfo_stream > stcb->asoc.streamoutcnt) { 27848c2654abSrjs SCTP_TCB_UNLOCK(stcb); 27858c2654abSrjs error = EINVAL; 27868c2654abSrjs break; 27878c2654abSrjs } 27888c2654abSrjs /* Mask off the flags that are allowed */ 27898c2654abSrjs s_info->sinfo_flags = (s_info->sinfo_flags & 279020ba2d4fSrjs (SCTP_UNORDERED | SCTP_ADDR_OVER | 279120ba2d4fSrjs SCTP_PR_SCTP_TTL | SCTP_PR_SCTP_BUF)); 27928c2654abSrjs /* Copy it in */ 27938c2654abSrjs stcb->asoc.def_send = *s_info; 27948c2654abSrjs SCTP_TCB_UNLOCK(stcb); 27958c2654abSrjs } 27968c2654abSrjs break; 27978c2654abSrjs case SCTP_PEER_ADDR_PARAMS: 27988c2654abSrjs { 27998c2654abSrjs struct sctp_paddrparams *paddrp; 28008c2654abSrjs struct sctp_nets *net; 28018c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_paddrparams)) { 28028c2654abSrjs error = EINVAL; 28038c2654abSrjs break; 28048c2654abSrjs } 28058c2654abSrjs paddrp = sopt->sopt_data; 28068c2654abSrjs net = NULL; 28078c2654abSrjs if (paddrp->spp_assoc_id) { 28088c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 28098c2654abSrjs SCTP_INP_RLOCK(inp); 28108c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 28118c2654abSrjs if (stcb) { 28128c2654abSrjs SCTP_TCB_LOCK(stcb); 28138c2654abSrjs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 28148c2654abSrjs } 28158c2654abSrjs SCTP_INP_RUNLOCK(inp); 28168c2654abSrjs } else 28178c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id); 28188c2654abSrjs if (stcb == NULL) { 28198c2654abSrjs error = ENOENT; 28208c2654abSrjs break; 28218c2654abSrjs } 28228c2654abSrjs 28238c2654abSrjs } 28248c2654abSrjs if ((stcb == NULL) && 28258c2654abSrjs ((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) || 28268c2654abSrjs (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) { 28278c2654abSrjs /* Lookup via address */ 28288c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 28298c2654abSrjs SCTP_INP_RLOCK(inp); 28308c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 28318c2654abSrjs if (stcb) { 28328c2654abSrjs SCTP_TCB_LOCK(stcb); 28338c2654abSrjs net = sctp_findnet(stcb, 28348c2654abSrjs (struct sockaddr *)&paddrp->spp_address); 28358c2654abSrjs } 28368c2654abSrjs SCTP_INP_RUNLOCK(inp); 28378c2654abSrjs } else { 28388c2654abSrjs SCTP_INP_WLOCK(inp); 28398c2654abSrjs SCTP_INP_INCR_REF(inp); 28408c2654abSrjs SCTP_INP_WUNLOCK(inp); 28418c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, 28428c2654abSrjs (struct sockaddr *)&paddrp->spp_address, 28438c2654abSrjs &net, NULL, NULL); 28448c2654abSrjs if (stcb == NULL) { 28458c2654abSrjs SCTP_INP_WLOCK(inp); 28468c2654abSrjs SCTP_INP_DECR_REF(inp); 28478c2654abSrjs SCTP_INP_WUNLOCK(inp); 28488c2654abSrjs } 28498c2654abSrjs } 28508c2654abSrjs } else { 28518c2654abSrjs /* Effects the Endpoint */ 28528c2654abSrjs stcb = NULL; 28538c2654abSrjs } 28548c2654abSrjs if (stcb) { 28558c2654abSrjs /* Applies to the specific association */ 28568c2654abSrjs if (paddrp->spp_pathmaxrxt) { 28578c2654abSrjs if (net) { 28588c2654abSrjs if (paddrp->spp_pathmaxrxt) 28598c2654abSrjs net->failure_threshold = paddrp->spp_pathmaxrxt; 28608c2654abSrjs } else { 28618c2654abSrjs if (paddrp->spp_pathmaxrxt) 28628c2654abSrjs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 28638c2654abSrjs } 28648c2654abSrjs } 28658c2654abSrjs if ((paddrp->spp_hbinterval != 0) && (paddrp->spp_hbinterval != 0xffffffff)) { 28668c2654abSrjs /* Just a set */ 28678c2654abSrjs int old; 28688c2654abSrjs if (net) { 28698c2654abSrjs net->dest_state &= ~SCTP_ADDR_NOHB; 28708c2654abSrjs } else { 28718c2654abSrjs old = stcb->asoc.heart_beat_delay; 28728c2654abSrjs stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 28738c2654abSrjs if (old == 0) { 28748c2654abSrjs /* Turn back on the timer */ 28758c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 28768c2654abSrjs } 28778c2654abSrjs } 28788c2654abSrjs } else if (paddrp->spp_hbinterval == 0xffffffff) { 28798c2654abSrjs /* on demand HB */ 28808c2654abSrjs sctp_send_hb(stcb, 1, net); 28818c2654abSrjs } else { 28828c2654abSrjs if (net == NULL) { 28838c2654abSrjs /* off on association */ 28848c2654abSrjs if (stcb->asoc.heart_beat_delay) { 28858c2654abSrjs int cnt_of_unconf = 0; 28868c2654abSrjs struct sctp_nets *lnet; 28878c2654abSrjs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 28888c2654abSrjs if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) { 28898c2654abSrjs cnt_of_unconf++; 28908c2654abSrjs } 28918c2654abSrjs } 28928c2654abSrjs /* stop the timer ONLY if we have no unconfirmed addresses 28938c2654abSrjs */ 28948c2654abSrjs if (cnt_of_unconf == 0) 28958c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 28968c2654abSrjs } 28978c2654abSrjs stcb->asoc.heart_beat_delay = 0; 28988c2654abSrjs } else { 28998c2654abSrjs net->dest_state |= SCTP_ADDR_NOHB; 29008c2654abSrjs } 29018c2654abSrjs } 29028c2654abSrjs SCTP_TCB_UNLOCK(stcb); 29038c2654abSrjs } else { 29048c2654abSrjs /* Use endpoint defaults */ 29058c2654abSrjs SCTP_INP_WLOCK(inp); 29068c2654abSrjs if (paddrp->spp_pathmaxrxt) 29078c2654abSrjs inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 29088c2654abSrjs if (paddrp->spp_hbinterval != SCTP_ISSUE_HB) 29098c2654abSrjs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = paddrp->spp_hbinterval; 29108c2654abSrjs SCTP_INP_WUNLOCK(inp); 29118c2654abSrjs } 29128c2654abSrjs } 29138c2654abSrjs break; 29148c2654abSrjs case SCTP_RTOINFO: 29158c2654abSrjs { 29168c2654abSrjs struct sctp_rtoinfo *srto; 29178c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_rtoinfo)) { 29188c2654abSrjs error = EINVAL; 29198c2654abSrjs break; 29208c2654abSrjs } 29218c2654abSrjs srto = sopt->sopt_data; 29228c2654abSrjs if (srto->srto_assoc_id == 0) { 29238c2654abSrjs SCTP_INP_WLOCK(inp); 29248c2654abSrjs /* If we have a null asoc, its default for the endpoint */ 29258c2654abSrjs if (srto->srto_initial > 10) 29268c2654abSrjs inp->sctp_ep.initial_rto = srto->srto_initial; 29278c2654abSrjs if (srto->srto_max > 10) 29288c2654abSrjs inp->sctp_ep.sctp_maxrto = srto->srto_max; 29298c2654abSrjs if (srto->srto_min > 10) 29308c2654abSrjs inp->sctp_ep.sctp_minrto = srto->srto_min; 29318c2654abSrjs SCTP_INP_WUNLOCK(inp); 29328c2654abSrjs break; 29338c2654abSrjs } 29348c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 29358c2654abSrjs SCTP_INP_RLOCK(inp); 29368c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 29378c2654abSrjs if (stcb) { 29388c2654abSrjs SCTP_TCB_LOCK(stcb); 29398c2654abSrjs } 29408c2654abSrjs SCTP_INP_RUNLOCK(inp); 29418c2654abSrjs } else 29428c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id); 29438c2654abSrjs if (stcb == NULL) { 29448c2654abSrjs error = EINVAL; 29458c2654abSrjs break; 29468c2654abSrjs } 29478c2654abSrjs /* Set in ms we hope :-) */ 29488c2654abSrjs if (srto->srto_initial > 10) 29498c2654abSrjs stcb->asoc.initial_rto = srto->srto_initial; 29508c2654abSrjs if (srto->srto_max > 10) 29518c2654abSrjs stcb->asoc.maxrto = srto->srto_max; 29528c2654abSrjs if (srto->srto_min > 10) 29538c2654abSrjs stcb->asoc.minrto = srto->srto_min; 29548c2654abSrjs SCTP_TCB_UNLOCK(stcb); 29558c2654abSrjs } 29568c2654abSrjs break; 29578c2654abSrjs case SCTP_ASSOCINFO: 29588c2654abSrjs { 29598c2654abSrjs struct sctp_assocparams *sasoc; 29608c2654abSrjs 29618c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_assocparams)) { 29628c2654abSrjs error = EINVAL; 29638c2654abSrjs break; 29648c2654abSrjs } 29658c2654abSrjs sasoc = sopt->sopt_data; 29668c2654abSrjs if (sasoc->sasoc_assoc_id) { 29678c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 29688c2654abSrjs SCTP_INP_RLOCK(inp); 29698c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 29708c2654abSrjs if (stcb) { 29718c2654abSrjs SCTP_TCB_LOCK(stcb); 29728c2654abSrjs } 29738c2654abSrjs SCTP_INP_RUNLOCK(inp); 29748c2654abSrjs } else 29758c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, 29768c2654abSrjs sasoc->sasoc_assoc_id); 29778c2654abSrjs if (stcb == NULL) { 29788c2654abSrjs error = ENOENT; 29798c2654abSrjs break; 29808c2654abSrjs } 29818c2654abSrjs 29828c2654abSrjs } else { 29838c2654abSrjs stcb = NULL; 29848c2654abSrjs } 29858c2654abSrjs if (stcb) { 29868c2654abSrjs if (sasoc->sasoc_asocmaxrxt) 29878c2654abSrjs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 29888c2654abSrjs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 29898c2654abSrjs sasoc->sasoc_peer_rwnd = 0; 29908c2654abSrjs sasoc->sasoc_local_rwnd = 0; 29918c2654abSrjs if (stcb->asoc.cookie_life) 29928c2654abSrjs stcb->asoc.cookie_life = sasoc->sasoc_cookie_life; 29938c2654abSrjs SCTP_TCB_UNLOCK(stcb); 29948c2654abSrjs } else { 29958c2654abSrjs SCTP_INP_WLOCK(inp); 29968c2654abSrjs if (sasoc->sasoc_asocmaxrxt) 29978c2654abSrjs inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 29988c2654abSrjs sasoc->sasoc_number_peer_destinations = 0; 29998c2654abSrjs sasoc->sasoc_peer_rwnd = 0; 30008c2654abSrjs sasoc->sasoc_local_rwnd = 0; 30018c2654abSrjs if (sasoc->sasoc_cookie_life) 30028c2654abSrjs inp->sctp_ep.def_cookie_life = sasoc->sasoc_cookie_life; 30038c2654abSrjs SCTP_INP_WUNLOCK(inp); 30048c2654abSrjs } 30058c2654abSrjs } 30068c2654abSrjs break; 30078c2654abSrjs case SCTP_INITMSG: 30088c2654abSrjs { 30098c2654abSrjs struct sctp_initmsg *sinit; 30108c2654abSrjs 30118c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_initmsg)) { 30128c2654abSrjs error = EINVAL; 30138c2654abSrjs break; 30148c2654abSrjs } 30158c2654abSrjs sinit = sopt->sopt_data; 30168c2654abSrjs SCTP_INP_WLOCK(inp); 30178c2654abSrjs if (sinit->sinit_num_ostreams) 30188c2654abSrjs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 30198c2654abSrjs 30208c2654abSrjs if (sinit->sinit_max_instreams) 30218c2654abSrjs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 30228c2654abSrjs 30238c2654abSrjs if (sinit->sinit_max_attempts) 30248c2654abSrjs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 30258c2654abSrjs 30268c2654abSrjs if (sinit->sinit_max_init_timeo > 10) 30278c2654abSrjs /* We must be at least a 100ms (we set in ticks) */ 30288c2654abSrjs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 30298c2654abSrjs SCTP_INP_WUNLOCK(inp); 30308c2654abSrjs } 30318c2654abSrjs break; 30328c2654abSrjs case SCTP_PRIMARY_ADDR: 30338c2654abSrjs { 30348c2654abSrjs struct sctp_setprim *spa; 30358c2654abSrjs struct sctp_nets *net, *lnet; 30368c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_setprim)) { 30378c2654abSrjs error = EINVAL; 30388c2654abSrjs break; 30398c2654abSrjs } 30408c2654abSrjs spa = sopt->sopt_data; 30418c2654abSrjs 30428c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 30438c2654abSrjs SCTP_INP_RLOCK(inp); 30448c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 30458c2654abSrjs if (stcb) { 30468c2654abSrjs SCTP_TCB_LOCK(stcb); 30478c2654abSrjs } else { 30488c2654abSrjs error = EINVAL; 30498c2654abSrjs break; 30508c2654abSrjs } 30518c2654abSrjs SCTP_INP_RUNLOCK(inp); 30528c2654abSrjs } else 30538c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, spa->ssp_assoc_id); 30548c2654abSrjs if (stcb == NULL) { 30558c2654abSrjs /* One last shot */ 30568c2654abSrjs SCTP_INP_WLOCK(inp); 30578c2654abSrjs SCTP_INP_INCR_REF(inp); 30588c2654abSrjs SCTP_INP_WUNLOCK(inp); 30598c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, 30608c2654abSrjs (struct sockaddr *)&spa->ssp_addr, 30618c2654abSrjs &net, NULL, NULL); 30628c2654abSrjs if (stcb == NULL) { 30638c2654abSrjs SCTP_INP_WLOCK(inp); 30648c2654abSrjs SCTP_INP_DECR_REF(inp); 30658c2654abSrjs SCTP_INP_WUNLOCK(inp); 30668c2654abSrjs error = EINVAL; 30678c2654abSrjs break; 30688c2654abSrjs } 30698c2654abSrjs } else { 30708c2654abSrjs /* find the net, associd or connected lookup type */ 30718c2654abSrjs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 30728c2654abSrjs if (net == NULL) { 30738c2654abSrjs SCTP_TCB_UNLOCK(stcb); 30748c2654abSrjs error = EINVAL; 30758c2654abSrjs break; 30768c2654abSrjs } 30778c2654abSrjs } 30788c2654abSrjs if ((net != stcb->asoc.primary_destination) && 30798c2654abSrjs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 30808c2654abSrjs /* Ok we need to set it */ 30818c2654abSrjs lnet = stcb->asoc.primary_destination; 30828c2654abSrjs lnet->next_tsn_at_change = net->next_tsn_at_change = stcb->asoc.sending_seq; 30838c2654abSrjs if (sctp_set_primary_addr(stcb, 30848c2654abSrjs (struct sockaddr *)NULL, 30858c2654abSrjs net) == 0) { 30868c2654abSrjs if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 30878c2654abSrjs net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH; 30888c2654abSrjs } 30898c2654abSrjs net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY; 30908c2654abSrjs } 30918c2654abSrjs } 30928c2654abSrjs SCTP_TCB_UNLOCK(stcb); 30938c2654abSrjs } 30948c2654abSrjs break; 30958c2654abSrjs 30968c2654abSrjs case SCTP_SET_PEER_PRIMARY_ADDR: 30978c2654abSrjs { 30988c2654abSrjs struct sctp_setpeerprim *sspp; 30998c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_setpeerprim)) { 31008c2654abSrjs error = EINVAL; 31018c2654abSrjs break; 31028c2654abSrjs } 31038c2654abSrjs sspp = sopt->sopt_data; 31048c2654abSrjs 31058c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 31068c2654abSrjs SCTP_INP_RLOCK(inp); 31078c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 31088c2654abSrjs if (stcb) { 31098c2654abSrjs SCTP_TCB_UNLOCK(stcb); 31108c2654abSrjs } 31118c2654abSrjs SCTP_INP_RUNLOCK(inp); 31128c2654abSrjs } else 31138c2654abSrjs stcb = sctp_findassociation_ep_asocid(inp, sspp->sspp_assoc_id); 31148c2654abSrjs if (stcb == NULL) { 31158c2654abSrjs error = EINVAL; 31168c2654abSrjs break; 31178c2654abSrjs } 31188c2654abSrjs if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) { 31198c2654abSrjs error = EINVAL; 31208c2654abSrjs } 31218c2654abSrjs SCTP_TCB_UNLOCK(stcb); 31228c2654abSrjs } 31238c2654abSrjs break; 31248c2654abSrjs case SCTP_BINDX_ADD_ADDR: 31258c2654abSrjs { 31268c2654abSrjs struct sctp_getaddresses *addrs; 31278c2654abSrjs struct sockaddr *addr_touse; 31288c2654abSrjs struct sockaddr_in sin; 31298c2654abSrjs /* see if we're bound all already! */ 31308c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 31318c2654abSrjs error = EINVAL; 31328c2654abSrjs break; 31338c2654abSrjs } 31348c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) { 31358c2654abSrjs error = EINVAL; 31368c2654abSrjs break; 31378c2654abSrjs } 31388c2654abSrjs addrs = sopt->sopt_data; 31398c2654abSrjs addr_touse = addrs->addr; 31408c2654abSrjs if (addrs->addr->sa_family == AF_INET6) { 31418c2654abSrjs struct sockaddr_in6 *sin6; 31428c2654abSrjs sin6 = (struct sockaddr_in6 *)addr_touse; 31438c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 31448c2654abSrjs in6_sin6_2_sin(&sin, sin6); 31458c2654abSrjs addr_touse = (struct sockaddr *)&sin; 31468c2654abSrjs } 31478c2654abSrjs } 31488c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 31498c2654abSrjs error = sctp_inpcb_bind(so, addr_touse, curlwp); 31508c2654abSrjs break; 31518c2654abSrjs } 31528c2654abSrjs /* No locks required here since bind and mgmt_ep_sa all 31538c2654abSrjs * do their own locking. If we do something for the FIX: 31548c2654abSrjs * below we may need to lock in that case. 31558c2654abSrjs */ 31568c2654abSrjs if (addrs->sget_assoc_id == 0) { 31578c2654abSrjs /* add the address */ 31588c2654abSrjs struct sctp_inpcb *lep; 31598c2654abSrjs ((struct sockaddr_in *)addr_touse)->sin_port = inp->sctp_lport; 31608c2654abSrjs lep = sctp_pcb_findep(addr_touse, 1, 0); 31618c2654abSrjs if (lep != NULL) { 31628c2654abSrjs /* We must decrement the refcount 31638c2654abSrjs * since we have the ep already and 31648c2654abSrjs * are binding. No remove going on 31658c2654abSrjs * here. 31668c2654abSrjs */ 31678c2654abSrjs SCTP_INP_WLOCK(inp); 31688c2654abSrjs SCTP_INP_DECR_REF(inp); 31698c2654abSrjs SCTP_INP_WUNLOCK(inp); 31708c2654abSrjs } 31718c2654abSrjs if (lep == inp) { 31728c2654abSrjs /* already bound to it.. ok */ 31738c2654abSrjs break; 31748c2654abSrjs } else if (lep == NULL) { 31758c2654abSrjs ((struct sockaddr_in *)addr_touse)->sin_port = 0; 31768c2654abSrjs error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 31778c2654abSrjs SCTP_ADD_IP_ADDRESS); 31788c2654abSrjs } else { 31798c2654abSrjs error = EADDRNOTAVAIL; 31808c2654abSrjs } 31818c2654abSrjs if (error) 31828c2654abSrjs break; 31838c2654abSrjs 31848c2654abSrjs } else { 31858c2654abSrjs /* FIX: decide whether we allow assoc based bindx */ 31868c2654abSrjs } 31878c2654abSrjs } 31888c2654abSrjs break; 31898c2654abSrjs case SCTP_BINDX_REM_ADDR: 31908c2654abSrjs { 31918c2654abSrjs struct sctp_getaddresses *addrs; 31928c2654abSrjs struct sockaddr *addr_touse; 31938c2654abSrjs struct sockaddr_in sin; 31948c2654abSrjs /* see if we're bound all already! */ 31958c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 31968c2654abSrjs error = EINVAL; 31978c2654abSrjs break; 31988c2654abSrjs } 31998c2654abSrjs if (sopt->sopt_size < sizeof(struct sctp_getaddresses)) { 32008c2654abSrjs error = EINVAL; 32018c2654abSrjs break; 32028c2654abSrjs } 32038c2654abSrjs addrs = sopt->sopt_data; 32048c2654abSrjs addr_touse = addrs->addr; 32058c2654abSrjs if (addrs->addr->sa_family == AF_INET6) { 32068c2654abSrjs struct sockaddr_in6 *sin6; 32078c2654abSrjs sin6 = (struct sockaddr_in6 *)addr_touse; 32088c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 32098c2654abSrjs in6_sin6_2_sin(&sin, sin6); 32108c2654abSrjs addr_touse = (struct sockaddr *)&sin; 32118c2654abSrjs } 32128c2654abSrjs } 32138c2654abSrjs /* No lock required mgmt_ep_sa does its own locking. If 32148c2654abSrjs * the FIX: below is ever changed we may need to 32158c2654abSrjs * lock before calling association level binding. 32168c2654abSrjs */ 32178c2654abSrjs if (addrs->sget_assoc_id == 0) { 32188c2654abSrjs /* delete the address */ 32198c2654abSrjs sctp_addr_mgmt_ep_sa(inp, addr_touse, 32208c2654abSrjs SCTP_DEL_IP_ADDRESS); 32218c2654abSrjs } else { 32228c2654abSrjs /* FIX: decide whether we allow assoc based bindx */ 32238c2654abSrjs } 32248c2654abSrjs } 32258c2654abSrjs break; 32268c2654abSrjs default: 32278c2654abSrjs error = ENOPROTOOPT; 32288c2654abSrjs break; 32298c2654abSrjs } /* end switch (opt) */ 32308c2654abSrjs return (error); 32318c2654abSrjs } 32328c2654abSrjs 32338c2654abSrjs int 32348c2654abSrjs sctp_ctloutput(int op, struct socket *so, struct sockopt *sopt) 32358c2654abSrjs { 32368c2654abSrjs int s, error = 0; 32378c2654abSrjs struct inpcb *inp; 32388c2654abSrjs #ifdef INET6 32398c2654abSrjs struct in6pcb *in6p; 32408c2654abSrjs #endif 32418c2654abSrjs int family; /* family of the socket */ 32428c2654abSrjs 32438c2654abSrjs family = so->so_proto->pr_domain->dom_family; 32448c2654abSrjs 32458c2654abSrjs s = splsoftnet(); 32468c2654abSrjs switch (family) { 32478c2654abSrjs case PF_INET: 32488c2654abSrjs inp = sotoinpcb(so); 32498c2654abSrjs #ifdef INET6 32508c2654abSrjs in6p = NULL; 32518c2654abSrjs #endif 32528c2654abSrjs break; 32538c2654abSrjs #ifdef INET6 32548c2654abSrjs case PF_INET6: 32558c2654abSrjs inp = NULL; 32568c2654abSrjs in6p = sotoin6pcb(so); 32578c2654abSrjs break; 32588c2654abSrjs #endif 32598c2654abSrjs default: 32608c2654abSrjs splx(s); 32618c2654abSrjs return EAFNOSUPPORT; 32628c2654abSrjs } 32638c2654abSrjs #ifndef INET6 32648c2654abSrjs if (inp == NULL) 32658c2654abSrjs #else 32668c2654abSrjs if (inp == NULL && in6p == NULL) 32678c2654abSrjs #endif 32688c2654abSrjs { 32698c2654abSrjs splx(s); 32708c2654abSrjs return (ECONNRESET); 32718c2654abSrjs } 32728c2654abSrjs if (sopt->sopt_level != IPPROTO_SCTP) { 32738c2654abSrjs switch (family) { 32748c2654abSrjs case PF_INET: 32758c2654abSrjs error = ip_ctloutput(op, so, sopt); 32768c2654abSrjs break; 32778c2654abSrjs #ifdef INET6 32788c2654abSrjs case PF_INET6: 32798c2654abSrjs error = ip6_ctloutput(op, so, sopt); 32808c2654abSrjs break; 32818c2654abSrjs #endif 32828c2654abSrjs } 32838c2654abSrjs splx(s); 32848c2654abSrjs return (error); 32858c2654abSrjs } 32868c2654abSrjs /* Ok if we reach here it is a SCTP option we hope */ 32878c2654abSrjs if (op == PRCO_SETOPT) { 32888c2654abSrjs error = sctp_optsset(so, sopt); 32898c2654abSrjs } else if (op == PRCO_GETOPT) { 32908c2654abSrjs error = sctp_optsget(so, sopt); 32918c2654abSrjs } else { 32928c2654abSrjs error = EINVAL; 32938c2654abSrjs } 32948c2654abSrjs splx(s); 32958c2654abSrjs return (error); 32968c2654abSrjs } 32978c2654abSrjs 32988c2654abSrjs static int 32998c2654abSrjs sctp_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 33008c2654abSrjs { 33018c2654abSrjs int error = 0; 33028c2654abSrjs struct sctp_inpcb *inp; 33038c2654abSrjs struct sctp_tcb *stcb; 33048c2654abSrjs 33058c2654abSrjs KASSERT(solocked(so)); 33068c2654abSrjs #ifdef SCTP_DEBUG 33078c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) { 33088c2654abSrjs printf("Connect called in SCTP to "); 33098c2654abSrjs sctp_print_address(nam); 33108c2654abSrjs printf("Port %d\n", ntohs(((struct sockaddr_in *)nam)->sin_port)); 33118c2654abSrjs } 33128c2654abSrjs #endif /* SCTP_DEBUG */ 33138c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 33148c2654abSrjs if (inp == 0) { 33158c2654abSrjs /* I made the same as TCP since we are not setup? */ 33168c2654abSrjs return (ECONNRESET); 33178c2654abSrjs } 33188c2654abSrjs SCTP_ASOC_CREATE_LOCK(inp); 33198c2654abSrjs #ifdef SCTP_DEBUG 33208c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) { 33218c2654abSrjs printf("After ASOC lock\n"); 33228c2654abSrjs } 33238c2654abSrjs #endif /* SCTP_DEBUG */ 33248c2654abSrjs SCTP_INP_WLOCK(inp); 33258c2654abSrjs #ifdef SCTP_DEBUG 33268c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) { 33278c2654abSrjs printf("After INP_WLOCK lock\n"); 33288c2654abSrjs } 33298c2654abSrjs #endif /* SCTP_DEBUG */ 33308c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 33318c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 33328c2654abSrjs /* Should I really unlock ? */ 33338c2654abSrjs SCTP_INP_WUNLOCK(inp); 33348c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 33358c2654abSrjs return (EFAULT); 33368c2654abSrjs } 33378c2654abSrjs #ifdef INET6 33388c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 33398c2654abSrjs (nam->sa_family == AF_INET6)) { 33408c2654abSrjs SCTP_INP_WUNLOCK(inp); 33418c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 33428c2654abSrjs return (EINVAL); 33438c2654abSrjs } 33448c2654abSrjs #endif /* INET6 */ 3345d26f60daSmaxv 3346d26f60daSmaxv /* 3347d26f60daSmaxv * XXX XXX XXX Check nam->sa_len? 3348d26f60daSmaxv */ 3349d26f60daSmaxv 33508c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 33518c2654abSrjs SCTP_PCB_FLAGS_UNBOUND) { 33528c2654abSrjs /* Bind a ephemeral port */ 33538c2654abSrjs SCTP_INP_WUNLOCK(inp); 33548c2654abSrjs error = sctp_inpcb_bind(so, NULL, l); 33558c2654abSrjs if (error) { 33568c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 33578c2654abSrjs return (error); 33588c2654abSrjs } 33598c2654abSrjs SCTP_INP_WLOCK(inp); 33608c2654abSrjs } 33618c2654abSrjs #ifdef SCTP_DEBUG 33628c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) { 33638c2654abSrjs printf("After bind\n"); 33648c2654abSrjs } 33658c2654abSrjs #endif /* SCTP_DEBUG */ 33668c2654abSrjs /* Now do we connect? */ 33678c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 33688c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 33698c2654abSrjs /* We are already connected AND the TCP model */ 33708c2654abSrjs SCTP_INP_WUNLOCK(inp); 33718c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 33728c2654abSrjs return (EADDRINUSE); 33738c2654abSrjs } 33748c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 33758c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 33768c2654abSrjs if (stcb) { 33778c2654abSrjs SCTP_TCB_UNLOCK(stcb); 33788c2654abSrjs } 33798c2654abSrjs SCTP_INP_WUNLOCK(inp); 33808c2654abSrjs } else { 33818c2654abSrjs SCTP_INP_INCR_REF(inp); 33828c2654abSrjs SCTP_INP_WUNLOCK(inp); 33838c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, nam, NULL, NULL, NULL); 33848c2654abSrjs if (stcb == NULL) { 33858c2654abSrjs SCTP_INP_WLOCK(inp); 33868c2654abSrjs SCTP_INP_DECR_REF(inp); 33878c2654abSrjs SCTP_INP_WUNLOCK(inp); 33888c2654abSrjs } 33898c2654abSrjs } 33908c2654abSrjs if (stcb != NULL) { 33918c2654abSrjs /* Already have or am bring up an association */ 33928c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 33938c2654abSrjs SCTP_TCB_UNLOCK(stcb); 33948c2654abSrjs return (EALREADY); 33958c2654abSrjs } 33968c2654abSrjs /* We are GOOD to go */ 33978c2654abSrjs stcb = sctp_aloc_assoc(inp, nam, 1, &error, 0); 33988c2654abSrjs if (stcb == NULL) { 33998c2654abSrjs /* Gak! no memory */ 34008c2654abSrjs return (error); 34018c2654abSrjs } 34028c2654abSrjs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 34038c2654abSrjs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 34048c2654abSrjs /* Set the connected flag so we can queue data */ 34058c2654abSrjs soisconnecting(so); 34068c2654abSrjs } 34078c2654abSrjs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 34088c2654abSrjs SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 34098c2654abSrjs sctp_send_initiate(inp, stcb); 34108c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp); 34118c2654abSrjs SCTP_TCB_UNLOCK(stcb); 34128c2654abSrjs return error; 34138c2654abSrjs } 34148c2654abSrjs 34158c2654abSrjs static int 34168c2654abSrjs sctp_connect2(struct socket *so, struct socket *so2) 34178c2654abSrjs { 34188c2654abSrjs KASSERT(solocked(so)); 34198c2654abSrjs 34208c2654abSrjs return EOPNOTSUPP; 34218c2654abSrjs } 34228c2654abSrjs 34238c2654abSrjs int 34248c2654abSrjs sctp_rcvd(struct socket *so, int flags, struct lwp *l) 34258c2654abSrjs { 34268c2654abSrjs struct sctp_socket_q_list *sq=NULL; 34278c2654abSrjs /* 34288c2654abSrjs * The user has received some data, we may be able to stuff more 34298c2654abSrjs * up the socket. And we need to possibly update the rwnd. 34308c2654abSrjs */ 34318c2654abSrjs struct sctp_inpcb *inp; 34328c2654abSrjs struct sctp_tcb *stcb=NULL; 34338c2654abSrjs 34348c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 34358c2654abSrjs #ifdef SCTP_DEBUG 34368c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) 34378c2654abSrjs printf("Read for so:%p inp:%p Flags:%x\n", 34388c2654abSrjs so, inp, flags); 34398c2654abSrjs #endif 34408c2654abSrjs 34418c2654abSrjs if (inp == 0) { 34428c2654abSrjs /* I made the same as TCP since we are not setup? */ 34438c2654abSrjs #ifdef SCTP_DEBUG 34448c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) 34458c2654abSrjs printf("Nope, connection reset\n"); 34468c2654abSrjs #endif 34478c2654abSrjs return (ECONNRESET); 34488c2654abSrjs } 34498c2654abSrjs /* 34508c2654abSrjs * Grab the first one on the list. It will re-insert itself if 34518c2654abSrjs * it runs out of room 34528c2654abSrjs */ 34538c2654abSrjs SCTP_INP_WLOCK(inp); 34548c2654abSrjs if ((flags & MSG_EOR) && ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) 34558c2654abSrjs && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 34568c2654abSrjs /* Ok the other part of our grubby tracking 34578c2654abSrjs * stuff for our horrible layer violation that 34588c2654abSrjs * the tsvwg thinks is ok for sctp_peeloff.. gak! 34598c2654abSrjs * We must update the next vtag pending on the 34608c2654abSrjs * socket buffer (if any). 34618c2654abSrjs */ 34628c2654abSrjs inp->sctp_vtag_first = sctp_get_first_vtag_from_sb(so); 34638c2654abSrjs sq = TAILQ_FIRST(&inp->sctp_queue_list); 34648c2654abSrjs if (sq) { 34658c2654abSrjs stcb = sq->tcb; 34668c2654abSrjs } else { 34678c2654abSrjs stcb = NULL; 34688c2654abSrjs } 34698c2654abSrjs } else { 34708c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 34718c2654abSrjs } 34728c2654abSrjs if (stcb) { 34738c2654abSrjs SCTP_TCB_LOCK(stcb); 34748c2654abSrjs } 34758c2654abSrjs if (stcb) { 34768c2654abSrjs long incr; 34778c2654abSrjs /* all code in normal stcb path assumes 34788c2654abSrjs * that you have a tcb_lock only. Thus 34798c2654abSrjs * we must release the inp write lock. 34808c2654abSrjs */ 34818c2654abSrjs if (flags & MSG_EOR) { 34828c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) 34838c2654abSrjs && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 34848c2654abSrjs stcb = sctp_remove_from_socket_q(inp); 34858c2654abSrjs } 34868c2654abSrjs #ifdef SCTP_DEBUG 34878c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) 34888c2654abSrjs printf("remove from socket queue for inp:%p tcbret:%p\n", 34898c2654abSrjs inp, stcb); 34908c2654abSrjs #endif 34918c2654abSrjs 34928c2654abSrjs stcb->asoc.my_rwnd_control_len = sctp_sbspace_sub(stcb->asoc.my_rwnd_control_len, 34938c2654abSrjs sizeof(struct mbuf)); 34948c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_RECVDATAIOEVNT) { 34958c2654abSrjs stcb->asoc.my_rwnd_control_len = sctp_sbspace_sub(stcb->asoc.my_rwnd_control_len, 34968c2654abSrjs CMSG_LEN(sizeof(struct sctp_sndrcvinfo))); 34978c2654abSrjs } 34988c2654abSrjs } 34998c2654abSrjs if ((TAILQ_EMPTY(&stcb->asoc.delivery_queue) == 0) || 35008c2654abSrjs (TAILQ_EMPTY(&stcb->asoc.reasmqueue) == 0)) { 35018c2654abSrjs /* Deliver if there is something to be delivered */ 35028c2654abSrjs sctp_service_queues(stcb, &stcb->asoc, 1); 35038c2654abSrjs } 35048c2654abSrjs sctp_set_rwnd(stcb, &stcb->asoc); 35058c2654abSrjs /* if we increase by 1 or more MTU's (smallest MTUs of all 35068c2654abSrjs * nets) we send a window update sack 35078c2654abSrjs */ 35088c2654abSrjs incr = stcb->asoc.my_rwnd - stcb->asoc.my_last_reported_rwnd; 35098c2654abSrjs if (incr < 0) { 35108c2654abSrjs incr = 0; 35118c2654abSrjs } 35128c2654abSrjs if (((uint32_t)incr >= (stcb->asoc.smallest_mtu * SCTP_SEG_TO_RWND_UPD)) || 35138c2654abSrjs ((((uint32_t)incr)*SCTP_SCALE_OF_RWND_TO_UPD) >= so->so_rcv.sb_hiwat)) { 35148c2654abSrjs if (callout_pending(&stcb->asoc.dack_timer.timer)) { 35158c2654abSrjs /* If the timer is up, stop it */ 35168c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_RECV, 35178c2654abSrjs stcb->sctp_ep, stcb, NULL); 35188c2654abSrjs } 35198c2654abSrjs /* Send the sack, with the new rwnd */ 35208c2654abSrjs sctp_send_sack(stcb); 35218c2654abSrjs /* Now do the output */ 35228c2654abSrjs sctp_chunk_output(inp, stcb, 10); 35238c2654abSrjs } 35248c2654abSrjs } else { 35258c2654abSrjs if ((( sq ) && (flags & MSG_EOR) && ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0)) 35268c2654abSrjs && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 35278c2654abSrjs stcb = sctp_remove_from_socket_q(inp); 35288c2654abSrjs } 35298c2654abSrjs } 35308c2654abSrjs if ((so->so_rcv.sb_mb == NULL) && 35318c2654abSrjs (TAILQ_EMPTY(&inp->sctp_queue_list) == 0)) { 35328c2654abSrjs int sq_cnt=0; 35338c2654abSrjs #ifdef SCTP_DEBUG 35348c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) 35358c2654abSrjs printf("Something off, inp:%p so->so_rcv->sb_mb is empty and sockq is not.. cleaning\n", 35368c2654abSrjs inp); 35378c2654abSrjs #endif 35388c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) 35398c2654abSrjs && ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 35408c2654abSrjs int done_yet; 35418c2654abSrjs done_yet = TAILQ_EMPTY(&inp->sctp_queue_list); 35428c2654abSrjs while (!done_yet) { 35438c2654abSrjs sq_cnt++; 35448c2654abSrjs (void)sctp_remove_from_socket_q(inp); 35458c2654abSrjs done_yet = TAILQ_EMPTY(&inp->sctp_queue_list); 35468c2654abSrjs } 35478c2654abSrjs } 35488c2654abSrjs #ifdef SCTP_DEBUG 35498c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_USRREQ2) 35508c2654abSrjs printf("Cleaned up %d sockq's\n", sq_cnt); 35518c2654abSrjs #endif 35528c2654abSrjs } 35538c2654abSrjs if (stcb) { 35548c2654abSrjs SCTP_TCB_UNLOCK(stcb); 35558c2654abSrjs } 35568c2654abSrjs SCTP_INP_WUNLOCK(inp); 35578c2654abSrjs return (0); 35588c2654abSrjs } 35598c2654abSrjs 35608c2654abSrjs int 35618c2654abSrjs sctp_listen(struct socket *so, struct lwp *l) 35628c2654abSrjs { 35638c2654abSrjs /* 35648c2654abSrjs * Note this module depends on the protocol processing being 35658c2654abSrjs * called AFTER any socket level flags and backlog are applied 35668c2654abSrjs * to the socket. The traditional way that the socket flags are 35678c2654abSrjs * applied is AFTER protocol processing. We have made a change 35688c2654abSrjs * to the sys/kern/uipc_socket.c module to reverse this but this 35698c2654abSrjs * MUST be in place if the socket API for SCTP is to work properly. 35708c2654abSrjs */ 35718c2654abSrjs int error = 0; 35728c2654abSrjs struct sctp_inpcb *inp; 35738c2654abSrjs 35748c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 35758c2654abSrjs if (inp == 0) { 35768c2654abSrjs /* I made the same as TCP since we are not setup? */ 35778c2654abSrjs return (ECONNRESET); 35788c2654abSrjs } 35798c2654abSrjs SCTP_INP_RLOCK(inp); 35808c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 35818c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 35828c2654abSrjs /* We are already connected AND the TCP model */ 35838c2654abSrjs SCTP_INP_RUNLOCK(inp); 35848c2654abSrjs return (EADDRINUSE); 35858c2654abSrjs } 35868c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 35878c2654abSrjs /* We must do a bind. */ 35888c2654abSrjs SCTP_INP_RUNLOCK(inp); 35898c2654abSrjs if ((error = sctp_inpcb_bind(so, NULL, l))) { 35908c2654abSrjs /* bind error, probably perm */ 35918c2654abSrjs return (error); 35928c2654abSrjs } 35938c2654abSrjs } else { 35948c2654abSrjs SCTP_INP_RUNLOCK(inp); 35958c2654abSrjs } 35968c2654abSrjs SCTP_INP_WLOCK(inp); 35978c2654abSrjs if (inp->sctp_socket->so_qlimit) { 35988c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 35998c2654abSrjs /* 36008c2654abSrjs * For the UDP model we must TURN OFF the ACCEPT 36018c2654abSrjs * flags since we do NOT allow the accept() call. 36028c2654abSrjs * The TCP model (when present) will do accept which 36038c2654abSrjs * then prohibits connect(). 36048c2654abSrjs */ 36058c2654abSrjs inp->sctp_socket->so_options &= ~SO_ACCEPTCONN; 36068c2654abSrjs } 36078c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING; 36088c2654abSrjs } else { 36098c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING) { 36108c2654abSrjs /* 36118c2654abSrjs * Turning off the listen flags if the backlog is 36128c2654abSrjs * set to 0 (i.e. qlimit is 0). 36138c2654abSrjs */ 36148c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING; 36158c2654abSrjs } 36168c2654abSrjs inp->sctp_socket->so_options &= ~SO_ACCEPTCONN; 36178c2654abSrjs } 36188c2654abSrjs SCTP_INP_WUNLOCK(inp); 36198c2654abSrjs return (error); 36208c2654abSrjs } 36218c2654abSrjs 36228c2654abSrjs int 36238c2654abSrjs sctp_accept(struct socket *so, struct sockaddr *nam) 36248c2654abSrjs { 36258c2654abSrjs struct sctp_tcb *stcb; 36268c2654abSrjs const struct sockaddr *prim; 36278c2654abSrjs struct sctp_inpcb *inp; 36288c2654abSrjs int error; 36298c2654abSrjs 36308c2654abSrjs if (nam == NULL) { 36318c2654abSrjs return EINVAL; 36328c2654abSrjs } 36338c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 36348c2654abSrjs 36358c2654abSrjs if (inp == 0) { 36368c2654abSrjs return ECONNRESET; 36378c2654abSrjs } 36388c2654abSrjs SCTP_INP_RLOCK(inp); 36398c2654abSrjs if (so->so_state & SS_ISDISCONNECTED) { 36408c2654abSrjs SCTP_INP_RUNLOCK(inp); 36418c2654abSrjs return ECONNABORTED; 36428c2654abSrjs } 36438c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 36448c2654abSrjs if (stcb == NULL) { 36458c2654abSrjs SCTP_INP_RUNLOCK(inp); 36468c2654abSrjs return ECONNRESET; 36478c2654abSrjs } 36488c2654abSrjs SCTP_TCB_LOCK(stcb); 36498c2654abSrjs SCTP_INP_RUNLOCK(inp); 36508c2654abSrjs prim = (const struct sockaddr *)rtcache_getdst(&stcb->asoc.primary_destination->ro); 36518c2654abSrjs if (prim->sa_family == AF_INET) { 36528c2654abSrjs struct sockaddr_in *sin; 36538c2654abSrjs 36548c2654abSrjs sin = (struct sockaddr_in *)nam; 36558c2654abSrjs memset((void *)sin, 0, sizeof (*sin)); 36568c2654abSrjs 36578c2654abSrjs sin->sin_family = AF_INET; 36588c2654abSrjs sin->sin_len = sizeof(*sin); 36598c2654abSrjs sin->sin_port = ((const struct sockaddr_in *)prim)->sin_port; 36608c2654abSrjs sin->sin_addr = ((const struct sockaddr_in *)prim)->sin_addr; 36618c2654abSrjs } else { 36628c2654abSrjs struct sockaddr_in6 *sin6; 36638c2654abSrjs 36648c2654abSrjs sin6 = (struct sockaddr_in6 *)nam; 36658c2654abSrjs memset((void *)sin6, 0, sizeof (*sin6)); 36668c2654abSrjs sin6->sin6_family = AF_INET6; 36678c2654abSrjs sin6->sin6_len = sizeof(*sin6); 36688c2654abSrjs sin6->sin6_port = ((const struct sockaddr_in6 *)prim)->sin6_port; 36698c2654abSrjs 36708c2654abSrjs sin6->sin6_addr = ((const struct sockaddr_in6 *)prim)->sin6_addr; 36718c2654abSrjs if ((error = sa6_recoverscope(sin6)) != 0) 36728c2654abSrjs return error; 36738c2654abSrjs 36748c2654abSrjs } 36758c2654abSrjs /* Wake any delayed sleep action */ 36768c2654abSrjs SCTP_TCB_UNLOCK(stcb); 36778c2654abSrjs SCTP_INP_WLOCK(inp); 36788c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 36798c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 36808c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 36818c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 36828c2654abSrjs if (sowritable(inp->sctp_socket)) 36838c2654abSrjs sowwakeup(inp->sctp_socket); 36848c2654abSrjs } 36858c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 36868c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 36878c2654abSrjs if (soreadable(inp->sctp_socket)) 36888c2654abSrjs sorwakeup(inp->sctp_socket); 36898c2654abSrjs } 36908c2654abSrjs 36918c2654abSrjs } 36928c2654abSrjs SCTP_INP_WUNLOCK(inp); 36938c2654abSrjs return 0; 36948c2654abSrjs } 36958c2654abSrjs 36968c2654abSrjs static int 36978c2654abSrjs sctp_stat(struct socket *so, struct stat *ub) 36988c2654abSrjs { 36998c2654abSrjs return 0; 37008c2654abSrjs } 37018c2654abSrjs 37028c2654abSrjs int 37038c2654abSrjs sctp_sockaddr(struct socket *so, struct sockaddr *nam) 37048c2654abSrjs { 37058c2654abSrjs struct sockaddr_in *sin = (struct sockaddr_in *)nam; 37068c2654abSrjs struct sctp_inpcb *inp; 37078c2654abSrjs 37088c2654abSrjs memset(sin, 0, sizeof(*sin)); 37098c2654abSrjs sin->sin_family = AF_INET; 37108c2654abSrjs sin->sin_len = sizeof(*sin); 37118c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 37128c2654abSrjs if (!inp) { 37138c2654abSrjs return ECONNRESET; 37148c2654abSrjs } 37158c2654abSrjs SCTP_INP_RLOCK(inp); 37168c2654abSrjs sin->sin_port = inp->sctp_lport; 37178c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 37188c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 37198c2654abSrjs struct sctp_tcb *stcb; 37208c2654abSrjs const struct sockaddr_in *sin_a; 37218c2654abSrjs struct sctp_nets *net; 37228c2654abSrjs int fnd; 37238c2654abSrjs 37248c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 37258c2654abSrjs if (stcb == NULL) { 37268c2654abSrjs goto notConn; 37278c2654abSrjs } 37288c2654abSrjs fnd = 0; 37298c2654abSrjs sin_a = NULL; 37308c2654abSrjs SCTP_TCB_LOCK(stcb); 37318c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 37328c2654abSrjs sin_a = (const struct sockaddr_in *)rtcache_getdst(&net->ro); 37338c2654abSrjs if (sin_a->sin_family == AF_INET) { 37348c2654abSrjs fnd = 1; 37358c2654abSrjs break; 37368c2654abSrjs } 37378c2654abSrjs } 37388c2654abSrjs if ((!fnd) || (sin_a == NULL)) { 37398c2654abSrjs /* punt */ 37408c2654abSrjs SCTP_TCB_UNLOCK(stcb); 37418c2654abSrjs goto notConn; 37428c2654abSrjs } 37438c2654abSrjs sin->sin_addr = sctp_ipv4_source_address_selection(inp, 37448c2654abSrjs stcb, (struct route *)&net->ro, net, 0); 37458c2654abSrjs SCTP_TCB_UNLOCK(stcb); 37468c2654abSrjs } else { 37478c2654abSrjs /* For the bound all case you get back 0 */ 37488c2654abSrjs notConn: 37498c2654abSrjs sin->sin_addr.s_addr = 0; 37508c2654abSrjs } 37518c2654abSrjs 37528c2654abSrjs } else { 37538c2654abSrjs /* Take the first IPv4 address in the list */ 37548c2654abSrjs struct sctp_laddr *laddr; 37558c2654abSrjs int fnd = 0; 37568c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 37578c2654abSrjs if (laddr->ifa->ifa_addr->sa_family == AF_INET) { 37588c2654abSrjs struct sockaddr_in *sin_a; 37598c2654abSrjs sin_a = (struct sockaddr_in *)laddr->ifa->ifa_addr; 37608c2654abSrjs sin->sin_addr = sin_a->sin_addr; 37618c2654abSrjs fnd = 1; 37628c2654abSrjs break; 37638c2654abSrjs } 37648c2654abSrjs } 37658c2654abSrjs if (!fnd) { 37668c2654abSrjs SCTP_INP_RUNLOCK(inp); 37678c2654abSrjs return ENOENT; 37688c2654abSrjs } 37698c2654abSrjs } 37708c2654abSrjs SCTP_INP_RUNLOCK(inp); 37718c2654abSrjs return (0); 37728c2654abSrjs } 37738c2654abSrjs 37748c2654abSrjs int 37758c2654abSrjs sctp_peeraddr(struct socket *so, struct sockaddr *nam) 37768c2654abSrjs { 37778c2654abSrjs struct sockaddr_in *sin = (struct sockaddr_in *)nam; 37788c2654abSrjs int fnd; 37798c2654abSrjs const struct sockaddr_in *sin_a; 37808c2654abSrjs struct sctp_inpcb *inp; 37818c2654abSrjs struct sctp_tcb *stcb; 37828c2654abSrjs struct sctp_nets *net; 37838c2654abSrjs 37848c2654abSrjs /* Do the malloc first in case it blocks. */ 37858c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 37868c2654abSrjs if ((inp == NULL) || 37878c2654abSrjs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 37888c2654abSrjs /* UDP type and listeners will drop out here */ 37898c2654abSrjs return (ENOTCONN); 37908c2654abSrjs } 37918c2654abSrjs 37928c2654abSrjs memset(sin, 0, sizeof(*sin)); 37938c2654abSrjs sin->sin_family = AF_INET; 37948c2654abSrjs sin->sin_len = sizeof(*sin); 37958c2654abSrjs 37968c2654abSrjs /* We must recapture incase we blocked */ 37978c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb; 37988c2654abSrjs if (!inp) { 37998c2654abSrjs return ECONNRESET; 38008c2654abSrjs } 38018c2654abSrjs SCTP_INP_RLOCK(inp); 38028c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list); 38038c2654abSrjs if (stcb) { 38048c2654abSrjs SCTP_TCB_LOCK(stcb); 38058c2654abSrjs } 38068c2654abSrjs SCTP_INP_RUNLOCK(inp); 38078c2654abSrjs if (stcb == NULL) { 38088c2654abSrjs return ECONNRESET; 38098c2654abSrjs } 38108c2654abSrjs fnd = 0; 38118c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 38128c2654abSrjs sin_a = (const struct sockaddr_in *)rtcache_getdst(&net->ro); 38138c2654abSrjs if (sin_a->sin_family == AF_INET) { 38148c2654abSrjs fnd = 1; 38158c2654abSrjs sin->sin_port = stcb->rport; 38168c2654abSrjs sin->sin_addr = sin_a->sin_addr; 38178c2654abSrjs break; 38188c2654abSrjs } 38198c2654abSrjs } 38208c2654abSrjs SCTP_TCB_UNLOCK(stcb); 38218c2654abSrjs if (!fnd) { 38228c2654abSrjs /* No IPv4 address */ 38238c2654abSrjs return ENOENT; 38248c2654abSrjs } 38258c2654abSrjs return (0); 38268c2654abSrjs } 38278c2654abSrjs 38288c2654abSrjs static int 38298c2654abSrjs sctp_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 38308c2654abSrjs { 38318c2654abSrjs KASSERT(solocked(so)); 38328c2654abSrjs 38338c2654abSrjs m_freem(m); 38348c2654abSrjs m_freem(control); 38358c2654abSrjs 38368c2654abSrjs return EOPNOTSUPP; 38378c2654abSrjs } 38388c2654abSrjs 38398c2654abSrjs static int 38408c2654abSrjs sctp_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 38418c2654abSrjs { 38428c2654abSrjs int error = 0; 38438c2654abSrjs int family; 38448c2654abSrjs 38453917a6f0Srjs if (cmd == SIOCCONNECTX) { 38463917a6f0Srjs solock(so); 38473917a6f0Srjs error = sctp_do_connect_x(so, nam, curlwp, 0); 38483917a6f0Srjs sounlock(so); 38493917a6f0Srjs } else if (cmd == SIOCCONNECTXDEL) { 38503917a6f0Srjs solock(so); 38513917a6f0Srjs error = sctp_do_connect_x(so, nam, curlwp, 1); 38523917a6f0Srjs sounlock(so); 38533917a6f0Srjs } else { 38548c2654abSrjs family = so->so_proto->pr_domain->dom_family; 38558c2654abSrjs switch (family) { 38568c2654abSrjs #ifdef INET 38578c2654abSrjs case PF_INET: 38588c2654abSrjs error = in_control(so, cmd, nam, ifp); 38598c2654abSrjs break; 38608c2654abSrjs #endif 38618c2654abSrjs #ifdef INET6 38628c2654abSrjs case PF_INET6: 38638c2654abSrjs error = in6_control(so, cmd, nam, ifp); 38648c2654abSrjs break; 38658c2654abSrjs #endif 38668c2654abSrjs default: 38678c2654abSrjs error = EAFNOSUPPORT; 38688c2654abSrjs } 38693917a6f0Srjs } 38708c2654abSrjs return (error); 38718c2654abSrjs } 38728c2654abSrjs 38738c2654abSrjs static int 38748c2654abSrjs sctp_purgeif(struct socket *so, struct ifnet *ifp) 38758c2654abSrjs { 38768c2654abSrjs struct ifaddr *ifa; 38779e4c2bdaSozaki-r IFADDR_READER_FOREACH(ifa, ifp) { 38788c2654abSrjs if (ifa->ifa_addr->sa_family == PF_INET) { 38798c2654abSrjs sctp_delete_ip_address(ifa); 38808c2654abSrjs } 38818c2654abSrjs } 38828c2654abSrjs 38838c2654abSrjs mutex_enter(softnet_lock); 38848c2654abSrjs in_purgeif(ifp); 38858c2654abSrjs mutex_exit(softnet_lock); 38868c2654abSrjs 38878c2654abSrjs return 0; 38888c2654abSrjs } 38898c2654abSrjs 38908c2654abSrjs /* 38918c2654abSrjs * Sysctl for sctp variables. 38928c2654abSrjs */ 3893ad7c6453Srjs static void 3894ad7c6453Srjs sysctl_net_inet_sctp_setup(struct sysctllog **clog) 38958c2654abSrjs { 38968c2654abSrjs 38978c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 38988c2654abSrjs CTLFLAG_PERMANENT, 38998c2654abSrjs CTLTYPE_NODE, "net", NULL, 39008c2654abSrjs NULL, 0, NULL, 0, 39018c2654abSrjs CTL_NET, CTL_EOL); 39028c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39038c2654abSrjs CTLFLAG_PERMANENT, 39048c2654abSrjs CTLTYPE_NODE, "inet", NULL, 39058c2654abSrjs NULL, 0, NULL, 0, 39068c2654abSrjs CTL_NET, PF_INET, CTL_EOL); 39078c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39088c2654abSrjs CTLFLAG_PERMANENT, 39098c2654abSrjs CTLTYPE_NODE, "sctp", 39108c2654abSrjs SYSCTL_DESCR("sctp related settings"), 39118c2654abSrjs NULL, 0, NULL, 0, 39128c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, CTL_EOL); 39138c2654abSrjs 39148c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39158c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39168c2654abSrjs CTLTYPE_INT, "maxdgram", 39178c2654abSrjs SYSCTL_DESCR("Maximum outgoing SCTP buffer size"), 39188c2654abSrjs NULL, 0, &sctp_sendspace, 0, 39198c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_MAXDGRAM, 39208c2654abSrjs CTL_EOL); 39218c2654abSrjs 39228c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39238c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39248c2654abSrjs CTLTYPE_INT, "recvspace", 39258c2654abSrjs SYSCTL_DESCR("Maximum incoming SCTP buffer size"), 39268c2654abSrjs NULL, 0, &sctp_recvspace, 0, 39278c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_RECVSPACE, 39288c2654abSrjs CTL_EOL); 39298c2654abSrjs 39308c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39318c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 3932ad7c6453Srjs CTLTYPE_INT, "auto_asconf", 39338c2654abSrjs SYSCTL_DESCR("Enable SCTP Auto-ASCONF"), 39348c2654abSrjs NULL, 0, &sctp_auto_asconf, 0, 39358c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_AUTOASCONF, 39368c2654abSrjs CTL_EOL); 39378c2654abSrjs 39388c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39398c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39408c2654abSrjs CTLTYPE_INT, "ecn_enable", 39418c2654abSrjs SYSCTL_DESCR("Enable SCTP ECN"), 39428c2654abSrjs NULL, 0, &sctp_ecn, 0, 39438c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_ECN_ENABLE, 39448c2654abSrjs CTL_EOL); 39458c2654abSrjs 39468c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39478c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39488c2654abSrjs CTLTYPE_INT, "ecn_nonce", 39498c2654abSrjs SYSCTL_DESCR("Enable SCTP ECN Nonce"), 39508c2654abSrjs NULL, 0, &sctp_ecn_nonce, 0, 39518c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_ECN_NONCE, 39528c2654abSrjs CTL_EOL); 39538c2654abSrjs 39548c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39558c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39568c2654abSrjs CTLTYPE_INT, "strict_sack", 39578c2654abSrjs SYSCTL_DESCR("Enable SCTP Strict SACK checking"), 39588c2654abSrjs NULL, 0, &sctp_strict_sacks, 0, 39598c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_STRICT_SACK, 39608c2654abSrjs CTL_EOL); 39618c2654abSrjs 39628c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39638c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39648c2654abSrjs CTLTYPE_INT, "loopback_nocsum", 39658c2654abSrjs SYSCTL_DESCR("Enable NO Csum on packets sent on loopback"), 39668c2654abSrjs NULL, 0, &sctp_no_csum_on_loopback, 0, 39678c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_NOCSUM_LO, 39688c2654abSrjs CTL_EOL); 39698c2654abSrjs 39708c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39718c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39728c2654abSrjs CTLTYPE_INT, "strict_init", 39738c2654abSrjs SYSCTL_DESCR("Enable strict INIT/INIT-ACK singleton enforcement"), 39748c2654abSrjs NULL, 0, &sctp_strict_init, 0, 39758c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_STRICT_INIT, 39768c2654abSrjs CTL_EOL); 39778c2654abSrjs 39788c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39798c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39808c2654abSrjs CTLTYPE_INT, "peer_chkoh", 39818c2654abSrjs SYSCTL_DESCR("Amount to debit peers rwnd per chunk sent"), 39828c2654abSrjs NULL, 0, &sctp_peer_chunk_oh, 0, 39838c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_PEER_CHK_OH, 39848c2654abSrjs CTL_EOL); 39858c2654abSrjs 39868c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39878c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39888c2654abSrjs CTLTYPE_INT, "maxburst", 39898c2654abSrjs SYSCTL_DESCR("Default max burst for sctp endpoints"), 39908c2654abSrjs NULL, 0, &sctp_max_burst_default, 0, 39918c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_MAXBURST, 39928c2654abSrjs CTL_EOL); 39938c2654abSrjs 39948c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 39958c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 39968c2654abSrjs CTLTYPE_INT, "maxchunks", 39978c2654abSrjs SYSCTL_DESCR("Default max chunks on queue per asoc"), 39988c2654abSrjs NULL, 0, &sctp_max_chunks_on_queue, 0, 39998c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_MAXCHUNKONQ, 40008c2654abSrjs CTL_EOL); 40018c2654abSrjs #ifdef SCTP_DEBUG 40028c2654abSrjs sysctl_createv(clog, 0, NULL, NULL, 40038c2654abSrjs CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 40048c2654abSrjs CTLTYPE_INT, "debug", 40058c2654abSrjs SYSCTL_DESCR("Configure debug output"), 40068c2654abSrjs NULL, 0, &sctp_debug_on, 0, 40078c2654abSrjs CTL_NET, PF_INET, IPPROTO_SCTP, SCTPCTL_DEBUG, 40088c2654abSrjs CTL_EOL); 40098c2654abSrjs #endif 40108c2654abSrjs } 40118c2654abSrjs 40128c2654abSrjs PR_WRAP_USRREQS(sctp) 40138c2654abSrjs #define sctp_attach sctp_attach_wrapper 40148c2654abSrjs #define sctp_detach sctp_detach_wrapper 40158c2654abSrjs #define sctp_accept sctp_accept_wrapper 40168c2654abSrjs #define sctp_bind sctp_bind_wrapper 40178c2654abSrjs #define sctp_listen sctp_listen_wrapper 40188c2654abSrjs #define sctp_connect sctp_connect_wrapper 40198c2654abSrjs #define sctp_connect2 sctp_connect2_wrapper 40208c2654abSrjs #define sctp_disconnect sctp_disconnect_wrapper 40218c2654abSrjs #define sctp_shutdown sctp_shutdown_wrapper 40228c2654abSrjs #define sctp_abort sctp_abort_wrapper 40238c2654abSrjs #define sctp_ioctl sctp_ioctl_wrapper 40248c2654abSrjs #define sctp_stat sctp_stat_wrapper 40258c2654abSrjs #define sctp_peeraddr sctp_peeraddr_wrapper 40268c2654abSrjs #define sctp_sockaddr sctp_sockaddr_wrapper 40278c2654abSrjs #define sctp_rcvd sctp_rcvd_wrapper 40288c2654abSrjs #define sctp_recvoob sctp_recvoob_wrapper 40298c2654abSrjs #define sctp_send sctp_send_wrapper 40308c2654abSrjs #define sctp_sendoob sctp_sendoob_wrapper 40318c2654abSrjs #define sctp_purgeif sctp_purgeif_wrapper 40328c2654abSrjs 40338c2654abSrjs const struct pr_usrreqs sctp_usrreqs = { 40348c2654abSrjs .pr_attach = sctp_attach, 40358c2654abSrjs .pr_detach = sctp_detach, 40368c2654abSrjs .pr_accept = sctp_accept, 40378c2654abSrjs .pr_bind = sctp_bind, 40388c2654abSrjs .pr_listen = sctp_listen, 40398c2654abSrjs .pr_connect = sctp_connect, 40408c2654abSrjs .pr_connect2 = sctp_connect2, 40418c2654abSrjs .pr_disconnect = sctp_disconnect, 40428c2654abSrjs .pr_shutdown = sctp_shutdown, 40438c2654abSrjs .pr_abort = sctp_abort, 40448c2654abSrjs .pr_ioctl = sctp_ioctl, 40458c2654abSrjs .pr_stat = sctp_stat, 40468c2654abSrjs .pr_peeraddr = sctp_peeraddr, 40478c2654abSrjs .pr_sockaddr = sctp_sockaddr, 40488c2654abSrjs .pr_rcvd = sctp_rcvd, 40498c2654abSrjs .pr_recvoob = sctp_recvoob, 40508c2654abSrjs .pr_send = sctp_send, 40518c2654abSrjs .pr_sendoob = sctp_sendoob, 40528c2654abSrjs .pr_purgeif = sctp_purgeif, 40538c2654abSrjs }; 4054