The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/sctp6_usrreq.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $KAME: sctp6_usrreq.c,v 1.35 2004/08/17 06:28:03 t-momose Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Cisco Systems, Inc.
   18  * 4. Neither the name of the project nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL CISCO SYSTEMS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 #if !(defined(__OpenBSD__) || defined(__APPLE__))
   35 #include "opt_inet.h"
   36 #endif
   37 #if defined(__FreeBSD__) || defined(__DragonFly__)
   38 #include "opt_inet6.h"
   39 #include "opt_inet.h"
   40 #endif
   41 #ifdef __NetBSD__
   42 #include "opt_inet.h"
   43 #endif
   44 #if !(defined(__OpenBSD__) || defined(__APPLE__))
   45 #include "opt_ipsec.h"
   46 #endif
   47 #ifdef __APPLE__
   48 #include <sctp.h>
   49 #elif !defined(__OpenBSD__)
   50 #include "opt_sctp.h"
   51 #endif
   52 
   53 #include <sys/param.h>
   54 #include <sys/kernel.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/domain.h>
   57 #include <sys/protosw.h>
   58 #include <sys/socket.h>
   59 #include <sys/malloc.h>
   60 #include <sys/socketvar.h>
   61 #include <sys/sysctl.h>
   62 #include <sys/errno.h>
   63 #include <sys/stat.h>
   64 #include <sys/systm.h>
   65 #include <sys/syslog.h>
   66 #include <sys/proc.h>
   67 
   68 #include <sys/thread2.h>
   69 #include <sys/msgport2.h>
   70 
   71 #include <net/if.h>
   72 #include <net/route.h>
   73 #include <net/if_types.h>
   74 #include <netinet/in.h>
   75 #include <netinet/in_systm.h>
   76 #include <netinet/ip.h>
   77 #include <netinet/in_pcb.h>
   78 #include <netinet/in_var.h>
   79 #include <netinet/ip_var.h>
   80 #include <netinet/sctp_pcb.h>
   81 #include <netinet/sctp_header.h>
   82 #include <netinet/sctp_var.h>
   83 #include <netinet/sctputil.h>
   84 #include <netinet/sctp_output.h>
   85 #include <netinet/sctp_input.h>
   86 #include <netinet/sctp_asconf.h>
   87 #include <netinet6/ip6_var.h>
   88 #include <netinet/ip6.h>
   89 #if !defined(__OpenBSD__)
   90 #include <netinet6/in6_pcb.h>
   91 #endif
   92 #include <netinet/icmp6.h>
   93 #include <netinet6/sctp6_var.h>
   94 #include <netinet6/ip6protosw.h>
   95 #include <netinet6/nd6.h>
   96 
   97 #ifdef IPSEC
   98 #ifndef __OpenBSD__
   99 #include <netinet6/ipsec6.h>
  100 #include <netinet6/ipsec.h>
  101 #else
  102 #undef IPSEC
  103 #endif
  104 #endif /*IPSEC*/
  105 
  106 #if defined(NFAITH) && NFAITH > 0
  107 #include <net/if_faith.h>
  108 #endif
  109 
  110 #include <net/net_osdep.h>
  111 
  112 extern struct protosw inetsw[];
  113 
  114 #if defined(HAVE_NRL_INPCB) || defined(__FreeBSD__) || defined(__DragonFly__)
  115 #ifndef in6pcb
  116 #define in6pcb          inpcb
  117 #endif
  118 #ifndef sotoin6pcb
  119 #define sotoin6pcb      sotoinpcb
  120 #endif
  121 #endif
  122 
  123 #ifdef SCTP_DEBUG
  124 extern u_int32_t sctp_debug_on;
  125 #endif
  126 
  127 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
  128 extern void in6_sin_2_v4mapsin6 (struct sockaddr_in *sin,
  129                                  struct sockaddr_in6 *sin6);
  130 extern void in6_sin6_2_sin (struct sockaddr_in *,
  131                             struct sockaddr_in6 *sin6);
  132 extern void in6_sin6_2_sin_in_sock(struct sockaddr *nam);
  133 
  134 /*
  135  * Convert sockaddr_in6 to sockaddr_in.  Original sockaddr_in6 must be
  136  * v4 mapped addr or v4 compat addr
  137  */
  138 void
  139 in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
  140 {
  141         bzero(sin, sizeof(*sin));
  142         sin->sin_len = sizeof(struct sockaddr_in);
  143         sin->sin_family = AF_INET;
  144         sin->sin_port = sin6->sin6_port;
  145         sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
  146 }
  147 
  148 /* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
  149 void
  150 in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
  151 {
  152         bzero(sin6, sizeof(*sin6));
  153         sin6->sin6_len = sizeof(struct sockaddr_in6);
  154         sin6->sin6_family = AF_INET6;
  155         sin6->sin6_port = sin->sin_port;
  156         sin6->sin6_addr.s6_addr32[0] = 0;
  157         sin6->sin6_addr.s6_addr32[1] = 0;
  158         sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
  159         sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
  160 }
  161 
  162 /* Convert sockaddr_in6 into sockaddr_in. */
  163 void
  164 in6_sin6_2_sin_in_sock(struct sockaddr *nam)
  165 {
  166         struct sockaddr_in *sin_p;
  167         struct sockaddr_in6 sin6;
  168 
  169         /* save original sockaddr_in6 addr and convert it to sockaddr_in  */
  170         sin6 = *(struct sockaddr_in6 *)nam;
  171         sin_p = (struct sockaddr_in *)nam;
  172         in6_sin6_2_sin(sin_p, &sin6);
  173 }
  174 
  175 #endif /* !(__FreeBSD__ || __APPLE__) */
  176 
  177 static int sctp6_bind_oncpu(struct socket *so, struct sockaddr *addr, thread_t td);
  178 
  179 
  180 extern int sctp_no_csum_on_loopback;
  181 
  182 int
  183 sctp6_input(struct mbuf **mp, int *offp, int proto)
  184 {
  185         struct mbuf *m = *mp;
  186         struct ip6_hdr *ip6;
  187         struct sctphdr *sh;
  188         struct sctp_inpcb *in6p = NULL;
  189         struct sctp_nets *net;
  190         int refcount_up = 0;
  191         u_int32_t check, calc_check;
  192         struct inpcb *in6p_ip;
  193         struct sctp_chunkhdr *ch;
  194         struct mbuf *opts = NULL;
  195         int length, mlen, offset, iphlen;
  196         u_int8_t ecn_bits;
  197         struct sctp_tcb *stcb = NULL;
  198         int off = *offp;
  199 
  200         ip6 = mtod(m, struct ip6_hdr *);
  201 #ifndef PULLDOWN_TEST
  202         /* If PULLDOWN_TEST off, must be in a single mbuf. */
  203         IP6_EXTHDR_CHECK(m, off, (int)(sizeof(*sh) + sizeof(*ch)), IPPROTO_DONE);
  204         sh = (struct sctphdr *)((caddr_t)ip6 + off);
  205         ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(*sh));
  206 #else
  207         /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
  208         IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch));
  209         if (sh == NULL) {
  210                 sctp_pegs[SCTP_HDR_DROPS]++;
  211                 return IPPROTO_DONE;
  212         }
  213         ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
  214 #endif
  215 
  216         iphlen = off;
  217         offset = iphlen + sizeof(*sh) + sizeof(*ch);
  218 
  219 #if defined(NFAITH) && NFAITH > 0
  220 #if defined(__FreeBSD_cc_version) && __FreeBSD_cc_version <= 430000
  221 #if defined(NFAITH) && 0 < NFAITH
  222         if (faithprefix(&ip6h->ip6_dst)) {
  223                 /* XXX send icmp6 host/port unreach? */
  224                 goto bad;
  225         }
  226 #endif
  227 #else
  228 
  229 #ifdef __FreeBSD__
  230         if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
  231                 /* XXX send icmp6 host/port unreach? */
  232                 goto bad;
  233         }
  234 #else
  235         if (faithprefix(&ip6->ip6_dst))
  236                 goto bad;
  237 #endif
  238 #endif /* __FreeBSD_cc_version */
  239 
  240 #endif /* NFAITH defined and > 0 */
  241         sctp_pegs[SCTP_INPKTS]++;
  242 #ifdef SCTP_DEBUG
  243         if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
  244                 kprintf("V6 input gets a packet iphlen:%d pktlen:%d\n", iphlen, m->m_pkthdr.len);
  245         }
  246 #endif
  247         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
  248                 /* No multi-cast support in SCTP */
  249                 sctp_pegs[SCTP_IN_MCAST]++;
  250                 goto bad;
  251         }
  252         /* destination port of 0 is illegal, based on RFC2960. */
  253         if (sh->dest_port == 0)
  254                 goto bad;
  255         if ((sctp_no_csum_on_loopback == 0) ||
  256            (m->m_pkthdr.rcvif == NULL) ||
  257            (m->m_pkthdr.rcvif->if_type != IFT_LOOP)) {
  258                 /* we do NOT validate things from the loopback if the
  259                  * sysctl is set to 1.
  260                  */
  261                 check = sh->checksum;           /* save incoming checksum */
  262                 if ((check == 0) && (sctp_no_csum_on_loopback)) {
  263                         /* special hook for where we got a local address
  264                          * somehow routed across a non IFT_LOOP type interface
  265                          */
  266                         if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))
  267                                 goto sctp_skip_csum;
  268                 }
  269                 sh->checksum = 0;               /* prepare for calc */
  270                 calc_check = sctp_calculate_sum(m, &mlen, iphlen);
  271                 if (calc_check != check) {
  272 #ifdef SCTP_DEBUG
  273                         if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
  274                                 kprintf("Bad CSUM on SCTP packet calc_check:%x check:%x  m:%p mlen:%d iphlen:%d\n",
  275                                        calc_check, check, m,
  276                                        mlen, iphlen);
  277                         }
  278 #endif
  279                         stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
  280                                                          sh, ch, &in6p, &net);
  281                         /* in6p's ref-count increased && stcb locked */
  282                         if ((in6p) && (stcb)) {
  283                                 sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
  284                                 sctp_chunk_output(in6p, stcb, 2);
  285                         }  else if ((in6p != NULL) && (stcb == NULL)) {
  286                                 refcount_up = 1;
  287                         }
  288                         sctp_pegs[SCTP_BAD_CSUM]++;
  289                         goto bad;
  290                 }
  291                 sh->checksum = calc_check;
  292         } else {
  293 sctp_skip_csum:
  294                 mlen = m->m_pkthdr.len;
  295         }
  296         net = NULL;
  297         /*
  298          * Locate pcb and tcb for datagram
  299          * sctp_findassociation_addr() wants IP/SCTP/first chunk header...
  300          */
  301 #ifdef SCTP_DEBUG
  302         if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
  303                 kprintf("V6 Find the association\n");
  304         }
  305 #endif
  306         stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
  307             sh, ch, &in6p, &net);
  308         /* in6p's ref-count increased */
  309         if (in6p == NULL) {
  310                 struct sctp_init_chunk *init_chk, chunk_buf;
  311 
  312                 sctp_pegs[SCTP_NOPORTS]++;
  313                 if (ch->chunk_type == SCTP_INITIATION) {
  314                         /* we do a trick here to get the INIT tag,
  315                          * dig in and get the tag from the INIT and
  316                          * put it in the common header.
  317                          */
  318                         init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
  319                             iphlen + sizeof(*sh), sizeof(*init_chk),
  320                             (u_int8_t *)&chunk_buf);
  321                         sh->v_tag = init_chk->init.initiate_tag;
  322                 }
  323                 sctp_send_abort(m, iphlen, sh, 0, NULL);
  324                 goto bad;
  325         } else if (stcb == NULL) {
  326                 refcount_up = 1;
  327         }
  328         in6p_ip = (struct inpcb *)in6p;
  329 #ifdef IPSEC
  330         /*
  331          * Check AH/ESP integrity.
  332          */
  333 #ifdef __OpenBSD__
  334         {
  335                 struct inpcb *i_inp;
  336                 struct m_tag *mtag;
  337                 struct tdb_ident *tdbi;
  338                 struct tdb *tdb;
  339                 int error;
  340 
  341                 /* Find most recent IPsec tag */
  342                 i_inp = (struct inpcb *)in6p;
  343                 mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
  344                 crit_enter();
  345                 if (mtag != NULL) {
  346                         tdbi = (struct tdb_ident *)(mtag + 1);
  347                         tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
  348                 } else
  349                         tdb = NULL;
  350 
  351                 ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
  352                     tdb, i_inp);
  353                 if (error) {
  354                         crit_exit();
  355                         goto bad;
  356                 }
  357 
  358                 /* Latch SA */
  359                 if (i_inp->inp_tdb_in != tdb) {
  360                         if (tdb) {
  361                                 tdb_add_inp(tdb, i_inp, 1);
  362                                 if (i_inp->inp_ipo == NULL) {
  363                                         i_inp->inp_ipo = ipsec_add_policy(i_inp,
  364                                             af, IPSP_DIRECTION_OUT);
  365                                         if (i_inp->inp_ipo == NULL) {
  366                                                 crit_exit();
  367                                                 goto bad;
  368                                         }
  369                                 }
  370                                 if (i_inp->inp_ipo->ipo_dstid == NULL &&
  371                                     tdb->tdb_srcid != NULL) {
  372                                         i_inp->inp_ipo->ipo_dstid =
  373                                             tdb->tdb_srcid;
  374                                         tdb->tdb_srcid->ref_count++;
  375                                 }
  376                                 if (i_inp->inp_ipsec_remotecred == NULL &&
  377                                     tdb->tdb_remote_cred != NULL) {
  378                                         i_inp->inp_ipsec_remotecred =
  379                                             tdb->tdb_remote_cred;
  380                                         tdb->tdb_remote_cred->ref_count++;
  381                                 }
  382                                 if (i_inp->inp_ipsec_remoteauth == NULL &&
  383                                     tdb->tdb_remote_auth != NULL) {
  384                                         i_inp->inp_ipsec_remoteauth =
  385                                             tdb->tdb_remote_auth;
  386                                         tdb->tdb_remote_auth->ref_count++;
  387                                 }
  388                         } else { /* Just reset */
  389                                 TAILQ_REMOVE(&i_inp->inp_tdb_in->tdb_inp_in,
  390                                     i_inp, binp_tdb_in_next);
  391                                 i_inp->inp_tdb_in = NULL;
  392                         }
  393                 }
  394                 crit_exit();
  395         }
  396 #else
  397         if (ipsec6_in_reject_so(m, in6p->sctp_socket)) {
  398 /* XXX */
  399 #ifndef __APPLE__
  400                 /* FIX ME: need to find right stat for __APPLE__ */
  401                 ipsec6stat.in_polvio++;
  402 #endif
  403                 goto bad;
  404         }
  405 #endif
  406 #endif /*IPSEC*/
  407 
  408         /*
  409          * Construct sockaddr format source address.
  410          * Stuff source address and datagram in user buffer.
  411          */
  412         if ((in6p->ip_inp.inp.inp_flags & INP_CONTROLOPTS)
  413 #ifndef __OpenBSD__
  414             || (in6p->sctp_socket->so_options & SO_TIMESTAMP)
  415 #endif
  416             ) {
  417 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  418 #if (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version < 501113) || \
  419     defined(__APPLE__) || defined(__DragonFly__)
  420                 ip6_savecontrol(in6p_ip, &opts, ip6, m);
  421 #elif defined(__FreeBSD__) && (__FreeBSD_version >= 440000 || (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version >= 501113))
  422                 ip6_savecontrol(in6p_ip, m, &opts);
  423 #else
  424                 ip6_savecontrol(in6p_ip, m, &opts, NULL);
  425 #endif
  426 #else
  427                 ip6_savecontrol((struct in6pcb *)in6p_ip, m, &opts);
  428 #endif
  429         }
  430 
  431         /*
  432          * CONTROL chunk processing
  433          */
  434         length = ntohs(ip6->ip6_plen) + iphlen;
  435         offset -= sizeof(*ch);
  436         ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
  437         crit_enter();
  438         sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
  439             in6p, stcb, net, ecn_bits);
  440         /* inp's ref-count reduced && stcb unlocked */
  441         crit_exit();
  442         /* XXX this stuff below gets moved to appropriate parts later... */
  443         if (m)
  444                 m_freem(m);
  445         if (opts)
  446                 m_freem(opts);
  447 
  448         if ((in6p) && refcount_up){
  449                 /* reduce ref-count */
  450                 SCTP_INP_WLOCK(in6p);
  451                 SCTP_INP_DECR_REF(in6p);
  452                 SCTP_INP_WUNLOCK(in6p);
  453         }
  454 
  455         return IPPROTO_DONE;
  456 
  457 bad:
  458         if (stcb)
  459                 SCTP_TCB_UNLOCK(stcb);
  460 
  461         if ((in6p) && refcount_up){
  462                 /* reduce ref-count */
  463                 SCTP_INP_WLOCK(in6p);
  464                 SCTP_INP_DECR_REF(in6p);
  465                 SCTP_INP_WUNLOCK(in6p);
  466         }
  467         if (m)
  468                 m_freem(m);
  469         if (opts)
  470                 m_freem(opts);
  471         return IPPROTO_DONE;
  472 }
  473 
  474 
  475 static void
  476 sctp6_notify_mbuf(struct sctp_inpcb *inp,
  477                   struct icmp6_hdr *icmp6,
  478                   struct sctphdr *sh,
  479                   struct sctp_tcb *stcb,
  480                   struct sctp_nets *net)
  481 {
  482         unsigned int nxtsz;
  483 
  484         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
  485             (icmp6 == NULL) || (sh == NULL)) {
  486                 goto out;
  487         }
  488 
  489         /* First do we even look at it? */
  490         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
  491                 goto out;
  492 
  493         if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
  494                 /* not PACKET TO BIG */
  495                 goto out;
  496         }
  497         /*
  498          * ok we need to look closely. We could even get smarter and
  499          * look at anyone that we sent to in case we get a different
  500          * ICMP that tells us there is no way to reach a host, but for
  501          * this impl, all we care about is MTU discovery.
  502          */
  503         nxtsz = ntohl(icmp6->icmp6_mtu);
  504         /* Stop any PMTU timer */
  505         sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
  506 
  507         /* Adjust destination size limit */
  508         if (net->mtu > nxtsz) {
  509                 net->mtu = nxtsz;
  510         }
  511         /* now what about the ep? */
  512         if (stcb->asoc.smallest_mtu > nxtsz) {
  513                 struct sctp_tmit_chunk *chk;
  514                 struct sctp_stream_out *strm;
  515                 /* Adjust that too */
  516                 stcb->asoc.smallest_mtu = nxtsz;
  517                 /* now off to subtract IP_DF flag if needed */
  518 
  519                 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
  520                         if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
  521                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
  522                         }
  523                 }
  524                 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
  525                         if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
  526                                 /*
  527                                  * For this guy we also mark for immediate
  528                                  * resend since we sent to big of chunk
  529                                  */
  530                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
  531                                 if (chk->sent != SCTP_DATAGRAM_RESEND)
  532                                         stcb->asoc.sent_queue_retran_cnt++;
  533                                 chk->sent = SCTP_DATAGRAM_RESEND;
  534                                 chk->rec.data.doing_fast_retransmit = 0;
  535 
  536                                 chk->sent = SCTP_DATAGRAM_RESEND;
  537                                 /* Clear any time so NO RTT is being done */
  538                                 chk->sent_rcv_time.tv_sec = 0;
  539                                 chk->sent_rcv_time.tv_usec = 0;
  540                                 stcb->asoc.total_flight -= chk->send_size;
  541                                 net->flight_size -= chk->send_size;
  542                         }
  543                 }
  544                 TAILQ_FOREACH(strm, &stcb->asoc.out_wheel, next_spoke) {
  545                         TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) {
  546                                 if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
  547                                         chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
  548                                 }
  549                         }
  550                 }
  551         }
  552         sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
  553 out:
  554         if (inp) {
  555                 /* reduce inp's ref-count */
  556                 SCTP_INP_WLOCK(inp);
  557                 SCTP_INP_DECR_REF(inp);
  558                 SCTP_INP_WUNLOCK(inp);
  559         }
  560         if (stcb)
  561                 SCTP_TCB_UNLOCK(stcb);
  562 }
  563 
  564 
  565 void
  566 sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
  567 {
  568         struct sctphdr sh;
  569         struct ip6ctlparam *ip6cp = NULL;
  570         int cm;
  571 
  572         if (pktdst->sa_family != AF_INET6 ||
  573             pktdst->sa_len != sizeof(struct sockaddr_in6))
  574                 return;
  575 
  576         if ((unsigned)cmd >= PRC_NCMDS)
  577                 return;
  578         if (PRC_IS_REDIRECT(cmd)) {
  579                 d = NULL;
  580         } else if (inet6ctlerrmap[cmd] == 0) {
  581                 return;
  582         }
  583 
  584         /* if the parameter is from icmp6, decode it. */
  585         if (d != NULL) {
  586                 ip6cp = (struct ip6ctlparam *)d;
  587         } else {
  588                 ip6cp = NULL;
  589         }
  590 
  591         if (ip6cp) {
  592                 /*
  593                  * XXX: We assume that when IPV6 is non NULL,
  594                  * M and OFF are valid.
  595                  */
  596                 /* check if we can safely examine src and dst ports */
  597                 struct sctp_inpcb *inp;
  598                 struct sctp_tcb *stcb;
  599                 struct sctp_nets *net;
  600                 struct sockaddr_in6 final;
  601 
  602                 if (ip6cp->ip6c_m == NULL ||
  603                     (size_t)ip6cp->ip6c_m->m_pkthdr.len < (ip6cp->ip6c_off + sizeof(sh)))
  604                         return;
  605 
  606                 bzero(&sh, sizeof(sh));
  607                 bzero(&final, sizeof(final));
  608                 inp = NULL;
  609                 net = NULL;
  610                 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
  611                     (caddr_t)&sh);
  612                 ip6cp->ip6c_src->sin6_port = sh.src_port;
  613                 final.sin6_len = sizeof(final);
  614                 final.sin6_family = AF_INET6;
  615 #if defined(__FreeBSD__) && __FreeBSD_cc_version < 440000
  616                 final.sin6_addr = *ip6cp->ip6c_finaldst;
  617 #else
  618                 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
  619 #endif /* __FreeBSD_cc_version */
  620                 final.sin6_port = sh.dest_port;
  621                 crit_enter();
  622                 stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src,
  623                                                     (struct sockaddr *)&final,
  624                                                     &inp, &net, 1);
  625                 /* inp's ref-count increased && stcb locked */
  626                 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
  627                         if (cmd == PRC_MSGSIZE) {
  628                                 sctp6_notify_mbuf(inp,
  629                                                   ip6cp->ip6c_icmp6,
  630                                                   &sh,
  631                                                   stcb,
  632                                                   net);
  633                                 /* inp's ref-count reduced && stcb unlocked */
  634                         } else {
  635                                 if (cmd == PRC_HOSTDEAD) {
  636                                         cm = EHOSTUNREACH;
  637                                 } else {
  638                                         cm = inet6ctlerrmap[cmd];
  639                                 }
  640                                 sctp_notify(inp, cm, &sh,
  641                                             (struct sockaddr *)&final,
  642                                             stcb, net);
  643                                 /* inp's ref-count reduced && stcb unlocked */
  644                         }
  645                 } else {
  646                         if (PRC_IS_REDIRECT(cmd) && inp) {
  647 #ifdef __OpenBSD__
  648                                 in_rtchange((struct inpcb *)inp,
  649                                             inetctlerrmap[cmd]);
  650 #else
  651                                 in6_rtchange((struct in6pcb *)inp,
  652                                              inet6ctlerrmap[cmd]);
  653 #endif
  654                         }
  655                         if (inp) {
  656                                 /* reduce inp's ref-count */
  657                                 SCTP_INP_WLOCK(inp);
  658                                 SCTP_INP_DECR_REF(inp);
  659                                 SCTP_INP_WUNLOCK(inp);
  660                         }
  661                         if (stcb)
  662                                 SCTP_TCB_UNLOCK(stcb);
  663                 }
  664                 crit_exit();
  665         }
  666 }
  667 
  668 /*
  669  * this routine can probably be collasped into the one in sctp_userreq.c
  670  * since they do the same thing and now we lookup with a sockaddr
  671  */
  672 #ifdef __FreeBSD__
  673 static int
  674 sctp6_getcred(SYSCTL_HANDLER_ARGS)
  675 {
  676         struct sockaddr_in6 addrs[2];
  677         struct sctp_inpcb *inp;
  678         struct sctp_nets *net;
  679         struct sctp_tcb *stcb;
  680         int error;
  681 
  682 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  683         error = suser(req->td);
  684 #else
  685         error = suser(req->p);
  686 #endif
  687         if (error)
  688                 return (error);
  689 
  690         if (req->newlen != sizeof(addrs))
  691                 return (EINVAL);
  692         if (req->oldlen != sizeof(struct ucred))
  693                 return (EINVAL);
  694         error = SYSCTL_IN(req, addrs, sizeof(addrs));
  695         if (error)
  696                 return (error);
  697         crit_enter();
  698 
  699         stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
  700                                            sin6tosa(&addrs[1]),
  701                                            &inp, &net, 1);
  702         if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
  703                 error = ENOENT;
  704                 if (inp) {
  705                         SCTP_INP_WLOCK(inp);
  706                         SCTP_INP_DECR_REF(inp);
  707                         SCTP_INP_WUNLOCK(inp);
  708                 }
  709                 goto out;
  710         }
  711         error = SYSCTL_OUT(req, inp->sctp_socket->so_cred,
  712                            sizeof(struct ucred));
  713 
  714         SCTP_TCB_UNLOCK (stcb);
  715 out:
  716         crit_exit();
  717         return (error);
  718 }
  719 
  720 SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
  721             0, 0,
  722             sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
  723 
  724 #endif
  725 
  726 /*
  727  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
  728  *       will sofree() it when we return.
  729  */
  730 static void
  731 sctp6_abort(netmsg_t msg)
  732 {
  733         struct socket *so = msg->abort.base.nm_so;
  734         struct sctp_inpcb *inp;
  735         int error;
  736 
  737         inp = (struct sctp_inpcb *)so->so_pcb;
  738         if (inp) {
  739                 soisdisconnected(so);
  740                 sctp_inpcb_free(inp, 1);
  741                 error = 0;
  742         } else {
  743                 error = EINVAL;
  744         }
  745         lwkt_replymsg(&msg->lmsg, error);
  746 }
  747 
  748 static void
  749 sctp6_attach(netmsg_t msg)
  750 {
  751         struct socket *so = msg->attach.base.nm_so;
  752         struct in6pcb *inp6;
  753         int error;
  754         struct sctp_inpcb *inp;
  755 
  756         inp = (struct sctp_inpcb *)so->so_pcb;
  757         if (inp != NULL) {
  758                 error = EINVAL;
  759                 goto out;
  760         }
  761 
  762         if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
  763                 error = soreserve(so, sctp_sendspace, sctp_recvspace, NULL);
  764                 if (error)
  765                         goto out;
  766         }
  767         crit_enter();
  768         error = sctp_inpcb_alloc(so);
  769         crit_exit();
  770         if (error)
  771                 goto out;
  772         inp = (struct sctp_inpcb *)so->so_pcb;
  773         inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;     /* I'm v6! */
  774         inp6 = (struct in6pcb *)inp;
  775 
  776 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  777         inp6->inp_vflag |= INP_IPV6;
  778 #else
  779 #if defined(__OpenBSD__)
  780         inp->ip_inp.inp.inp_flags |= INP_IPV6;
  781 #else
  782         inp->inp_vflag |=  INP_IPV6;
  783 #endif
  784 #endif
  785 #if defined(__NetBSD__)
  786         if (ip6_v6only) {
  787                 inp6->in6p_flags |= IN6P_IPV6_V6ONLY;
  788         }
  789         so->so_send = sctp_sosend;
  790 #endif
  791         inp6->in6p_hops = -1;           /* use kernel default */
  792         inp6->in6p_cksum = -1;  /* just to be sure */
  793 #ifdef INET
  794         /*
  795          * XXX: ugly!!
  796          * IPv4 TTL initialization is necessary for an IPv6 socket as well,
  797          * because the socket may be bound to an IPv6 wildcard address,
  798          * which may match an IPv4-mapped IPv6 address.
  799          */
  800 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  801         inp6->inp_ip_ttl = ip_defttl;
  802 #else
  803         inp->inp_ip_ttl = ip_defttl;
  804 #endif
  805 #endif
  806         /*
  807          * Hmm what about the IPSEC stuff that is missing here but
  808          * in sctp_attach()?
  809          */
  810         error = 0;
  811 out:
  812         lwkt_replymsg(&msg->lmsg, error);
  813 }
  814 
  815 static void
  816 sctp6_bind(netmsg_t msg)
  817 {
  818         int error;
  819 
  820         error = sctp6_bind_oncpu(msg->bind.base.nm_so,
  821                                  msg->bind.nm_nam,
  822                                  msg->bind.nm_td);
  823         lwkt_replymsg(&msg->lmsg, error);
  824 }
  825 
  826 static int
  827 sctp6_bind_oncpu(struct socket *so, struct sockaddr *addr, thread_t td)
  828 {
  829         struct sctp_inpcb *inp;
  830         struct in6pcb *inp6;
  831         int error;
  832 
  833         inp = (struct sctp_inpcb *)so->so_pcb;
  834         if (inp == NULL) {
  835                 error = EINVAL;
  836                 goto out;
  837         }
  838 
  839         inp6 = (struct in6pcb *)inp;
  840 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  841         inp6->inp_vflag &= ~INP_IPV4;
  842         inp6->inp_vflag |= INP_IPV6;
  843 #else
  844 #if defined(__OpenBSD__)
  845         inp->ip_inp.inp.inp_flags &= ~INP_IPV4;
  846         inp->ip_inp.inp.inp_flags |= INP_IPV6;
  847 #else
  848         inp->inp_vflag &= ~INP_IPV4;
  849         inp->inp_vflag |= INP_IPV6;
  850 #endif
  851 #endif
  852         if (addr != NULL &&
  853 #if defined(__OpenBSD__)
  854              (0) /* we always do dual bind */
  855 #elif defined (__NetBSD__)
  856              !(inp6->in6p_flags & IN6P_IPV6_V6ONLY)
  857 #else
  858              !(inp6->inp_flags & IN6P_IPV6_V6ONLY)
  859 #endif
  860              ) {
  861                 if (addr->sa_family == AF_INET) {
  862                         /* binding v4 addr to v6 socket, so reset flags */
  863 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  864                         inp6->inp_vflag |= INP_IPV4;
  865                         inp6->inp_vflag &= ~INP_IPV6;
  866 #else
  867 #if defined(__OpenBSD__)
  868                         inp->ip_inp.inp.inp_flags |= INP_IPV4;
  869                         inp->ip_inp.inp.inp_flags &= ~INP_IPV6;
  870 #else
  871                         inp->inp_vflag |= INP_IPV4;
  872                         inp->inp_vflag &= ~INP_IPV6;
  873 #endif
  874 #endif
  875                 } else {
  876                         struct sockaddr_in6 *sin6_p;
  877                         sin6_p = (struct sockaddr_in6 *)addr;
  878 
  879                         if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
  880 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  881                           inp6->inp_vflag |= INP_IPV4;
  882 #else
  883 #if defined(__OpenBSD__)
  884                           inp->ip_inp.inp.inp_flags |= INP_IPV4;
  885 #else
  886                           inp->inp_vflag |= INP_IPV4;
  887 #endif
  888 #endif
  889                         }
  890                         else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  891                                 struct sockaddr_in sin;
  892                                 in6_sin6_2_sin(&sin, sin6_p);
  893 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
  894                                 inp6->inp_vflag |= INP_IPV4;
  895                                 inp6->inp_vflag &= ~INP_IPV6;
  896 #else
  897 #if defined(__OpenBSD__)
  898                                 inp->ip_inp.inp.inp_flags |= INP_IPV4;
  899                                 inp->ip_inp.inp.inp_flags &= ~INP_IPV6;
  900 
  901 #else
  902                                 inp->inp_vflag |= INP_IPV4;
  903                                 inp->inp_vflag &= ~INP_IPV6;
  904 #endif
  905 #endif
  906                                 crit_enter();
  907                                 error = sctp_inpcb_bind(so,
  908                                                 (struct sockaddr *)&sin,
  909                                                 td);
  910                                 crit_exit();
  911                                 goto out;
  912                         }
  913                 }
  914         } else if (addr != NULL) {
  915                 /* IPV6_V6ONLY socket */
  916                 if (addr->sa_family == AF_INET) {
  917                         /* can't bind v4 addr to v6 only socket! */
  918                         error = EINVAL;
  919                         goto out;
  920                 } else {
  921                         struct sockaddr_in6 *sin6_p;
  922                         sin6_p = (struct sockaddr_in6 *)addr;
  923 
  924                         if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  925                                 /* can't bind v4-mapped addrs either! */
  926                                 /* NOTE: we don't support SIIT */
  927                                 error = EINVAL;
  928                                 goto out;
  929                         }
  930                 }
  931         }
  932         crit_enter();
  933         error = sctp_inpcb_bind(so, addr, td);
  934         crit_exit();
  935 out:
  936         return error;
  937 }
  938 
  939 /*This could be made common with sctp_detach() since they are identical */
  940 static void
  941 sctp6_detach(netmsg_t msg)
  942 {
  943         struct socket *so = msg->detach.base.nm_so;
  944         struct sctp_inpcb *inp;
  945         int error;
  946 
  947         inp = (struct sctp_inpcb *)so->so_pcb;
  948         if (inp == NULL) {
  949                 error = EINVAL;
  950                 goto out;
  951         }
  952         crit_enter();
  953         if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
  954             (so->so_rcv.ssb_cc > 0))
  955                 sctp_inpcb_free(inp, 1);
  956         else
  957                 sctp_inpcb_free(inp, 0);
  958         crit_exit();
  959         error = 0;
  960 out:
  961         lwkt_replymsg(&msg->lmsg, error);
  962 }
  963 
  964 static void
  965 sctp6_disconnect(netmsg_t msg)
  966 {
  967         struct socket *so = msg->disconnect.base.nm_so;
  968         struct sctp_inpcb *inp;
  969         int error;
  970 
  971         crit_enter();
  972         inp = (struct sctp_inpcb *)so->so_pcb;
  973         if (inp == NULL) {
  974                 crit_exit();
  975                 error = ENOTCONN;
  976                 goto out;
  977         }
  978         if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
  979                 if (LIST_EMPTY(&inp->sctp_asoc_list)) {
  980                         /* No connection */
  981                         crit_exit();
  982                         error = ENOTCONN;
  983                 } else {
  984                         int some_on_streamwheel = 0;
  985                         struct sctp_association *asoc;
  986                         struct sctp_tcb *stcb;
  987 
  988                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
  989                         if (stcb == NULL) {
  990                                 crit_exit();
  991                                 error = EINVAL;
  992                                 goto out;
  993                         }
  994                         asoc = &stcb->asoc;
  995                         if (!TAILQ_EMPTY(&asoc->out_wheel)) {
  996                                 /* Check to see if some data queued */
  997                                 struct sctp_stream_out *outs;
  998                                 TAILQ_FOREACH(outs, &asoc->out_wheel,
  999                                               next_spoke) {
 1000                                         if (!TAILQ_EMPTY(&outs->outqueue)) {
 1001                                                 some_on_streamwheel = 1;
 1002                                                 break;
 1003                                         }
 1004                                 }
 1005                         }
 1006 
 1007                         if (TAILQ_EMPTY(&asoc->send_queue) &&
 1008                             TAILQ_EMPTY(&asoc->sent_queue) &&
 1009                             (some_on_streamwheel == 0)) {
 1010                                 /* nothing queued to send, so I'm done... */
 1011                                 if ((SCTP_GET_STATE(asoc) !=
 1012                                      SCTP_STATE_SHUTDOWN_SENT) &&
 1013                                     (SCTP_GET_STATE(asoc) !=
 1014                                      SCTP_STATE_SHUTDOWN_ACK_SENT)) {
 1015                                         /* only send SHUTDOWN the first time */
 1016 #ifdef SCTP_DEBUG
 1017                                         if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
 1018                                                 kprintf("%s:%d sends a shutdown\n",
 1019                                                        __FILE__,
 1020                                                        __LINE__
 1021                                                         );
 1022                                         }
 1023 #endif
 1024                                         sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
 1025                                         sctp_chunk_output(stcb->sctp_ep, stcb, 1);
 1026                                         asoc->state = SCTP_STATE_SHUTDOWN_SENT;
 1027                                         sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
 1028                                                          stcb->sctp_ep, stcb,
 1029                                                          asoc->primary_destination);
 1030                                         sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
 1031                                                          stcb->sctp_ep, stcb,
 1032                                                          asoc->primary_destination);
 1033                                 }
 1034                         } else {
 1035                                 /*
 1036                                  * we still got (or just got) data to send,
 1037                                  * so set SHUTDOWN_PENDING
 1038                                  */
 1039                                 /*
 1040                                  * XXX sockets draft says that MSG_EOF should
 1041                                  * be sent with no data.  currently, we will
 1042                                  * allow user data to be sent first and move
 1043                                  * to SHUTDOWN-PENDING
 1044                                  */
 1045                                 asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
 1046                         }
 1047                         crit_exit();
 1048                         error = 0;
 1049                 }
 1050         } else {
 1051                 /* UDP model does not support this */
 1052                 crit_exit();
 1053                 error = EOPNOTSUPP;
 1054         }
 1055 out:
 1056         lwkt_replymsg(&msg->lmsg, error);
 1057 }
 1058 
 1059 static
 1060 void
 1061 sctp6_send(netmsg_t msg)
 1062 {
 1063         struct socket *so = msg->send.base.nm_so;
 1064         struct mbuf *m = msg->send.nm_m;
 1065         struct mbuf *control = msg->send.nm_control;
 1066         struct sockaddr *addr = msg->send.nm_addr;
 1067         struct sctp_inpcb *inp;
 1068         struct in6pcb *inp6;
 1069         int flags = msg->send.nm_flags;
 1070 #ifdef INET
 1071         struct sockaddr_in6 *sin6;
 1072 #endif /* INET */
 1073         int error;
 1074         /* No SPL needed since sctp_output does this */
 1075 
 1076         inp = (struct sctp_inpcb *)so->so_pcb;
 1077         if (inp == NULL) {
 1078                 if (control) {
 1079                         m_freem(control);
 1080                         control = NULL;
 1081                 }
 1082                 m_freem(m);
 1083                 error = EINVAL;
 1084                 goto out;
 1085         }
 1086         inp6 = (struct in6pcb *)inp;
 1087         /* For the TCP model we may get a NULL addr, if we
 1088          * are a connected socket thats ok.
 1089          */
 1090         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
 1091             (addr == NULL)) {
 1092                 goto connected_type;
 1093         }
 1094         if (addr == NULL) {
 1095                 m_freem(m);
 1096                 if (control) {
 1097                         m_freem(control);
 1098                         control = NULL;
 1099                 }
 1100                 error = EDESTADDRREQ;
 1101                 goto out;
 1102         }
 1103 
 1104 #ifdef INET
 1105         sin6 = (struct sockaddr_in6 *)addr;
 1106         if (
 1107 
 1108 #if defined(__OpenBSD__)
 1109              (0) /* we always do dual bind */
 1110 #elif defined (__NetBSD__)
 1111              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
 1112 #else
 1113              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
 1114 #endif
 1115             ) {
 1116                 /*
 1117                  * if IPV6_V6ONLY flag, we discard datagrams
 1118                  * destined to a v4 addr or v4-mapped addr
 1119                  */
 1120                 if (addr->sa_family == AF_INET) {
 1121                         error = EINVAL;
 1122                         goto out;
 1123                 }
 1124                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
 1125                         error = EINVAL;
 1126                         goto out;
 1127                 }
 1128         }
 1129 
 1130         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
 1131                 if (!ip6_v6only) {
 1132                         struct sockaddr_in *sin;
 1133 
 1134                         sin = kmalloc(sizeof(*sin), M_LWKTMSG, M_INTWAIT);
 1135                         /* convert v4-mapped into v4 addr and send */
 1136                         in6_sin6_2_sin(sin, sin6);
 1137                         msg->send.nm_addr = (struct sockaddr *)sin;
 1138                         msg->send.nm_flags |= PRUS_NAMALLOC;
 1139                         sctp_send(msg);
 1140                         /* msg invalid now */
 1141                         return;
 1142                 } else {
 1143                         /* mapped addresses aren't enabled */
 1144                         error = EINVAL;
 1145                         goto out;
 1146                 }
 1147         }
 1148 #endif /* INET */
 1149 connected_type:
 1150         /* now what about control */
 1151         if (control) {
 1152                 if (inp->control) {
 1153                         kprintf("huh? control set?\n");
 1154                         m_freem(inp->control);
 1155                         inp->control = NULL;
 1156                 }
 1157                 inp->control = control;
 1158         }
 1159         /* add it in possibly */
 1160         if ((inp->pkt) &&
 1161             (inp->pkt->m_flags & M_PKTHDR)) {
 1162                 struct mbuf *x;
 1163                 int c_len;
 1164 
 1165                 c_len = 0;
 1166                 /* How big is it */
 1167                 for (x=m;x;x = x->m_next) {
 1168                         c_len += x->m_len;
 1169                 }
 1170                 inp->pkt->m_pkthdr.len += c_len;
 1171         }
 1172         /* Place the data */
 1173         if (inp->pkt) {
 1174                 inp->pkt_last->m_next = m;
 1175                 inp->pkt_last = m;
 1176         } else {
 1177                 inp->pkt_last = inp->pkt = m;
 1178         }
 1179         if (
 1180 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1181             /* FreeBSD and MacOSX uses a flag passed */
 1182             (!(flags & PRUS_MORETOCOME))
 1183 #elif defined(__NetBSD__)
 1184             /* NetBSD uses the so_state field */
 1185             (!(so->so_state & SS_MORETOCOME))
 1186 #else
 1187             1   /* Open BSD does not have any "more to come" indication */
 1188 #endif
 1189             ) {
 1190                 /*
 1191                  * note with the current version this code will only be
 1192                  * used by OpenBSD, NetBSD and FreeBSD have methods for
 1193                  * re-defining sosend() to use sctp_sosend().  One can
 1194                  * optionaly switch back to this code (by changing back
 1195                  * the defininitions but this is not advisable.
 1196                  */
 1197                 error = sctp_output(inp, inp->pkt, addr,
 1198                                     inp->control, msg->send.nm_td, flags);
 1199                 inp->pkt = NULL;
 1200                 inp->control = NULL;
 1201         } else {
 1202                 error = 0;
 1203         }
 1204 out:
 1205         lwkt_replymsg(&msg->lmsg, error);
 1206 }
 1207 
 1208 static void
 1209 sctp6_connect(netmsg_t msg)
 1210 {
 1211         struct socket *so = msg->connect.base.nm_so;
 1212         struct sockaddr *addr = msg->connect.nm_nam;
 1213         struct sctp_inpcb *inp;
 1214         struct in6pcb *inp6;
 1215         struct sctp_tcb *stcb;
 1216 #ifdef INET
 1217         struct sockaddr_in6 *sin6;
 1218         struct sockaddr_storage ss;
 1219 #endif /* INET */
 1220         int error = 0;
 1221 
 1222         crit_enter();
 1223         inp6 = (struct in6pcb *)so->so_pcb;
 1224         inp = (struct sctp_inpcb *)so->so_pcb;
 1225         if (inp == NULL) {
 1226                 crit_exit();
 1227                 error = ECONNRESET;     /* I made the same as TCP since
 1228                                          * we are not setup? */
 1229                 goto out;
 1230         }
 1231         SCTP_ASOC_CREATE_LOCK(inp);
 1232         SCTP_INP_RLOCK(inp);
 1233         if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
 1234             SCTP_PCB_FLAGS_UNBOUND) {
 1235                 /* Bind a ephemeral port */
 1236                 SCTP_INP_RUNLOCK(inp);
 1237                 error = sctp6_bind_oncpu(so, NULL, msg->connect.nm_td);
 1238                 if (error) {
 1239                         crit_exit();
 1240                         SCTP_ASOC_CREATE_UNLOCK(inp);
 1241                         goto out;
 1242                 }
 1243                 SCTP_INP_RLOCK(inp);
 1244         }
 1245 
 1246         if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
 1247             (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
 1248                 /* We are already connected AND the TCP model */
 1249                 crit_exit();
 1250                 SCTP_INP_RUNLOCK(inp);
 1251                 SCTP_ASOC_CREATE_UNLOCK(inp);
 1252                 error = EADDRINUSE;
 1253                 goto out;
 1254         }
 1255 
 1256 #ifdef INET
 1257         sin6 = (struct sockaddr_in6 *)addr;
 1258         if (
 1259 #if defined(__OpenBSD__)
 1260              (0) /* we always do dual bind */
 1261 #elif defined (__NetBSD__)
 1262              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
 1263 #else
 1264              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
 1265 #endif
 1266             ) {
 1267                 /*
 1268                  * if IPV6_V6ONLY flag, ignore connections
 1269                  * destined to a v4 addr or v4-mapped addr
 1270                  */
 1271                 if (addr->sa_family == AF_INET) {
 1272                         crit_exit();
 1273                         SCTP_INP_RUNLOCK(inp);
 1274                         SCTP_ASOC_CREATE_UNLOCK(inp);
 1275                         error = EINVAL;
 1276                         goto out;
 1277                 }
 1278                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
 1279                         crit_exit();
 1280                         SCTP_INP_RUNLOCK(inp);
 1281                         SCTP_ASOC_CREATE_UNLOCK(inp);
 1282                         error = EINVAL;
 1283                         goto out;
 1284                 }
 1285         }
 1286 
 1287         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
 1288                 if (!ip6_v6only) {
 1289                         /* convert v4-mapped into v4 addr */
 1290                         in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
 1291                         addr = (struct sockaddr *)&ss;
 1292                 } else {
 1293                         /* mapped addresses aren't enabled */
 1294                         crit_exit();
 1295                         SCTP_INP_RUNLOCK(inp);
 1296                         SCTP_ASOC_CREATE_UNLOCK(inp);
 1297                         error = EINVAL;
 1298                         goto out;
 1299                 }
 1300         } else
 1301 #endif /* INET */
 1302                 addr = addr;    /* for true v6 address case */
 1303 
 1304         /* Now do we connect? */
 1305         if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
 1306                 stcb = LIST_FIRST(&inp->sctp_asoc_list);
 1307                 if (stcb)
 1308                         SCTP_TCB_UNLOCK (stcb);
 1309                 SCTP_INP_RUNLOCK(inp);
 1310         }else {
 1311                 SCTP_INP_RUNLOCK(inp);
 1312                 SCTP_INP_WLOCK(inp);
 1313                 SCTP_INP_INCR_REF(inp);
 1314                 SCTP_INP_WUNLOCK(inp);
 1315                 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
 1316                 if (stcb == NULL) {
 1317                         SCTP_INP_WLOCK(inp);
 1318                         SCTP_INP_DECR_REF(inp);
 1319                         SCTP_INP_WUNLOCK(inp);
 1320                 }
 1321         }
 1322 
 1323         if (stcb != NULL) {
 1324                 /* Already have or am bring up an association */
 1325                 SCTP_ASOC_CREATE_UNLOCK(inp);
 1326                 SCTP_TCB_UNLOCK (stcb);
 1327                 crit_exit();
 1328                 error = EALREADY;
 1329                 goto out;
 1330         }
 1331         /* We are GOOD to go */
 1332         stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0);
 1333         SCTP_ASOC_CREATE_UNLOCK(inp);
 1334         if (stcb == NULL) {
 1335                 /* Gak! no memory */
 1336                 crit_exit();
 1337                 goto out;
 1338         }
 1339         if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
 1340                 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
 1341                 /* Set the connected flag so we can queue data */
 1342                 soisconnecting(so);
 1343         }
 1344         stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
 1345         SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
 1346         sctp_send_initiate(inp, stcb);
 1347         SCTP_TCB_UNLOCK (stcb);
 1348         crit_exit();
 1349 out:
 1350         lwkt_replymsg(&msg->lmsg, error);
 1351 }
 1352 
 1353 static int
 1354 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1355 sctp6_getaddr(struct socket *so, struct sockaddr **addr)
 1356 {
 1357         struct sockaddr_in6 *sin6;
 1358 #else
 1359 sctp6_getaddr(struct socket *so, struct mbuf *nam)
 1360 {
 1361         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
 1362 #endif
 1363         struct sctp_inpcb *inp;
 1364         /*
 1365          * Do the malloc first in case it blocks.
 1366          */
 1367 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1368         sin6 = kmalloc(sizeof *sin6, M_SONAME, M_WAITOK | M_ZERO);
 1369 #else
 1370         nam->m_len = sizeof(*sin6);
 1371 #endif
 1372         bzero(sin6, sizeof(*sin6));
 1373         sin6->sin6_family = AF_INET6;
 1374         sin6->sin6_len = sizeof(*sin6);
 1375 
 1376         inp = (struct sctp_inpcb *)so->so_pcb;
 1377         if (!inp) {
 1378 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1379                 kfree(sin6, M_SONAME);
 1380 #endif
 1381                 return ECONNRESET;
 1382         }
 1383 
 1384         sin6->sin6_port = inp->sctp_lport;
 1385         if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
 1386                 /* For the bound all case you get back 0 */
 1387                 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
 1388                         struct sctp_tcb *stcb;
 1389                         struct sockaddr_in6 *sin_a6;
 1390                         struct sctp_nets *net;
 1391                         int fnd;
 1392 
 1393                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
 1394                         if (stcb == NULL) {
 1395                                 goto notConn6;
 1396                         }
 1397                         fnd = 0;
 1398                         sin_a6 = NULL;
 1399                         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
 1400                                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
 1401                                 if (sin_a6->sin6_family == AF_INET6) {
 1402                                         fnd = 1;
 1403                                         break;
 1404                                 }
 1405                         }
 1406                         if ((!fnd) || (sin_a6 == NULL)) {
 1407                                 /* punt */
 1408                                 goto notConn6;
 1409                         }
 1410                         sin6->sin6_addr = sctp_ipv6_source_address_selection(
 1411                             inp, stcb, (struct route *)&net->ro, net, 0);
 1412 
 1413                 } else {
 1414                         /* For the bound all case you get back 0 */
 1415                 notConn6:
 1416                         memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
 1417                 }
 1418         } else {
 1419                 /* Take the first IPv6 address in the list */
 1420                 struct sctp_laddr *laddr;
 1421                 int fnd = 0;
 1422                 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
 1423                         if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
 1424                                 struct sockaddr_in6 *sin_a;
 1425                                 sin_a = (struct sockaddr_in6 *)laddr->ifa->ifa_addr;
 1426                                 sin6->sin6_addr = sin_a->sin6_addr;
 1427                                 fnd = 1;
 1428                                 break;
 1429                         }
 1430                 }
 1431                 if (!fnd) {
 1432 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1433                         kfree(sin6, M_SONAME);
 1434 #endif
 1435                         return ENOENT;
 1436                 }
 1437         }
 1438         /* Scoping things for v6 */
 1439         if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
 1440                 /* skip ifp check below */
 1441                 in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
 1442         else
 1443                 sin6->sin6_scope_id = 0;        /*XXX*/
 1444 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1445         (*addr) = (struct sockaddr *)sin6;
 1446 #endif
 1447         return (0);
 1448 }
 1449 
 1450 static int
 1451 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1452 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
 1453 {
 1454         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
 1455 #else
 1456 sctp6_peeraddr(struct socket *so, struct mbuf *nam)
 1457 {
 1458         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
 1459 #endif
 1460         int fnd;
 1461         struct sockaddr_in6 *sin_a6;
 1462         struct sctp_inpcb *inp;
 1463         struct sctp_tcb *stcb;
 1464         struct sctp_nets *net;
 1465         /*
 1466          * Do the malloc first in case it blocks.
 1467          */
 1468         inp = (struct sctp_inpcb *)so->so_pcb;
 1469         if (!(inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
 1470                 /* UDP type and listeners will drop out here */
 1471                 return (ENOTCONN);
 1472         }
 1473 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1474         sin6 = kmalloc(sizeof *sin6, M_SONAME, M_WAITOK | M_ZERO);
 1475 #else
 1476         nam->m_len = sizeof(*sin6);
 1477 #endif
 1478         bzero(sin6, sizeof(*sin6));
 1479         sin6->sin6_family = AF_INET6;
 1480         sin6->sin6_len = sizeof(*sin6);
 1481 
 1482         /* We must recapture incase we blocked */
 1483         inp = (struct sctp_inpcb *)so->so_pcb;
 1484         if (!inp) {
 1485 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1486                 kfree(sin6, M_SONAME);
 1487 #endif
 1488                 return ECONNRESET;
 1489         }
 1490         stcb = LIST_FIRST(&inp->sctp_asoc_list);
 1491         if (stcb == NULL) {
 1492 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1493                 kfree(sin6, M_SONAME);
 1494 #endif
 1495                 return ECONNRESET;
 1496         }
 1497         fnd = 0;
 1498         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
 1499                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
 1500                 if (sin_a6->sin6_family == AF_INET6) {
 1501                         fnd = 1;
 1502                         sin6->sin6_port = stcb->rport;
 1503                         sin6->sin6_addr = sin_a6->sin6_addr;
 1504                         break;
 1505                 }
 1506         }
 1507         if (!fnd) {
 1508                 /* No IPv4 address */
 1509 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1510                 kfree(sin6, M_SONAME);
 1511 #endif
 1512                 return ENOENT;
 1513         }
 1514         in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
 1515 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1516         *addr = (struct sockaddr *)sin6;
 1517 #endif
 1518         return (0);
 1519 }
 1520 
 1521 static void
 1522 sctp6_in6getaddr(netmsg_t msg)
 1523 {
 1524         struct socket *so = msg->sockaddr.base.nm_so;
 1525         struct sockaddr **nam = msg->sockaddr.nm_nam;
 1526         struct sockaddr *addr;
 1527         struct in6pcb *inp6 = sotoin6pcb(so);
 1528         int error;
 1529 
 1530         if (inp6 == NULL) {
 1531                 error = EINVAL;
 1532                 goto out;
 1533         }
 1534 
 1535         crit_enter();
 1536         /* allow v6 addresses precedence */
 1537         error = sctp6_getaddr(so, nam);
 1538         if (error) {
 1539                 /* try v4 next if v6 failed */
 1540                 error = sctp_ingetaddr_oncpu(so, nam);
 1541                 if (error) {
 1542                         crit_exit();
 1543                         goto out;
 1544                 }
 1545 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1546                 addr = *nam;
 1547 #endif
 1548                 /* if I'm V6ONLY, convert it to v4-mapped */
 1549                 if (
 1550 #if defined(__OpenBSD__)
 1551              (0) /* we always do dual bind */
 1552 #elif defined (__NetBSD__)
 1553              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
 1554 #else
 1555              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
 1556 #endif
 1557                     ) {
 1558                         struct sockaddr_in6 sin6;
 1559                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
 1560                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
 1561 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
 1562                         nam->m_len = sizeof(sin6);
 1563 #endif
 1564 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
 1565                 } else {
 1566                         nam->m_len = sizeof(struct sockaddr_in);
 1567 #endif
 1568                 }
 1569 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
 1570         } else {
 1571                 nam->m_len = sizeof(struct sockaddr_in6);
 1572 #endif
 1573         }
 1574         crit_exit();
 1575 out:
 1576         lwkt_replymsg(&msg->lmsg, error);
 1577 }
 1578 
 1579 static void
 1580 sctp6_getpeeraddr(netmsg_t msg)
 1581 {
 1582         struct socket *so = msg->peeraddr.base.nm_so;
 1583         struct sockaddr **nam = msg->peeraddr.nm_nam;
 1584         struct sockaddr *addr = *nam;
 1585         struct in6pcb *inp6 = sotoin6pcb(so);
 1586         int error;
 1587 
 1588         if (inp6 == NULL) {
 1589                 error = EINVAL;
 1590                 goto out;
 1591         }
 1592 
 1593         crit_enter();
 1594         /* allow v6 addresses precedence */
 1595         error = sctp6_peeraddr(so, nam);
 1596         if (error) {
 1597                 /* try v4 next if v6 failed */
 1598                 error = sctp_peeraddr_oncpu(so, nam);
 1599                 if (error) {
 1600                         crit_exit();
 1601                         goto out;
 1602                 }
 1603                 /* if I'm V6ONLY, convert it to v4-mapped */
 1604                 if (
 1605 #if defined(__OpenBSD__)
 1606              (0) /* we always do dual bind */
 1607 #elif defined (__NetBSD__)
 1608              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
 1609 #else
 1610              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
 1611 #endif
 1612                     ) {
 1613                         struct sockaddr_in6 sin6;
 1614                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
 1615                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
 1616 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
 1617                         nam->m_len = sizeof(sin6);
 1618 #endif
 1619 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
 1620                 } else {
 1621                         nam->m_len = sizeof(struct sockaddr_in);
 1622 #endif
 1623                 }
 1624 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
 1625         } else {
 1626                 nam->m_len = sizeof(struct sockaddr_in6);
 1627 #endif
 1628         }
 1629         crit_exit();
 1630 out:
 1631         lwkt_replymsg(&msg->lmsg, error);
 1632 }
 1633 
 1634 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
 1635 struct pr_usrreqs sctp6_usrreqs = {
 1636         .pru_abort = sctp6_abort,
 1637         .pru_accept = sctp_accept,
 1638         .pru_attach = sctp6_attach,
 1639         .pru_bind = sctp6_bind,
 1640         .pru_connect = sctp6_connect,
 1641         .pru_connect2 = pr_generic_notsupp,
 1642         .pru_control = in6_control_dispatch,
 1643         .pru_detach = sctp6_detach,
 1644         .pru_disconnect = sctp6_disconnect,
 1645         .pru_listen = sctp_listen,
 1646         .pru_peeraddr = sctp6_getpeeraddr,
 1647         .pru_rcvd = sctp_usr_recvd,
 1648         .pru_rcvoob = pr_generic_notsupp,
 1649         .pru_send = sctp6_send,
 1650         .pru_sense = pru_sense_null,
 1651         .pru_shutdown = sctp_shutdown,
 1652         .pru_sockaddr = sctp6_in6getaddr,
 1653         .pru_sosend = sctp_sosend,
 1654         .pru_soreceive = soreceive
 1655 };
 1656 
 1657 #else
 1658 
 1659 #error x
 1660 
 1661 int
 1662 sctp6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
 1663              struct mbuf *control, struct proc *p)
 1664 {
 1665         int s;
 1666         int error = 0;
 1667         int family;
 1668 
 1669 #if defined(__OpenBSD__)
 1670         p = curproc;
 1671 #endif
 1672         s = splsoftnet();
 1673         family = so->so_proto->pr_domain->dom_family;
 1674 
 1675         if (req == PRU_CONTROL) {
 1676                 switch (family) {
 1677                 case PF_INET:
 1678                         error = in_control(so, (long)m, (caddr_t)nam,
 1679                             (struct ifnet *)control
 1680 #if defined(__NetBSD__)
 1681                              , p
 1682 #endif
 1683                              );
 1684 #ifdef INET6
 1685                 case PF_INET6:
 1686                         error = in6_control(so, (long)m, (caddr_t)nam,
 1687                             (struct ifnet *)control, p);
 1688 #endif
 1689                 default:
 1690                         error = EAFNOSUPPORT;
 1691                 }
 1692                 splx(s);
 1693                 return (error);
 1694         }
 1695 #ifdef __NetBSD__
 1696         if (req == PRU_PURGEIF) {
 1697                 struct ifnet *ifn;
 1698                 struct ifaddr *ifa;
 1699                 ifn = (struct ifnet *)control;
 1700                 TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
 1701                         if (ifa->ifa_addr->sa_family == family) {
 1702                                 sctp_delete_ip_address(ifa);
 1703                         }
 1704                 }
 1705                 switch (family) {
 1706                 case PF_INET:
 1707                         in_purgeif (ifn);
 1708                         break;
 1709 #ifdef INET6
 1710                 case PF_INET6:
 1711                         in6_purgeif (ifn);
 1712                         break;
 1713 #endif
 1714                 default:
 1715                         splx(s);
 1716                         return (EAFNOSUPPORT);
 1717                 }
 1718                 splx(s);
 1719                 return (0);
 1720         }
 1721 #endif
 1722         switch (req) {
 1723         case PRU_ATTACH:
 1724                 error = sctp6_attach(so, family, p);
 1725                 break;
 1726         case PRU_DETACH:
 1727                 error = sctp6_detach(so);
 1728                 break;
 1729         case PRU_BIND:
 1730                 if (nam == NULL)
 1731                         return (EINVAL);
 1732                 error = sctp6_bind(so, nam, p);
 1733                 break;
 1734         case PRU_LISTEN:
 1735                 error = sctp_listen(so, p);
 1736                 break;
 1737         case PRU_CONNECT:
 1738                 if (nam == NULL)
 1739                         return (EINVAL);
 1740                 error = sctp6_connect(so, nam, p);
 1741                 break;
 1742         case PRU_DISCONNECT:
 1743                 error = sctp6_disconnect(so);
 1744                 break;
 1745         case PRU_ACCEPT:
 1746                 if (nam == NULL)
 1747                         return (EINVAL);
 1748                 error = sctp_accept(so, nam);
 1749                 break;
 1750         case PRU_SHUTDOWN:
 1751                 error = sctp_shutdown(so);
 1752                 break;
 1753 
 1754         case PRU_RCVD:
 1755                 /*
 1756                  * For OpenBSD and NetBSD, this is real ugly. The (mbuf *)
 1757                  * nam that is passed (by soreceive()) is the int flags
 1758                  * cast as a (mbuf *) yuck!
 1759                  */
 1760                 error = sctp_usr_recvd(so, (int)((long)nam));
 1761                 break;
 1762 
 1763         case PRU_SEND:
 1764                 /* Flags are ignored */
 1765                 error = sctp6_send(so, 0, m, nam, control, p);
 1766                 break;
 1767         case PRU_ABORT:
 1768                 error = sctp6_abort(so);
 1769                 break;
 1770 
 1771         case PRU_SENSE:
 1772                 error = 0;
 1773                 break;
 1774         case PRU_RCVOOB:
 1775                 error = EAFNOSUPPORT;
 1776                 break;
 1777         case PRU_SENDOOB:
 1778                 error = EAFNOSUPPORT;
 1779                 break;
 1780         case PRU_PEERADDR:
 1781                 error = sctp6_getpeeraddr(so, nam);
 1782                 break;
 1783         case PRU_SOCKADDR:
 1784                 error = sctp6_in6getaddr(so, nam);
 1785                 break;
 1786         case PRU_SLOWTIMO:
 1787                 error = 0;
 1788                 break;
 1789         default:
 1790                 break;
 1791         }
 1792         splx(s);
 1793         return (error);
 1794 }
 1795 #endif

Cache object: 4db8a0513f9baae475686fc94ae3e389


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.