18c2654abSrjs /* $KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $ */
2*50d76f75Sandvar /* $NetBSD: sctp6_usrreq.c,v 1.26 2024/07/06 10:09:15 andvar 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*50d76f75Sandvar __KERNEL_RCSID(0, "$NetBSD: sctp6_usrreq.c,v 1.26 2024/07/06 10:09:15 andvar Exp $");
378c2654abSrjs
388c2654abSrjs #ifdef _KERNEL_OPT
398c2654abSrjs #include "opt_inet.h"
408c2654abSrjs #include "opt_ipsec.h"
418c2654abSrjs #include "opt_sctp.h"
422526d8f6Sknakahara #include "opt_net_mpsafe.h"
438c2654abSrjs #endif /* _KERNEL_OPT */
448c2654abSrjs
458c2654abSrjs #include <sys/param.h>
468c2654abSrjs #include <sys/kernel.h>
478c2654abSrjs #include <sys/mbuf.h>
488c2654abSrjs #include <sys/domain.h>
498c2654abSrjs #include <sys/protosw.h>
508c2654abSrjs #include <sys/socket.h>
518c2654abSrjs #include <sys/malloc.h>
528c2654abSrjs #include <sys/socketvar.h>
538c2654abSrjs #include <sys/sysctl.h>
548c2654abSrjs #include <sys/errno.h>
558c2654abSrjs #include <sys/stat.h>
568c2654abSrjs #include <sys/systm.h>
578c2654abSrjs #include <sys/syslog.h>
588c2654abSrjs #include <sys/proc.h>
598c2654abSrjs #include <net/if.h>
608c2654abSrjs #include <net/route.h>
618c2654abSrjs #include <net/if_types.h>
628c2654abSrjs #include <netinet/in.h>
638c2654abSrjs #include <netinet/in_systm.h>
648c2654abSrjs #include <netinet/ip.h>
658c2654abSrjs #include <netinet/in_pcb.h>
668c2654abSrjs #include <netinet/in_var.h>
678c2654abSrjs #include <netinet/ip_var.h>
688c2654abSrjs #include <netinet/sctp_pcb.h>
698c2654abSrjs #include <netinet/sctp_header.h>
708c2654abSrjs #include <netinet/sctp_var.h>
718c2654abSrjs #include <netinet/sctputil.h>
728c2654abSrjs #include <netinet/sctp_output.h>
738c2654abSrjs #include <netinet/sctp_input.h>
748c2654abSrjs #include <netinet/sctp_asconf.h>
758e337251Srjs #include <netinet/sctp_route.h>
768c2654abSrjs #include <netinet6/ip6_var.h>
778c2654abSrjs #include <netinet6/scope6_var.h>
788c2654abSrjs #include <netinet/ip6.h>
798c2654abSrjs #include <netinet6/in6_pcb.h>
808c2654abSrjs #include <netinet/icmp6.h>
818c2654abSrjs #include <netinet6/sctp6_var.h>
828c2654abSrjs #include <netinet6/ip6protosw.h>
838c2654abSrjs
848c2654abSrjs #ifdef IPSEC
85505ea976Srjs #include <netipsec/ipsec.h>
86505ea976Srjs #include <netipsec/ipsec6.h>
878c2654abSrjs #endif /*IPSEC*/
888c2654abSrjs
898c2654abSrjs #if defined(NFAITH) && NFAITH > 0
908c2654abSrjs #include <net/if_faith.h>
918c2654abSrjs #endif
928c2654abSrjs
938c2654abSrjs #if defined(HAVE_NRL_INPCB) || defined(__FreeBSD__)
948c2654abSrjs #ifndef in6pcb
958c2654abSrjs #define in6pcb inpcb
968c2654abSrjs #endif
978c2654abSrjs #ifndef sotoin6pcb
988c2654abSrjs #define sotoin6pcb sotoinpcb
998c2654abSrjs #endif
1008c2654abSrjs #endif
1018c2654abSrjs
1028c2654abSrjs #ifdef SCTP_DEBUG
1038c2654abSrjs extern u_int32_t sctp_debug_on;
1048c2654abSrjs #endif
1058c2654abSrjs
1068c2654abSrjs static int sctp6_detach(struct socket *so);
1078c2654abSrjs
1088c2654abSrjs extern int sctp_no_csum_on_loopback;
1098c2654abSrjs
1108c2654abSrjs int
sctp6_input(struct mbuf ** mp,int * offp,int proto)1118c2654abSrjs sctp6_input(struct mbuf **mp, int *offp, int proto)
1128c2654abSrjs {
1138c2654abSrjs struct mbuf *m = *mp;
1148c2654abSrjs struct ip6_hdr *ip6;
1158c2654abSrjs struct sctphdr *sh;
1168c2654abSrjs struct sctp_inpcb *in6p = NULL;
1178c2654abSrjs struct sctp_nets *net;
1188c2654abSrjs int refcount_up = 0;
1198c2654abSrjs u_int32_t check, calc_check;
1208c2654abSrjs struct inpcb *in6p_ip;
1218c2654abSrjs struct sctp_chunkhdr *ch;
1228c2654abSrjs struct mbuf *opts = NULL;
1238c2654abSrjs int length, mlen, offset, iphlen;
1248c2654abSrjs u_int8_t ecn_bits;
1258c2654abSrjs struct sctp_tcb *stcb = NULL;
1268c2654abSrjs int off = *offp;
1278c2654abSrjs int s;
1288c2654abSrjs
1298c2654abSrjs ip6 = mtod(m, struct ip6_hdr *);
1308c2654abSrjs /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
1318c2654abSrjs IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch));
1328c2654abSrjs if (sh == NULL) {
1338c2654abSrjs sctp_pegs[SCTP_HDR_DROPS]++;
1348c2654abSrjs return IPPROTO_DONE;
1358c2654abSrjs }
1368c2654abSrjs ch = (struct sctp_chunkhdr *)((vaddr_t)sh + sizeof(struct sctphdr));
1378c2654abSrjs
1388c2654abSrjs iphlen = off;
1398c2654abSrjs offset = iphlen + sizeof(*sh) + sizeof(*ch);
1408c2654abSrjs
1418c2654abSrjs #if defined(NFAITH) && NFAITH > 0
1428c2654abSrjs if (faithprefix(&ip6->ip6_dst))
1438c2654abSrjs goto bad;
1448c2654abSrjs #endif /* NFAITH defined and > 0 */
1458c2654abSrjs sctp_pegs[SCTP_INPKTS]++;
1468c2654abSrjs #ifdef SCTP_DEBUG
1478c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
1488c2654abSrjs printf("V6 input gets a packet iphlen:%d pktlen:%d\n", iphlen, m->m_pkthdr.len);
1498c2654abSrjs }
1508c2654abSrjs #endif
1518c2654abSrjs if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
1528c2654abSrjs /* No multi-cast support in SCTP */
1538c2654abSrjs sctp_pegs[SCTP_IN_MCAST]++;
1548c2654abSrjs goto bad;
1558c2654abSrjs }
1568c2654abSrjs /* destination port of 0 is illegal, based on RFC2960. */
1578c2654abSrjs if (sh->dest_port == 0)
1588c2654abSrjs goto bad;
1598c2654abSrjs if ((sctp_no_csum_on_loopback == 0) ||
160fe6d4275Sozaki-r (m_get_rcvif_NOMPSAFE(m) == NULL) ||
161fe6d4275Sozaki-r (m_get_rcvif_NOMPSAFE(m)->if_type != IFT_LOOP)) {
1628c2654abSrjs /* we do NOT validate things from the loopback if the
1638c2654abSrjs * sysctl is set to 1.
1648c2654abSrjs */
1658c2654abSrjs check = sh->checksum; /* save incoming checksum */
1668c2654abSrjs if ((check == 0) && (sctp_no_csum_on_loopback)) {
1678c2654abSrjs /* special hook for where we got a local address
1688c2654abSrjs * somehow routed across a non IFT_LOOP type interface
1698c2654abSrjs */
1708c2654abSrjs if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))
1718c2654abSrjs goto sctp_skip_csum;
1728c2654abSrjs }
1738c2654abSrjs sh->checksum = 0; /* prepare for calc */
1748c2654abSrjs calc_check = sctp_calculate_sum(m, &mlen, iphlen);
1758c2654abSrjs if (calc_check != check) {
1768c2654abSrjs #ifdef SCTP_DEBUG
1778c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
1788c2654abSrjs printf("Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n",
1798c2654abSrjs calc_check, check, m,
1808c2654abSrjs mlen, iphlen);
1818c2654abSrjs }
1828c2654abSrjs #endif
1838c2654abSrjs stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
1848c2654abSrjs sh, ch, &in6p, &net);
1858c2654abSrjs /* in6p's ref-count increased && stcb locked */
1868c2654abSrjs if ((in6p) && (stcb)) {
1878c2654abSrjs sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
1888c2654abSrjs sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, 2);
1898c2654abSrjs } else if ((in6p != NULL) && (stcb == NULL)) {
1908c2654abSrjs refcount_up = 1;
1918c2654abSrjs }
1928c2654abSrjs sctp_pegs[SCTP_BAD_CSUM]++;
1938c2654abSrjs goto bad;
1948c2654abSrjs }
1958c2654abSrjs sh->checksum = calc_check;
1968c2654abSrjs } else {
1978c2654abSrjs sctp_skip_csum:
1988c2654abSrjs mlen = m->m_pkthdr.len;
1998c2654abSrjs }
2008c2654abSrjs net = NULL;
2018c2654abSrjs /*
2028c2654abSrjs * Locate pcb and tcb for datagram
2038c2654abSrjs * sctp_findassociation_addr() wants IP/SCTP/first chunk header...
2048c2654abSrjs */
2058c2654abSrjs #ifdef SCTP_DEBUG
2068c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
2078c2654abSrjs printf("V6 Find the association\n");
2088c2654abSrjs }
2098c2654abSrjs #endif
2108c2654abSrjs stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
2118c2654abSrjs sh, ch, &in6p, &net);
2128c2654abSrjs /* in6p's ref-count increased */
2138c2654abSrjs if (in6p == NULL) {
2148c2654abSrjs struct sctp_init_chunk *init_chk, chunk_buf;
2158c2654abSrjs
2168c2654abSrjs sctp_pegs[SCTP_NOPORTS]++;
2178c2654abSrjs if (ch->chunk_type == SCTP_INITIATION) {
2188c2654abSrjs /* we do a trick here to get the INIT tag,
2198c2654abSrjs * dig in and get the tag from the INIT and
2208c2654abSrjs * put it in the common header.
2218c2654abSrjs */
2228c2654abSrjs init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
2238c2654abSrjs iphlen + sizeof(*sh), sizeof(*init_chk),
2248c2654abSrjs (u_int8_t *)&chunk_buf);
2258c2654abSrjs sh->v_tag = init_chk->init.initiate_tag;
2268c2654abSrjs }
2278c2654abSrjs sctp_send_abort(m, iphlen, sh, 0, NULL);
2288c2654abSrjs goto bad;
2298c2654abSrjs } else if (stcb == NULL) {
2308c2654abSrjs refcount_up = 1;
2318c2654abSrjs }
2328c2654abSrjs in6p_ip = (struct inpcb *)in6p;
2338c2654abSrjs #ifdef IPSEC
2348c2654abSrjs /*
2358c2654abSrjs * Check AH/ESP integrity.
2368c2654abSrjs */
2377118c214Sozaki-r if (ipsec_used && ipsec_in_reject(m, in6p_ip)) {
2388c2654abSrjs /* XXX */
239505ea976Srjs #if 0
240505ea976Srjs /* FIX ME: need to find right stat */
2418c2654abSrjs ipsec6stat.in_polvio++;
2428c2654abSrjs #endif
2438c2654abSrjs goto bad;
2448c2654abSrjs }
2458c2654abSrjs #endif /*IPSEC*/
2468c2654abSrjs
2478c2654abSrjs /*
2488c2654abSrjs * Construct sockaddr format source address.
2498c2654abSrjs * Stuff source address and datagram in user buffer.
2508c2654abSrjs */
2518c2654abSrjs if ((in6p->ip_inp.inp.inp_flags & INP_CONTROLOPTS)
2528c2654abSrjs #ifndef __OpenBSD__
2538c2654abSrjs || (in6p->sctp_socket->so_options & SO_TIMESTAMP)
2548c2654abSrjs #endif
2558c2654abSrjs ) {
2568c2654abSrjs #if defined(__FreeBSD__) || defined(__APPLE__)
2578c2654abSrjs #if (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version < 501113) || defined(__APPLE__)
2588c2654abSrjs ip6_savecontrol(in6p_ip, &opts, ip6, m);
2598c2654abSrjs #elif __FreeBSD_version >= 440000 || (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version >= 501113)
2608c2654abSrjs ip6_savecontrol(in6p_ip, m, &opts);
2618c2654abSrjs #else
2628c2654abSrjs ip6_savecontrol(in6p_ip, m, &opts, NULL);
2638c2654abSrjs #endif
2648c2654abSrjs #elif defined(__NetBSD__)
2657118c214Sozaki-r ip6_savecontrol(in6p_ip, &opts, ip6, m);
2668c2654abSrjs #else
2677118c214Sozaki-r ip6_savecontrol(in6p_ip, m, &opts);
2688c2654abSrjs #endif
2698c2654abSrjs }
2708c2654abSrjs
2718c2654abSrjs /*
2728c2654abSrjs * CONTROL chunk processing
2738c2654abSrjs */
2748c2654abSrjs length = ntohs(ip6->ip6_plen) + iphlen;
2758c2654abSrjs offset -= sizeof(*ch);
2768c2654abSrjs ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
2778c2654abSrjs s = splsoftnet();
2788c2654abSrjs (void)sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
2798c2654abSrjs in6p, stcb, net, ecn_bits);
2808c2654abSrjs /* inp's ref-count reduced && stcb unlocked */
2818c2654abSrjs splx(s);
2828c2654abSrjs /* XXX this stuff below gets moved to appropriate parts later... */
2838c2654abSrjs m_freem(m);
2848c2654abSrjs m_freem(opts);
2858c2654abSrjs
2868c2654abSrjs if ((in6p) && refcount_up){
2878c2654abSrjs /* reduce ref-count */
2888c2654abSrjs SCTP_INP_WLOCK(in6p);
2898c2654abSrjs SCTP_INP_DECR_REF(in6p);
2908c2654abSrjs SCTP_INP_WUNLOCK(in6p);
2918c2654abSrjs }
2928c2654abSrjs
2938c2654abSrjs return IPPROTO_DONE;
2948c2654abSrjs
2958c2654abSrjs bad:
2968c2654abSrjs if (stcb) {
2978c2654abSrjs SCTP_TCB_UNLOCK(stcb);
2988c2654abSrjs }
2998c2654abSrjs
3008c2654abSrjs if ((in6p) && refcount_up){
3018c2654abSrjs /* reduce ref-count */
3028c2654abSrjs SCTP_INP_WLOCK(in6p);
3038c2654abSrjs SCTP_INP_DECR_REF(in6p);
3048c2654abSrjs SCTP_INP_WUNLOCK(in6p);
3058c2654abSrjs }
3068c2654abSrjs m_freem(m);
3078c2654abSrjs m_freem(opts);
3088c2654abSrjs return IPPROTO_DONE;
3098c2654abSrjs }
3108c2654abSrjs
3118c2654abSrjs
3128c2654abSrjs static void
sctp6_notify_mbuf(struct sctp_inpcb * inp,struct icmp6_hdr * icmp6,struct sctphdr * sh,struct sctp_tcb * stcb,struct sctp_nets * net)3138c2654abSrjs sctp6_notify_mbuf(struct sctp_inpcb *inp,
3148c2654abSrjs struct icmp6_hdr *icmp6,
3158c2654abSrjs struct sctphdr *sh,
3168c2654abSrjs struct sctp_tcb *stcb,
3178c2654abSrjs struct sctp_nets *net)
3188c2654abSrjs {
3198c2654abSrjs unsigned int nxtsz;
3208c2654abSrjs
3218c2654abSrjs if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
3228c2654abSrjs (icmp6 == NULL) || (sh == NULL)) {
3238c2654abSrjs goto out;
3248c2654abSrjs }
3258c2654abSrjs
3268c2654abSrjs /* First do we even look at it? */
3278c2654abSrjs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
3288c2654abSrjs goto out;
3298c2654abSrjs
3308c2654abSrjs if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
3318c2654abSrjs /* not PACKET TO BIG */
3328c2654abSrjs goto out;
3338c2654abSrjs }
3348c2654abSrjs /*
3358c2654abSrjs * ok we need to look closely. We could even get smarter and
3368c2654abSrjs * look at anyone that we sent to in case we get a different
3378c2654abSrjs * ICMP that tells us there is no way to reach a host, but for
3388c2654abSrjs * this impl, all we care about is MTU discovery.
3398c2654abSrjs */
3408c2654abSrjs nxtsz = ntohl(icmp6->icmp6_mtu);
3418c2654abSrjs /* Stop any PMTU timer */
3428c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
3438c2654abSrjs
3448c2654abSrjs /* Adjust destination size limit */
3458c2654abSrjs if (net->mtu > nxtsz) {
3468c2654abSrjs net->mtu = nxtsz;
3478c2654abSrjs }
3488c2654abSrjs /* now what about the ep? */
3498c2654abSrjs if (stcb->asoc.smallest_mtu > nxtsz) {
3508c2654abSrjs struct sctp_tmit_chunk *chk;
3518c2654abSrjs struct sctp_stream_out *strm;
3528c2654abSrjs /* Adjust that too */
3538c2654abSrjs stcb->asoc.smallest_mtu = nxtsz;
3548c2654abSrjs /* now off to subtract IP_DF flag if needed */
3558c2654abSrjs
3568c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
3578c2654abSrjs if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
3588c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
3598c2654abSrjs }
3608c2654abSrjs }
3618c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
3628c2654abSrjs if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
3638c2654abSrjs /*
3648c2654abSrjs * For this guy we also mark for immediate
3658c2654abSrjs * resend since we sent to big of chunk
3668c2654abSrjs */
3678c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
3688c2654abSrjs if (chk->sent != SCTP_DATAGRAM_RESEND)
3698c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
3708c2654abSrjs chk->sent = SCTP_DATAGRAM_RESEND;
3718c2654abSrjs chk->rec.data.doing_fast_retransmit = 0;
3728c2654abSrjs
3738c2654abSrjs chk->sent = SCTP_DATAGRAM_RESEND;
3748c2654abSrjs /* Clear any time so NO RTT is being done */
3758c2654abSrjs chk->sent_rcv_time.tv_sec = 0;
3768c2654abSrjs chk->sent_rcv_time.tv_usec = 0;
3778c2654abSrjs stcb->asoc.total_flight -= chk->send_size;
3788c2654abSrjs net->flight_size -= chk->send_size;
3798c2654abSrjs }
3808c2654abSrjs }
3818c2654abSrjs TAILQ_FOREACH(strm, &stcb->asoc.out_wheel, next_spoke) {
3828c2654abSrjs TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) {
3838c2654abSrjs if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
3848c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
3858c2654abSrjs }
3868c2654abSrjs }
3878c2654abSrjs }
3888c2654abSrjs }
3898c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
3908c2654abSrjs out:
3918c2654abSrjs if (inp) {
3928c2654abSrjs /* reduce inp's ref-count */
3938c2654abSrjs SCTP_INP_WLOCK(inp);
3948c2654abSrjs SCTP_INP_DECR_REF(inp);
3958c2654abSrjs SCTP_INP_WUNLOCK(inp);
3968c2654abSrjs }
3978c2654abSrjs if (stcb) {
3988c2654abSrjs SCTP_TCB_UNLOCK(stcb);
3998c2654abSrjs }
4008c2654abSrjs }
4018c2654abSrjs
4028c2654abSrjs
4038c2654abSrjs void *
sctp6_ctlinput(int cmd,const struct sockaddr * pktdst,void * d)4048c2654abSrjs sctp6_ctlinput(int cmd, const struct sockaddr *pktdst, void *d)
4058c2654abSrjs {
4068c2654abSrjs struct sctphdr sh;
4078c2654abSrjs struct ip6ctlparam *ip6cp = NULL;
4088c2654abSrjs int s, cm;
4098c2654abSrjs
4108c2654abSrjs if (pktdst->sa_family != AF_INET6 ||
4118c2654abSrjs pktdst->sa_len != sizeof(struct sockaddr_in6))
4128c2654abSrjs return NULL;
4138c2654abSrjs
4148c2654abSrjs if ((unsigned)cmd >= PRC_NCMDS)
4158c2654abSrjs return NULL;
4168c2654abSrjs if (PRC_IS_REDIRECT(cmd)) {
4178c2654abSrjs d = NULL;
4188c2654abSrjs } else if (inet6ctlerrmap[cmd] == 0) {
4198c2654abSrjs return NULL;
4208c2654abSrjs }
4218c2654abSrjs
4228c2654abSrjs /* if the parameter is from icmp6, decode it. */
4238c2654abSrjs if (d != NULL) {
4248c2654abSrjs ip6cp = (struct ip6ctlparam *)d;
4258c2654abSrjs } else {
4268c2654abSrjs ip6cp = (struct ip6ctlparam *)NULL;
4278c2654abSrjs }
4288c2654abSrjs
4298c2654abSrjs if (ip6cp) {
4308c2654abSrjs /*
4318c2654abSrjs * XXX: We assume that when IPV6 is non NULL,
4328c2654abSrjs * M and OFF are valid.
4338c2654abSrjs */
4348c2654abSrjs /* check if we can safely examine src and dst ports */
4358c2654abSrjs struct sctp_inpcb *inp;
4368c2654abSrjs struct sctp_tcb *stcb;
4378c2654abSrjs struct sctp_nets *net;
4388c2654abSrjs struct sockaddr_in6 final;
4398c2654abSrjs
4408c2654abSrjs if (ip6cp->ip6c_m == NULL ||
4418c2654abSrjs (size_t)ip6cp->ip6c_m->m_pkthdr.len < (ip6cp->ip6c_off + sizeof(sh)))
4428c2654abSrjs return NULL;
4438c2654abSrjs
4448c2654abSrjs memset(&sh, 0, sizeof(sh));
4458c2654abSrjs memset(&final, 0, sizeof(final));
4468c2654abSrjs inp = NULL;
4478c2654abSrjs net = NULL;
4488c2654abSrjs m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
4498c2654abSrjs (void *)&sh);
4508c2654abSrjs ip6cp->ip6c_src->sin6_port = sh.src_port;
4518c2654abSrjs final.sin6_len = sizeof(final);
4528c2654abSrjs final.sin6_family = AF_INET6;
4538c2654abSrjs final.sin6_addr = ((const struct sockaddr_in6 *)pktdst)->sin6_addr;
4548c2654abSrjs final.sin6_port = sh.dest_port;
4558c2654abSrjs s = splsoftnet();
4568759207cSozaki-r stcb = sctp_findassociation_addr_sa(sin6tosa(ip6cp->ip6c_src),
4578759207cSozaki-r sin6tosa(&final),
4588c2654abSrjs &inp, &net, 1);
4598c2654abSrjs /* inp's ref-count increased && stcb locked */
4608c2654abSrjs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
4618c2654abSrjs if (cmd == PRC_MSGSIZE) {
4628c2654abSrjs sctp6_notify_mbuf(inp,
4638c2654abSrjs ip6cp->ip6c_icmp6,
4648c2654abSrjs &sh,
4658c2654abSrjs stcb,
4668c2654abSrjs net);
4678c2654abSrjs /* inp's ref-count reduced && stcb unlocked */
4688c2654abSrjs } else {
4698c2654abSrjs if (cmd == PRC_HOSTDEAD) {
4708c2654abSrjs cm = EHOSTUNREACH;
4718c2654abSrjs } else {
4728c2654abSrjs cm = inet6ctlerrmap[cmd];
4738c2654abSrjs }
4748759207cSozaki-r sctp_notify(inp, cm, &sh, sin6tosa(&final),
4758c2654abSrjs stcb, net);
4768c2654abSrjs /* inp's ref-count reduced && stcb unlocked */
4778c2654abSrjs }
4788c2654abSrjs } else {
4798c2654abSrjs if (PRC_IS_REDIRECT(cmd) && inp) {
480b000e63fSozaki-r in6pcb_rtchange((struct inpcb *)inp, inet6ctlerrmap[cmd]);
4818c2654abSrjs }
4828c2654abSrjs if (inp) {
4838c2654abSrjs /* reduce inp's ref-count */
4848c2654abSrjs SCTP_INP_WLOCK(inp);
4858c2654abSrjs SCTP_INP_DECR_REF(inp);
4868c2654abSrjs SCTP_INP_WUNLOCK(inp);
4878c2654abSrjs }
4888c2654abSrjs if (stcb) {
4898c2654abSrjs SCTP_TCB_UNLOCK(stcb);
4908c2654abSrjs }
4918c2654abSrjs }
4928c2654abSrjs splx(s);
4938c2654abSrjs }
4948c2654abSrjs return NULL;
4958c2654abSrjs }
4968c2654abSrjs
4978c2654abSrjs /*
498*50d76f75Sandvar * this routine can probably be collapsed into the one in sctp_userreq.c
4998c2654abSrjs * since they do the same thing and now we lookup with a sockaddr
5008c2654abSrjs */
5018c2654abSrjs #ifdef __FreeBSD__
5028c2654abSrjs static int
sctp6_getcred(SYSCTL_HANDLER_ARGS)5038c2654abSrjs sctp6_getcred(SYSCTL_HANDLER_ARGS)
5048c2654abSrjs {
5058c2654abSrjs struct sockaddr_in6 addrs[2];
5068c2654abSrjs struct sctp_inpcb *inp;
5078c2654abSrjs struct sctp_nets *net;
5088c2654abSrjs struct sctp_tcb *stcb;
5098c2654abSrjs int error, s;
5108c2654abSrjs
5118c2654abSrjs #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
5128c2654abSrjs error = suser(req->td);
5138c2654abSrjs #else
5148c2654abSrjs error = suser(req->p);
5158c2654abSrjs #endif
5168c2654abSrjs if (error)
5178c2654abSrjs return (error);
5188c2654abSrjs
5198c2654abSrjs if (req->newlen != sizeof(addrs))
5208c2654abSrjs return (EINVAL);
5218c2654abSrjs if (req->oldlen != sizeof(struct ucred))
5228c2654abSrjs return (EINVAL);
5238c2654abSrjs error = SYSCTL_IN(req, addrs, sizeof(addrs));
5248c2654abSrjs if (error)
5258c2654abSrjs return (error);
5268c2654abSrjs s = splsoftnet();
5278c2654abSrjs
5288c2654abSrjs stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
5298c2654abSrjs sin6tosa(&addrs[1]),
5308c2654abSrjs &inp, &net, 1);
5318c2654abSrjs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
5328c2654abSrjs error = ENOENT;
5338c2654abSrjs if (inp) {
5348c2654abSrjs SCTP_INP_WLOCK(inp);
5358c2654abSrjs SCTP_INP_DECR_REF(inp);
5368c2654abSrjs SCTP_INP_WUNLOCK(inp);
5378c2654abSrjs }
5388c2654abSrjs goto out;
5398c2654abSrjs }
5408c2654abSrjs error = SYSCTL_OUT(req, inp->sctp_socket->so_cred,
5418c2654abSrjs sizeof(struct ucred));
5428c2654abSrjs
5438c2654abSrjs SCTP_TCB_UNLOCK (stcb);
5448c2654abSrjs out:
5458c2654abSrjs splx(s);
5468c2654abSrjs return (error);
5478c2654abSrjs }
5488c2654abSrjs
5498c2654abSrjs SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
5508c2654abSrjs 0, 0,
5518c2654abSrjs sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
5528c2654abSrjs
5538c2654abSrjs #endif
5548c2654abSrjs
5558c2654abSrjs /* This is the same as the sctp_abort() could be made common */
5568c2654abSrjs static int
sctp6_abort(struct socket * so)5578c2654abSrjs sctp6_abort(struct socket *so)
5588c2654abSrjs {
5598c2654abSrjs int s;
5608c2654abSrjs struct sctp_inpcb *inp;
5618c2654abSrjs
5628c2654abSrjs KASSERT(solocked(so));
5638c2654abSrjs
5648c2654abSrjs s = splsoftnet();
5658c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
5668c2654abSrjs if (inp == 0)
5678c2654abSrjs return EINVAL; /* ??? possible? panic instead? */
5688c2654abSrjs soisdisconnected(so);
5698c2654abSrjs sctp_inpcb_free(inp, 1);
5708c2654abSrjs splx(s);
5718c2654abSrjs return 0;
5728c2654abSrjs }
5738c2654abSrjs
5748c2654abSrjs static int
sctp6_attach(struct socket * so,int proto)5758c2654abSrjs sctp6_attach(struct socket *so, int proto)
5768c2654abSrjs {
5778c2654abSrjs struct in6pcb *inp6;
5788c2654abSrjs int error;
5798c2654abSrjs struct sctp_inpcb *inp;
5808c2654abSrjs
5818c2654abSrjs sosetlock(so);
5828c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
5838c2654abSrjs if (inp != NULL)
5848c2654abSrjs return EINVAL;
5858c2654abSrjs
5868c2654abSrjs if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
5878c2654abSrjs error = soreserve(so, sctp_sendspace, sctp_recvspace);
5888c2654abSrjs if (error)
5898c2654abSrjs return error;
5908c2654abSrjs }
5918c2654abSrjs error = sctp_inpcb_alloc(so);
5928c2654abSrjs if (error)
5938c2654abSrjs return error;
5948c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
5958c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */
5968c2654abSrjs inp6 = (struct in6pcb *)inp;
5978c2654abSrjs
5988c2654abSrjs inp->inp_vflag |= INP_IPV6;
5998c2654abSrjs if (ip6_v6only) {
6008c2654abSrjs inp6->in6p_flags |= IN6P_IPV6_V6ONLY;
6018c2654abSrjs }
6028c2654abSrjs so->so_send = sctp_sosend;
6038c2654abSrjs
60401b82b52Srjs #ifdef IPSEC
60501b82b52Srjs inp6->in6p_af = proto;
60601b82b52Srjs #endif
6078c2654abSrjs inp6->in6p_hops = -1; /* use kernel default */
6088c2654abSrjs inp6->in6p_cksum = -1; /* just to be sure */
6098c2654abSrjs #ifdef INET
6108c2654abSrjs /*
6118c2654abSrjs * XXX: ugly!!
6128c2654abSrjs * IPv4 TTL initialization is necessary for an IPv6 socket as well,
6138c2654abSrjs * because the socket may be bound to an IPv6 wildcard address,
6148c2654abSrjs * which may match an IPv4-mapped IPv6 address.
6158c2654abSrjs */
6168c2654abSrjs inp->inp_ip_ttl = ip_defttl;
6178c2654abSrjs #endif
6188c2654abSrjs /*
6198c2654abSrjs * Hmm what about the IPSEC stuff that is missing here but
6208c2654abSrjs * in sctp_attach()?
6218c2654abSrjs */
6228c2654abSrjs return 0;
6238c2654abSrjs }
6248c2654abSrjs
6258c2654abSrjs static int
sctp6_bind(struct socket * so,struct sockaddr * nam,struct lwp * l)6268c2654abSrjs sctp6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
6278c2654abSrjs {
6288c2654abSrjs struct sctp_inpcb *inp;
6298c2654abSrjs struct in6pcb *inp6;
6308c2654abSrjs int error;
6318c2654abSrjs
6328c2654abSrjs KASSERT(solocked(so));
6338c2654abSrjs
6348c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
6358c2654abSrjs if (inp == 0)
6368c2654abSrjs return EINVAL;
6378c2654abSrjs
6388c2654abSrjs inp6 = (struct in6pcb *)inp;
6398c2654abSrjs inp->inp_vflag &= ~INP_IPV4;
6408c2654abSrjs inp->inp_vflag |= INP_IPV6;
6418c2654abSrjs
6428c2654abSrjs if (nam != NULL && (inp6->in6p_flags & IN6P_IPV6_V6ONLY) == 0) {
6438c2654abSrjs if (nam->sa_family == AF_INET) {
6448c2654abSrjs /* binding v4 addr to v6 socket, so reset flags */
6458c2654abSrjs inp->inp_vflag |= INP_IPV4;
6468c2654abSrjs inp->inp_vflag &= ~INP_IPV6;
6478c2654abSrjs } else {
6488c2654abSrjs struct sockaddr_in6 *sin6_p;
6498c2654abSrjs sin6_p = (struct sockaddr_in6 *)nam;
6508c2654abSrjs
6518c2654abSrjs if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
6528c2654abSrjs inp->inp_vflag |= INP_IPV4;
6538c2654abSrjs }
6548c2654abSrjs else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
6558c2654abSrjs struct sockaddr_in sin;
6568c2654abSrjs in6_sin6_2_sin(&sin, sin6_p);
6578c2654abSrjs inp->inp_vflag |= INP_IPV4;
6588c2654abSrjs inp->inp_vflag &= ~INP_IPV6;
6598c2654abSrjs error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, l);
6608c2654abSrjs return error;
6618c2654abSrjs }
6628c2654abSrjs }
6638c2654abSrjs } else if (nam != NULL) {
6648c2654abSrjs /* IPV6_V6ONLY socket */
6658c2654abSrjs if (nam->sa_family == AF_INET) {
6668c2654abSrjs /* can't bind v4 addr to v6 only socket! */
6678c2654abSrjs return EINVAL;
6688c2654abSrjs } else {
6698c2654abSrjs struct sockaddr_in6 *sin6_p;
6708c2654abSrjs sin6_p = (struct sockaddr_in6 *)nam;
6718c2654abSrjs
6728c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr))
6738c2654abSrjs /* can't bind v4-mapped addrs either! */
6748c2654abSrjs /* NOTE: we don't support SIIT */
6758c2654abSrjs return EINVAL;
6768c2654abSrjs }
6778c2654abSrjs }
6788c2654abSrjs error = sctp_inpcb_bind(so, nam, l);
6798c2654abSrjs return error;
6808c2654abSrjs }
6818c2654abSrjs
6828c2654abSrjs /*This could be made common with sctp_detach() since they are identical */
6838c2654abSrjs static int
sctp6_detach(struct socket * so)6848c2654abSrjs sctp6_detach(struct socket *so)
6858c2654abSrjs {
6868c2654abSrjs struct sctp_inpcb *inp;
6878c2654abSrjs
6888c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
6898c2654abSrjs if (inp == 0)
6908c2654abSrjs return EINVAL;
6918c2654abSrjs
6928c2654abSrjs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
6938c2654abSrjs (so->so_rcv.sb_cc > 0))
6948c2654abSrjs sctp_inpcb_free(inp, 1);
6958c2654abSrjs else
6968c2654abSrjs sctp_inpcb_free(inp, 0);
6978c2654abSrjs return 0;
6988c2654abSrjs }
6998c2654abSrjs
7008c2654abSrjs static int
sctp6_disconnect(struct socket * so)7018c2654abSrjs sctp6_disconnect(struct socket *so)
7028c2654abSrjs {
7038c2654abSrjs struct sctp_inpcb *inp;
7048c2654abSrjs
7058c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
7068c2654abSrjs if (inp == NULL) {
7078c2654abSrjs return (ENOTCONN);
7088c2654abSrjs }
7098c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
7108c2654abSrjs if (LIST_EMPTY(&inp->sctp_asoc_list)) {
7118c2654abSrjs /* No connection */
7128c2654abSrjs return (ENOTCONN);
7138c2654abSrjs } else {
7148c2654abSrjs int some_on_streamwheel = 0;
7158c2654abSrjs struct sctp_association *asoc;
7168c2654abSrjs struct sctp_tcb *stcb;
7178c2654abSrjs
7188c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list);
7198c2654abSrjs if (stcb == NULL) {
7208c2654abSrjs return (EINVAL);
7218c2654abSrjs }
7228c2654abSrjs asoc = &stcb->asoc;
7238c2654abSrjs if (!TAILQ_EMPTY(&asoc->out_wheel)) {
7248c2654abSrjs /* Check to see if some data queued */
7258c2654abSrjs struct sctp_stream_out *outs;
7268c2654abSrjs TAILQ_FOREACH(outs, &asoc->out_wheel,
7278c2654abSrjs next_spoke) {
7288c2654abSrjs if (!TAILQ_EMPTY(&outs->outqueue)) {
7298c2654abSrjs some_on_streamwheel = 1;
7308c2654abSrjs break;
7318c2654abSrjs }
7328c2654abSrjs }
7338c2654abSrjs }
7348c2654abSrjs
7358c2654abSrjs if (TAILQ_EMPTY(&asoc->send_queue) &&
7368c2654abSrjs TAILQ_EMPTY(&asoc->sent_queue) &&
7378c2654abSrjs (some_on_streamwheel == 0)) {
7388c2654abSrjs /* nothing queued to send, so I'm done... */
7398c2654abSrjs if ((SCTP_GET_STATE(asoc) !=
7408c2654abSrjs SCTP_STATE_SHUTDOWN_SENT) &&
7418c2654abSrjs (SCTP_GET_STATE(asoc) !=
7428c2654abSrjs SCTP_STATE_SHUTDOWN_ACK_SENT)) {
7438c2654abSrjs /* only send SHUTDOWN the first time */
7448c2654abSrjs #ifdef SCTP_DEBUG
7458c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
7468c2654abSrjs printf("%s:%d sends a shutdown\n",
7478c2654abSrjs __FILE__,
7488c2654abSrjs __LINE__
7498c2654abSrjs );
7508c2654abSrjs }
7518c2654abSrjs #endif
7528c2654abSrjs sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
7538c2654abSrjs sctp_chunk_output(stcb->sctp_ep, stcb, 1);
7548c2654abSrjs asoc->state = SCTP_STATE_SHUTDOWN_SENT;
7558c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
7568c2654abSrjs stcb->sctp_ep, stcb,
7578c2654abSrjs asoc->primary_destination);
7588c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
7598c2654abSrjs stcb->sctp_ep, stcb,
7608c2654abSrjs asoc->primary_destination);
7618c2654abSrjs }
7628c2654abSrjs } else {
7638c2654abSrjs /*
7648c2654abSrjs * we still got (or just got) data to send,
7658c2654abSrjs * so set SHUTDOWN_PENDING
7668c2654abSrjs */
7678c2654abSrjs /*
7688c2654abSrjs * XXX sockets draft says that MSG_EOF should
7698c2654abSrjs * be sent with no data. currently, we will
7708c2654abSrjs * allow user data to be sent first and move
7718c2654abSrjs * to SHUTDOWN-PENDING
7728c2654abSrjs */
7738c2654abSrjs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
7748c2654abSrjs }
7758c2654abSrjs return (0);
7768c2654abSrjs }
7778c2654abSrjs } else {
7788c2654abSrjs /* UDP model does not support this */
7798c2654abSrjs return EOPNOTSUPP;
7808c2654abSrjs }
7818c2654abSrjs }
7828c2654abSrjs
7838c2654abSrjs static int
sctp6_recvoob(struct socket * so,struct mbuf * m,int flags)7848c2654abSrjs sctp6_recvoob(struct socket *so, struct mbuf *m, int flags)
7858c2654abSrjs {
7868c2654abSrjs KASSERT(solocked(so));
7878c2654abSrjs
7888c2654abSrjs return EOPNOTSUPP;
7898c2654abSrjs }
7908c2654abSrjs
7918c2654abSrjs static int
sctp6_send(struct socket * so,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct lwp * l)7928c2654abSrjs sctp6_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
7938c2654abSrjs struct mbuf *control, struct lwp *l)
7948c2654abSrjs {
7958c2654abSrjs struct sctp_inpcb *inp;
7968c2654abSrjs struct in6pcb *inp6;
7978c2654abSrjs #ifdef INET
7988c2654abSrjs struct sockaddr_in6 *sin6;
7998c2654abSrjs #endif /* INET */
8008c2654abSrjs /* No SPL needed since sctp_output does this */
8018c2654abSrjs
8028c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
8038c2654abSrjs if (inp == NULL) {
8048c2654abSrjs m_freem(control);
8058c2654abSrjs control = NULL;
8068c2654abSrjs m_freem(m);
8078c2654abSrjs return EINVAL;
8088c2654abSrjs }
8098c2654abSrjs inp6 = (struct in6pcb *)inp;
8108c2654abSrjs /* For the TCP model we may get a NULL addr, if we
8118c2654abSrjs * are a connected socket thats ok.
8128c2654abSrjs */
8138c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
8148c2654abSrjs (nam == NULL)) {
8158c2654abSrjs goto connected_type;
8168c2654abSrjs }
8178c2654abSrjs if (nam == NULL) {
8188c2654abSrjs m_freem(m);
8198c2654abSrjs m_freem(control);
8208c2654abSrjs control = NULL;
8218c2654abSrjs return (EDESTADDRREQ);
8228c2654abSrjs }
8238c2654abSrjs
8248c2654abSrjs #ifdef INET
8258c2654abSrjs sin6 = (struct sockaddr_in6 *)nam;
826d020c71cSmaxv /*
827d020c71cSmaxv * XXX XXX XXX Check sin6->sin6_len?
828d020c71cSmaxv */
8298c2654abSrjs if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) {
8308c2654abSrjs /*
8318c2654abSrjs * if IPV6_V6ONLY flag, we discard datagrams
8328c2654abSrjs * destined to a v4 addr or v4-mapped addr
8338c2654abSrjs */
8348c2654abSrjs if (nam->sa_family == AF_INET) {
8358c2654abSrjs return EINVAL;
8368c2654abSrjs }
8378c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
8388c2654abSrjs return EINVAL;
8398c2654abSrjs }
8408c2654abSrjs }
8418c2654abSrjs
8428c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
8438c2654abSrjs if (!ip6_v6only) {
8448c2654abSrjs struct sockaddr_in sin;
8458c2654abSrjs /* convert v4-mapped into v4 addr and send */
8468c2654abSrjs in6_sin6_2_sin(&sin, sin6);
8478c2654abSrjs return sctp_send(so, m, (struct sockaddr *)&sin,
8488c2654abSrjs control, l);
8498c2654abSrjs } else {
8508c2654abSrjs /* mapped addresses aren't enabled */
8518c2654abSrjs return EINVAL;
8528c2654abSrjs }
8538c2654abSrjs }
8548c2654abSrjs #endif /* INET */
8558c2654abSrjs connected_type:
8568c2654abSrjs /* now what about control */
8578c2654abSrjs if (control) {
8588c2654abSrjs if (inp->control) {
8598c2654abSrjs printf("huh? control set?\n");
8608c2654abSrjs m_freem(inp->control);
8618c2654abSrjs inp->control = NULL;
8628c2654abSrjs }
8638c2654abSrjs inp->control = control;
8648c2654abSrjs }
8658c2654abSrjs /* add it in possibly */
8668c2654abSrjs if ((inp->pkt) &&
8678c2654abSrjs (inp->pkt->m_flags & M_PKTHDR)) {
8688c2654abSrjs struct mbuf *x;
8698c2654abSrjs int c_len;
8708c2654abSrjs
8718c2654abSrjs c_len = 0;
8728c2654abSrjs /* How big is it */
8738c2654abSrjs for (x=m;x;x = x->m_next) {
8748c2654abSrjs c_len += x->m_len;
8758c2654abSrjs }
8768c2654abSrjs inp->pkt->m_pkthdr.len += c_len;
8778c2654abSrjs }
8788c2654abSrjs /* Place the data */
8798c2654abSrjs if (inp->pkt) {
8808c2654abSrjs inp->pkt_last->m_next = m;
8818c2654abSrjs inp->pkt_last = m;
8828c2654abSrjs } else {
8838c2654abSrjs inp->pkt_last = inp->pkt = m;
8848c2654abSrjs }
8858c2654abSrjs if ((so->so_state & SS_MORETOCOME) == 0) {
8868c2654abSrjs /*
8878c2654abSrjs * note with the current version this code will only be
8888c2654abSrjs * used by OpenBSD, NetBSD and FreeBSD have methods for
8898c2654abSrjs * re-defining sosend() to use sctp_sosend(). One can
890*50d76f75Sandvar * optionally switch back to this code (by changing back
891*50d76f75Sandvar * the definitions but this is not advisable.
8928c2654abSrjs */
8938c2654abSrjs int ret;
8948c2654abSrjs ret = sctp_output(inp, inp->pkt , nam, inp->control, l, 0);
8958c2654abSrjs inp->pkt = NULL;
8968c2654abSrjs inp->control = NULL;
8978c2654abSrjs return (ret);
8988c2654abSrjs } else {
8998c2654abSrjs return (0);
9008c2654abSrjs }
9018c2654abSrjs }
9028c2654abSrjs
9038c2654abSrjs static int
sctp6_sendoob(struct socket * so,struct mbuf * m,struct mbuf * control)9048c2654abSrjs sctp6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
9058c2654abSrjs {
9068c2654abSrjs KASSERT(solocked(so));
9078c2654abSrjs
9088c2654abSrjs m_freem(m);
9098c2654abSrjs m_freem(control);
9108c2654abSrjs
9118c2654abSrjs return EOPNOTSUPP;
9128c2654abSrjs }
9138c2654abSrjs
9148c2654abSrjs static int
sctp6_connect(struct socket * so,struct sockaddr * nam,struct lwp * l)9158c2654abSrjs sctp6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
9168c2654abSrjs {
9178c2654abSrjs int error = 0;
9188c2654abSrjs struct sctp_inpcb *inp;
9198c2654abSrjs struct in6pcb *inp6;
9208c2654abSrjs struct sctp_tcb *stcb;
9218c2654abSrjs #ifdef INET
9228c2654abSrjs struct sockaddr_in6 *sin6;
9238c2654abSrjs struct sockaddr_storage ss;
9248c2654abSrjs #endif /* INET */
9258c2654abSrjs
9268c2654abSrjs inp6 = (struct in6pcb *)so->so_pcb;
9278c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
9288c2654abSrjs if (inp == 0) {
9298c2654abSrjs return (ECONNRESET); /* I made the same as TCP since
9308c2654abSrjs * we are not setup? */
9318c2654abSrjs }
9328c2654abSrjs SCTP_ASOC_CREATE_LOCK(inp);
9338c2654abSrjs SCTP_INP_RLOCK(inp);
9348c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
9358c2654abSrjs SCTP_PCB_FLAGS_UNBOUND) {
9368c2654abSrjs /* Bind a ephemeral port */
9378c2654abSrjs SCTP_INP_RUNLOCK(inp);
9388c2654abSrjs error = sctp6_bind(so, NULL, l);
9398c2654abSrjs if (error) {
9408c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
9418c2654abSrjs
9428c2654abSrjs return (error);
9438c2654abSrjs }
9448c2654abSrjs SCTP_INP_RLOCK(inp);
9458c2654abSrjs }
9468c2654abSrjs
9478c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
9488c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
9498c2654abSrjs /* We are already connected AND the TCP model */
9508c2654abSrjs SCTP_INP_RUNLOCK(inp);
9518c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
9528c2654abSrjs return (EADDRINUSE);
9538c2654abSrjs }
9548c2654abSrjs
9558c2654abSrjs #ifdef INET
9568c2654abSrjs sin6 = (struct sockaddr_in6 *)nam;
957d26f60daSmaxv
958d26f60daSmaxv /*
959d26f60daSmaxv * XXX XXX XXX Check sin6->sin6_len?
960d26f60daSmaxv */
961d26f60daSmaxv
9628c2654abSrjs if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) {
9638c2654abSrjs /*
9648c2654abSrjs * if IPV6_V6ONLY flag, ignore connections
9658c2654abSrjs * destined to a v4 addr or v4-mapped addr
9668c2654abSrjs */
9678c2654abSrjs if (nam->sa_family == AF_INET) {
9688c2654abSrjs SCTP_INP_RUNLOCK(inp);
9698c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
9708c2654abSrjs return EINVAL;
9718c2654abSrjs }
9728c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
9738c2654abSrjs SCTP_INP_RUNLOCK(inp);
9748c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
9758c2654abSrjs return EINVAL;
9768c2654abSrjs }
9778c2654abSrjs }
9788c2654abSrjs
9798c2654abSrjs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
9808c2654abSrjs if (!ip6_v6only) {
9818c2654abSrjs /* convert v4-mapped into v4 addr */
9828c2654abSrjs in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
9838c2654abSrjs nam = (struct sockaddr *)&ss;
9848c2654abSrjs } else {
9858c2654abSrjs /* mapped addresses aren't enabled */
9868c2654abSrjs SCTP_INP_RUNLOCK(inp);
9878c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
9888c2654abSrjs return EINVAL;
9898c2654abSrjs }
9908c2654abSrjs }
9918c2654abSrjs #endif /* INET */
9928c2654abSrjs
9938c2654abSrjs /* Now do we connect? */
9948c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
9958c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list);
9968c2654abSrjs if (stcb) {
9978c2654abSrjs SCTP_TCB_UNLOCK (stcb);
9988c2654abSrjs }
9998c2654abSrjs SCTP_INP_RUNLOCK(inp);
10008c2654abSrjs } else {
10018c2654abSrjs SCTP_INP_RUNLOCK(inp);
10028c2654abSrjs SCTP_INP_WLOCK(inp);
10038c2654abSrjs SCTP_INP_INCR_REF(inp);
10048c2654abSrjs SCTP_INP_WUNLOCK(inp);
10058c2654abSrjs stcb = sctp_findassociation_ep_addr(&inp, nam, NULL, NULL, NULL);
10068c2654abSrjs if (stcb == NULL) {
10078c2654abSrjs SCTP_INP_WLOCK(inp);
10088c2654abSrjs SCTP_INP_DECR_REF(inp);
10098c2654abSrjs SCTP_INP_WUNLOCK(inp);
10108c2654abSrjs }
10118c2654abSrjs }
10128c2654abSrjs
10138c2654abSrjs if (stcb != NULL) {
10148c2654abSrjs /* Already have or am bring up an association */
10158c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
10168c2654abSrjs SCTP_TCB_UNLOCK (stcb);
10178c2654abSrjs return (EALREADY);
10188c2654abSrjs }
10198c2654abSrjs /* We are GOOD to go */
10208c2654abSrjs stcb = sctp_aloc_assoc(inp, nam, 1, &error, 0);
10218c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
10228c2654abSrjs if (stcb == NULL) {
10238c2654abSrjs /* Gak! no memory */
10248c2654abSrjs return (error);
10258c2654abSrjs }
10268c2654abSrjs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
10278c2654abSrjs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
10288c2654abSrjs /* Set the connected flag so we can queue data */
10298c2654abSrjs soisconnecting(so);
10308c2654abSrjs }
10318c2654abSrjs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
10328c2654abSrjs SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
10338c2654abSrjs sctp_send_initiate(inp, stcb);
10348c2654abSrjs SCTP_TCB_UNLOCK (stcb);
10358c2654abSrjs return error;
10368c2654abSrjs }
10378c2654abSrjs
10388c2654abSrjs static int
sctp6_connect2(struct socket * so,struct socket * so2)10398c2654abSrjs sctp6_connect2(struct socket *so, struct socket *so2)
10408c2654abSrjs {
10418c2654abSrjs KASSERT(solocked(so));
10428c2654abSrjs
10438c2654abSrjs return EOPNOTSUPP;
10448c2654abSrjs }
10458c2654abSrjs
10468c2654abSrjs static int
sctp6_getaddr(struct socket * so,struct sockaddr * nam)10478c2654abSrjs sctp6_getaddr(struct socket *so, struct sockaddr *nam)
10488c2654abSrjs {
10498c2654abSrjs struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
10508c2654abSrjs struct sctp_inpcb *inp;
10518c2654abSrjs int error;
10528c2654abSrjs
10538c2654abSrjs /*
10548c2654abSrjs * Do the malloc first in case it blocks.
10558c2654abSrjs */
10568c2654abSrjs memset(sin6, 0, sizeof(*sin6));
10578c2654abSrjs sin6->sin6_family = AF_INET6;
10588c2654abSrjs sin6->sin6_len = sizeof(*sin6);
10598c2654abSrjs
10608c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
10618c2654abSrjs if (inp == NULL) {
10628c2654abSrjs return ECONNRESET;
10638c2654abSrjs }
10648c2654abSrjs
10658c2654abSrjs sin6->sin6_port = inp->sctp_lport;
10668c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
10678c2654abSrjs /* For the bound all case you get back 0 */
10688c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
10698c2654abSrjs struct sctp_tcb *stcb;
10708c2654abSrjs const struct sockaddr_in6 *sin_a6;
10718c2654abSrjs struct sctp_nets *net;
10728c2654abSrjs int fnd;
10738c2654abSrjs
10748c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list);
10758c2654abSrjs if (stcb == NULL) {
10768c2654abSrjs goto notConn6;
10778c2654abSrjs }
10788c2654abSrjs fnd = 0;
10798c2654abSrjs sin_a6 = NULL;
10808c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
10818c2654abSrjs sin_a6 = (const struct sockaddr_in6 *)rtcache_getdst(&net->ro);
10828c2654abSrjs if (sin_a6->sin6_family == AF_INET6) {
10838c2654abSrjs fnd = 1;
10848c2654abSrjs break;
10858c2654abSrjs }
10868c2654abSrjs }
10878c2654abSrjs if ((!fnd) || (sin_a6 == NULL)) {
10888c2654abSrjs /* punt */
10898c2654abSrjs goto notConn6;
10908c2654abSrjs }
10918c2654abSrjs sin6->sin6_addr = sctp_ipv6_source_address_selection(
10928c2654abSrjs inp, stcb, &net->ro, net, 0);
10938c2654abSrjs
10948c2654abSrjs } else {
10958c2654abSrjs /* For the bound all case you get back 0 */
10968c2654abSrjs notConn6:
10978c2654abSrjs memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
10988c2654abSrjs }
10998c2654abSrjs } else {
11008c2654abSrjs /* Take the first IPv6 address in the list */
11018c2654abSrjs struct sctp_laddr *laddr;
11028c2654abSrjs int fnd = 0;
11038c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
11048c2654abSrjs if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
11058c2654abSrjs struct sockaddr_in6 *sin_a;
11068c2654abSrjs sin_a = (struct sockaddr_in6 *)laddr->ifa->ifa_addr;
11078c2654abSrjs sin6->sin6_addr = sin_a->sin6_addr;
11088c2654abSrjs fnd = 1;
11098c2654abSrjs break;
11108c2654abSrjs }
11118c2654abSrjs }
11128c2654abSrjs if (!fnd) {
11138c2654abSrjs return ENOENT;
11148c2654abSrjs }
11158c2654abSrjs }
11168c2654abSrjs /* Scoping things for v6 */
11178c2654abSrjs if ((error = sa6_recoverscope(sin6)) != 0)
11188c2654abSrjs return (error);
11198c2654abSrjs
11208c2654abSrjs return (0);
11218c2654abSrjs }
11228c2654abSrjs
11238c2654abSrjs static int
sctp6_peeraddr(struct socket * so,struct sockaddr * nam)11248c2654abSrjs sctp6_peeraddr(struct socket *so, struct sockaddr *nam)
11258c2654abSrjs {
11268c2654abSrjs struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
11278c2654abSrjs int fnd, error;
11288c2654abSrjs const struct sockaddr_in6 *sin_a6;
11298c2654abSrjs struct sctp_inpcb *inp;
11308c2654abSrjs struct sctp_tcb *stcb;
11318c2654abSrjs struct sctp_nets *net;
11328c2654abSrjs /*
11338c2654abSrjs * Do the malloc first in case it blocks.
11348c2654abSrjs */
11358c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
11368c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
11378c2654abSrjs /* UDP type and listeners will drop out here */
11388c2654abSrjs return (ENOTCONN);
11398c2654abSrjs }
11408c2654abSrjs memset(sin6, 0, sizeof(*sin6));
11418c2654abSrjs sin6->sin6_family = AF_INET6;
11428c2654abSrjs sin6->sin6_len = sizeof(*sin6);
11438c2654abSrjs
11448c2654abSrjs /* We must recapture incase we blocked */
11458c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
11468c2654abSrjs if (inp == NULL) {
11478c2654abSrjs return ECONNRESET;
11488c2654abSrjs }
11498c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list);
11508c2654abSrjs if (stcb == NULL) {
11518c2654abSrjs return ECONNRESET;
11528c2654abSrjs }
11538c2654abSrjs fnd = 0;
11548c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
11558c2654abSrjs sin_a6 = (const struct sockaddr_in6 *)rtcache_getdst(&net->ro);
11568c2654abSrjs if (sin_a6->sin6_family == AF_INET6) {
11578c2654abSrjs fnd = 1;
11588c2654abSrjs sin6->sin6_port = stcb->rport;
11598c2654abSrjs sin6->sin6_addr = sin_a6->sin6_addr;
11608c2654abSrjs break;
11618c2654abSrjs }
11628c2654abSrjs }
11638c2654abSrjs if (!fnd) {
11648c2654abSrjs /* No IPv4 address */
11658c2654abSrjs return ENOENT;
11668c2654abSrjs }
11678c2654abSrjs if ((error = sa6_recoverscope(sin6)) != 0)
11688c2654abSrjs return (error);
11698c2654abSrjs
11708c2654abSrjs return (0);
11718c2654abSrjs }
11728c2654abSrjs
11738c2654abSrjs static int
sctp6_sockaddr(struct socket * so,struct sockaddr * nam)11748c2654abSrjs sctp6_sockaddr(struct socket *so, struct sockaddr *nam)
11758c2654abSrjs {
11768c2654abSrjs struct in6pcb *inp6 = sotoin6pcb(so);
11778c2654abSrjs int error;
11788c2654abSrjs
11798c2654abSrjs if (inp6 == NULL)
11808c2654abSrjs return EINVAL;
11818c2654abSrjs
11828c2654abSrjs /* allow v6 addresses precedence */
11838c2654abSrjs error = sctp6_getaddr(so, nam);
11848c2654abSrjs if (error) {
11858c2654abSrjs /* try v4 next if v6 failed */
11868c2654abSrjs error = sctp_sockaddr(so, nam);
11878c2654abSrjs if (error) {
11888c2654abSrjs return (error);
11898c2654abSrjs }
11908c2654abSrjs
11918c2654abSrjs /* if I'm V6ONLY, convert it to v4-mapped */
11928c2654abSrjs if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) {
11938c2654abSrjs struct sockaddr_in6 sin6;
11948c2654abSrjs in6_sin_2_v4mapsin6((struct sockaddr_in *)nam, &sin6);
11958c2654abSrjs memcpy(nam, &sin6, sizeof(struct sockaddr_in6));
11968c2654abSrjs }
11978c2654abSrjs }
11988c2654abSrjs return (error);
11998c2654abSrjs }
12008c2654abSrjs
12018c2654abSrjs #if 0
12028c2654abSrjs static int
12038c2654abSrjs sctp6_getpeeraddr(struct socket *so, struct sockaddr *nam)
12048c2654abSrjs {
12058c2654abSrjs struct in6pcb *inp6 = sotoin6pcb(so);
12068c2654abSrjs int error;
12078c2654abSrjs
12088c2654abSrjs if (inp6 == NULL)
12098c2654abSrjs return EINVAL;
12108c2654abSrjs
12118c2654abSrjs /* allow v6 addresses precedence */
12128c2654abSrjs error = sctp6_peeraddr(so, nam);
12138c2654abSrjs if (error) {
12148c2654abSrjs /* try v4 next if v6 failed */
12158c2654abSrjs error = sctp_peeraddr(so, nam);
12168c2654abSrjs if (error) {
12178c2654abSrjs return (error);
12188c2654abSrjs }
12198c2654abSrjs /* if I'm V6ONLY, convert it to v4-mapped */
12208c2654abSrjs if ((inp6->in6p_flags & IN6P_IPV6_V6ONLY)) {
12218c2654abSrjs struct sockaddr_in6 sin6;
12228c2654abSrjs in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
12238c2654abSrjs memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
12248c2654abSrjs }
12258c2654abSrjs }
12268c2654abSrjs return error;
12278c2654abSrjs }
12288c2654abSrjs #endif
12298c2654abSrjs
12308c2654abSrjs static int
sctp6_ioctl(struct socket * so,u_long cmd,void * nam,struct ifnet * ifp)12318c2654abSrjs sctp6_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
12328c2654abSrjs {
12338c2654abSrjs int error = 0;
12348c2654abSrjs int family;
12358c2654abSrjs
12367cd04cafSrjs if (cmd == SIOCCONNECTX) {
12377cd04cafSrjs solock(so);
12387cd04cafSrjs error = sctp_do_connect_x(so, nam, curlwp, 0);
12397cd04cafSrjs sounlock(so);
12407cd04cafSrjs } else if (cmd == SIOCCONNECTXDEL) {
12417cd04cafSrjs solock(so);
12427cd04cafSrjs error = sctp_do_connect_x(so, nam, curlwp, 1);
12437cd04cafSrjs sounlock(so);
12447cd04cafSrjs } else {
12458c2654abSrjs family = so->so_proto->pr_domain->dom_family;
12468c2654abSrjs switch (family) {
12478c2654abSrjs #ifdef INET
12488c2654abSrjs case PF_INET:
12498c2654abSrjs error = in_control(so, cmd, nam, ifp);
12508c2654abSrjs break;
12518c2654abSrjs #endif
12528c2654abSrjs #ifdef INET6
12538c2654abSrjs case PF_INET6:
12548c2654abSrjs error = in6_control(so, cmd, nam, ifp);
12558c2654abSrjs break;
12568c2654abSrjs #endif
12578c2654abSrjs default:
12588c2654abSrjs error = EAFNOSUPPORT;
12598c2654abSrjs }
12607cd04cafSrjs }
12618c2654abSrjs return (error);
12628c2654abSrjs }
12638c2654abSrjs
12648c2654abSrjs static int
sctp6_accept(struct socket * so,struct sockaddr * nam)12658c2654abSrjs sctp6_accept(struct socket *so, struct sockaddr *nam)
12668c2654abSrjs {
126714564804Srjs return sctp_accept(so, nam);
12688c2654abSrjs }
12698c2654abSrjs
12708c2654abSrjs static int
sctp6_stat(struct socket * so,struct stat * ub)12718c2654abSrjs sctp6_stat(struct socket *so, struct stat *ub)
12728c2654abSrjs {
12738c2654abSrjs return 0;
12748c2654abSrjs }
12758c2654abSrjs
12768c2654abSrjs static int
sctp6_listen(struct socket * so,struct lwp * l)12778c2654abSrjs sctp6_listen(struct socket *so, struct lwp *l)
12788c2654abSrjs {
12798c2654abSrjs return sctp_listen(so, l);
12808c2654abSrjs }
12818c2654abSrjs
12828c2654abSrjs static int
sctp6_shutdown(struct socket * so)12838c2654abSrjs sctp6_shutdown(struct socket *so)
12848c2654abSrjs {
12858c2654abSrjs return sctp_shutdown(so);
12868c2654abSrjs }
12878c2654abSrjs
12888c2654abSrjs static int
sctp6_rcvd(struct socket * so,int flags,struct lwp * l)12898c2654abSrjs sctp6_rcvd(struct socket *so, int flags, struct lwp *l)
12908c2654abSrjs {
12918c2654abSrjs KASSERT(solocked(so));
12928c2654abSrjs
12938c2654abSrjs return sctp_rcvd(so, flags, l);
12948c2654abSrjs }
12958c2654abSrjs
12968c2654abSrjs static int
sctp6_purgeif(struct socket * so,struct ifnet * ifp)12978c2654abSrjs sctp6_purgeif(struct socket *so, struct ifnet *ifp)
12988c2654abSrjs {
12998c2654abSrjs struct ifaddr *ifa;
1300a403cbd4Sozaki-r /* FIXME NOMPSAFE */
13019e4c2bdaSozaki-r IFADDR_READER_FOREACH(ifa, ifp) {
13028c2654abSrjs if (ifa->ifa_addr->sa_family == PF_INET6) {
13038c2654abSrjs sctp_delete_ip_address(ifa);
13048c2654abSrjs }
13058c2654abSrjs }
13068c2654abSrjs
13072526d8f6Sknakahara #ifndef NET_MPSAFE
13088c2654abSrjs mutex_enter(softnet_lock);
13092526d8f6Sknakahara #endif
13108c2654abSrjs in6_purgeif(ifp);
13112526d8f6Sknakahara #ifndef NET_MPSAFE
13128c2654abSrjs mutex_exit(softnet_lock);
13132526d8f6Sknakahara #endif
13148c2654abSrjs
13158c2654abSrjs return 0;
13168c2654abSrjs }
13178c2654abSrjs
13188c2654abSrjs PR_WRAP_USRREQS(sctp6)
13198c2654abSrjs #define sctp6_attach sctp6_attach_wrapper
13208c2654abSrjs #define sctp6_detach sctp6_detach_wrapper
13218c2654abSrjs #define sctp6_accept sctp6_accept_wrapper
13228c2654abSrjs #define sctp6_bind sctp6_bind_wrapper
13238c2654abSrjs #define sctp6_listen sctp6_listen_wrapper
13248c2654abSrjs #define sctp6_connect sctp6_connect_wrapper
13258c2654abSrjs #define sctp6_connect2 sctp6_connect2_wrapper
13268c2654abSrjs #define sctp6_disconnect sctp6_disconnect_wrapper
13278c2654abSrjs #define sctp6_shutdown sctp6_shutdown_wrapper
13288c2654abSrjs #define sctp6_abort sctp6_abort_wrapper
13298c2654abSrjs #define sctp6_ioctl sctp6_ioctl_wrapper
13308c2654abSrjs #define sctp6_stat sctp6_stat_wrapper
13318c2654abSrjs #define sctp6_peeraddr sctp6_peeraddr_wrapper
13328c2654abSrjs #define sctp6_sockaddr sctp6_sockaddr_wrapper
13338c2654abSrjs #define sctp6_rcvd sctp6_rcvd_wrapper
13348c2654abSrjs #define sctp6_recvoob sctp6_recvoob_wrapper
13358c2654abSrjs #define sctp6_send sctp6_send_wrapper
13368c2654abSrjs #define sctp6_sendoob sctp6_sendoob_wrapper
13378c2654abSrjs #define sctp6_purgeif sctp6_purgeif_wrapper
13388c2654abSrjs
13398c2654abSrjs const struct pr_usrreqs sctp6_usrreqs = {
13408c2654abSrjs .pr_attach = sctp6_attach,
13418c2654abSrjs .pr_detach = sctp6_detach,
13428c2654abSrjs .pr_accept = sctp6_accept,
13438c2654abSrjs .pr_bind = sctp6_bind,
13448c2654abSrjs .pr_listen = sctp6_listen,
13458c2654abSrjs .pr_connect = sctp6_connect,
13468c2654abSrjs .pr_connect2 = sctp6_connect2,
13478c2654abSrjs .pr_disconnect = sctp6_disconnect,
13488c2654abSrjs .pr_shutdown = sctp6_shutdown,
13498c2654abSrjs .pr_abort = sctp6_abort,
13508c2654abSrjs .pr_ioctl = sctp6_ioctl,
13518c2654abSrjs .pr_stat = sctp6_stat,
13528c2654abSrjs .pr_peeraddr = sctp6_peeraddr,
13538c2654abSrjs .pr_sockaddr = sctp6_sockaddr,
13548c2654abSrjs .pr_rcvd = sctp6_rcvd,
13558c2654abSrjs .pr_recvoob = sctp6_recvoob,
13568c2654abSrjs .pr_send = sctp6_send,
13578c2654abSrjs .pr_sendoob = sctp6_sendoob,
13588c2654abSrjs .pr_purgeif = sctp6_purgeif,
13598c2654abSrjs };
1360