8f27b6f940ef7b458e5ef632974593c29a58ac46
[dragonfly.git] / sys / netinet6 / sctp6_usrreq.c
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 __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 inpcb *in_inp;
1069         struct in6pcb *inp6;
1070         int flags = msg->send.nm_flags;
1071 #ifdef INET
1072         struct sockaddr_in6 *sin6;
1073 #endif /* INET */
1074         int error;
1075         /* No SPL needed since sctp_output does this */
1076
1077         inp = (struct sctp_inpcb *)so->so_pcb;
1078         if (inp == NULL) {
1079                 if (control) {
1080                         m_freem(control);
1081                         control = NULL;
1082                 }
1083                 m_freem(m);
1084                 error = EINVAL;
1085                 goto out;
1086         }
1087         in_inp = (struct inpcb *)inp;
1088         inp6 = (struct in6pcb *)inp;
1089         /* For the TCP model we may get a NULL addr, if we
1090          * are a connected socket thats ok.
1091          */
1092         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
1093             (addr == NULL)) {
1094                 goto connected_type;
1095         }
1096         if (addr == NULL) {
1097                 m_freem(m);
1098                 if (control) {
1099                         m_freem(control);
1100                         control = NULL;
1101                 }
1102                 error = EDESTADDRREQ;
1103                 goto out;
1104         }
1105
1106 #ifdef INET
1107         sin6 = (struct sockaddr_in6 *)addr;
1108         if (
1109
1110 #if defined(__OpenBSD__)
1111              (0) /* we always do dual bind */
1112 #elif defined (__NetBSD__)
1113              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1114 #else
1115              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1116 #endif
1117             ) {
1118                 /*
1119                  * if IPV6_V6ONLY flag, we discard datagrams
1120                  * destined to a v4 addr or v4-mapped addr
1121                  */
1122                 if (addr->sa_family == AF_INET) {
1123                         error = EINVAL;
1124                         goto out;
1125                 }
1126                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1127                         error = EINVAL;
1128                         goto out;
1129                 }
1130         }
1131
1132         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1133                 if (!ip6_v6only) {
1134                         struct sockaddr_in *sin;
1135
1136                         sin = kmalloc(sizeof(*sin), M_LWKTMSG, M_INTWAIT);
1137                         /* convert v4-mapped into v4 addr and send */
1138                         in6_sin6_2_sin(sin, sin6);
1139                         msg->send.nm_addr = (struct sockaddr *)sin;
1140                         msg->send.nm_flags |= PRUS_NAMALLOC;
1141                         sctp_send(msg);
1142                         /* msg invalid now */
1143                         return;
1144                 } else {
1145                         /* mapped addresses aren't enabled */
1146                         error = EINVAL;
1147                         goto out;
1148                 }
1149         }
1150 #endif /* INET */
1151 connected_type:
1152         /* now what about control */
1153         if (control) {
1154                 if (inp->control) {
1155                         kprintf("huh? control set?\n");
1156                         m_freem(inp->control);
1157                         inp->control = NULL;
1158                 }
1159                 inp->control = control;
1160         }
1161         /* add it in possibly */
1162         if ((inp->pkt) &&
1163             (inp->pkt->m_flags & M_PKTHDR)) {
1164                 struct mbuf *x;
1165                 int c_len;
1166
1167                 c_len = 0;
1168                 /* How big is it */
1169                 for (x=m;x;x = x->m_next) {
1170                         c_len += x->m_len;
1171                 }
1172                 inp->pkt->m_pkthdr.len += c_len;
1173         }
1174         /* Place the data */
1175         if (inp->pkt) {
1176                 inp->pkt_last->m_next = m;
1177                 inp->pkt_last = m;
1178         } else {
1179                 inp->pkt_last = inp->pkt = m;
1180         }
1181         if (
1182 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1183             /* FreeBSD and MacOSX uses a flag passed */
1184             (!(flags & PRUS_MORETOCOME))
1185 #elif defined(__NetBSD__)
1186             /* NetBSD uses the so_state field */
1187             (!(so->so_state & SS_MORETOCOME))
1188 #else
1189             1   /* Open BSD does not have any "more to come" indication */
1190 #endif
1191             ) {
1192                 /*
1193                  * note with the current version this code will only be
1194                  * used by OpenBSD, NetBSD and FreeBSD have methods for
1195                  * re-defining sosend() to use sctp_sosend().  One can
1196                  * optionaly switch back to this code (by changing back
1197                  * the defininitions but this is not advisable.
1198                  */
1199                 error = sctp_output(inp, inp->pkt, addr,
1200                                     inp->control, msg->send.nm_td, flags);
1201                 inp->pkt = NULL;
1202                 inp->control = NULL;
1203         } else {
1204                 error = 0;
1205         }
1206 out:
1207         lwkt_replymsg(&msg->lmsg, error);
1208 }
1209
1210 static void
1211 sctp6_connect(netmsg_t msg)
1212 {
1213         struct socket *so = msg->connect.base.nm_so;
1214         struct sockaddr *addr = msg->connect.nm_nam;
1215         struct sctp_inpcb *inp;
1216         struct in6pcb *inp6;
1217         struct sctp_tcb *stcb;
1218 #ifdef INET
1219         struct sockaddr_in6 *sin6;
1220         struct sockaddr_storage ss;
1221 #endif /* INET */
1222         int error = 0;
1223
1224         crit_enter();
1225         inp6 = (struct in6pcb *)so->so_pcb;
1226         inp = (struct sctp_inpcb *)so->so_pcb;
1227         if (inp == NULL) {
1228                 crit_exit();
1229                 error = ECONNRESET;     /* I made the same as TCP since
1230                                          * we are not setup? */
1231                 goto out;
1232         }
1233         SCTP_ASOC_CREATE_LOCK(inp);
1234         SCTP_INP_RLOCK(inp);
1235         if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1236             SCTP_PCB_FLAGS_UNBOUND) {
1237                 /* Bind a ephemeral port */
1238                 SCTP_INP_RUNLOCK(inp);
1239                 error = sctp6_bind_oncpu(so, NULL, msg->connect.nm_td);
1240                 if (error) {
1241                         crit_exit();
1242                         SCTP_ASOC_CREATE_UNLOCK(inp);
1243                         goto out;
1244                 }
1245                 SCTP_INP_RLOCK(inp);
1246         }
1247
1248         if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1249             (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1250                 /* We are already connected AND the TCP model */
1251                 crit_exit();
1252                 SCTP_INP_RUNLOCK(inp);
1253                 SCTP_ASOC_CREATE_UNLOCK(inp);
1254                 error = EADDRINUSE;
1255                 goto out;
1256         }
1257
1258 #ifdef INET
1259         sin6 = (struct sockaddr_in6 *)addr;
1260         if (
1261 #if defined(__OpenBSD__)
1262              (0) /* we always do dual bind */
1263 #elif defined (__NetBSD__)
1264              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1265 #else
1266              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1267 #endif
1268             ) {
1269                 /*
1270                  * if IPV6_V6ONLY flag, ignore connections
1271                  * destined to a v4 addr or v4-mapped addr
1272                  */
1273                 if (addr->sa_family == AF_INET) {
1274                         crit_exit();
1275                         SCTP_INP_RUNLOCK(inp);
1276                         SCTP_ASOC_CREATE_UNLOCK(inp);
1277                         error = EINVAL;
1278                         goto out;
1279                 }
1280                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1281                         crit_exit();
1282                         SCTP_INP_RUNLOCK(inp);
1283                         SCTP_ASOC_CREATE_UNLOCK(inp);
1284                         error = EINVAL;
1285                         goto out;
1286                 }
1287         }
1288
1289         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1290                 if (!ip6_v6only) {
1291                         /* convert v4-mapped into v4 addr */
1292                         in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
1293                         addr = (struct sockaddr *)&ss;
1294                 } else {
1295                         /* mapped addresses aren't enabled */
1296                         crit_exit();
1297                         SCTP_INP_RUNLOCK(inp);
1298                         SCTP_ASOC_CREATE_UNLOCK(inp);
1299                         error = EINVAL;
1300                         goto out;
1301                 }
1302         } else
1303 #endif /* INET */
1304                 addr = addr;    /* for true v6 address case */
1305
1306         /* Now do we connect? */
1307         if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1308                 stcb = LIST_FIRST(&inp->sctp_asoc_list);
1309                 if (stcb)
1310                         SCTP_TCB_UNLOCK (stcb);
1311                 SCTP_INP_RUNLOCK(inp);
1312         }else {
1313                 SCTP_INP_RUNLOCK(inp);
1314                 SCTP_INP_WLOCK(inp);
1315                 SCTP_INP_INCR_REF(inp);
1316                 SCTP_INP_WUNLOCK(inp);
1317                 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
1318                 if (stcb == NULL) {
1319                         SCTP_INP_WLOCK(inp);
1320                         SCTP_INP_DECR_REF(inp);
1321                         SCTP_INP_WUNLOCK(inp);
1322                 }
1323         }
1324
1325         if (stcb != NULL) {
1326                 /* Already have or am bring up an association */
1327                 SCTP_ASOC_CREATE_UNLOCK(inp);
1328                 SCTP_TCB_UNLOCK (stcb);
1329                 crit_exit();
1330                 error = EALREADY;
1331                 goto out;
1332         }
1333         /* We are GOOD to go */
1334         stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0);
1335         SCTP_ASOC_CREATE_UNLOCK(inp);
1336         if (stcb == NULL) {
1337                 /* Gak! no memory */
1338                 crit_exit();
1339                 goto out;
1340         }
1341         if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1342                 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1343                 /* Set the connected flag so we can queue data */
1344                 soisconnecting(so);
1345         }
1346         stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1347         SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1348         sctp_send_initiate(inp, stcb);
1349         SCTP_TCB_UNLOCK (stcb);
1350         crit_exit();
1351 out:
1352         lwkt_replymsg(&msg->lmsg, error);
1353 }
1354
1355 static int
1356 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1357 sctp6_getaddr(struct socket *so, struct sockaddr **addr)
1358 {
1359         struct sockaddr_in6 *sin6;
1360 #else
1361 sctp6_getaddr(struct socket *so, struct mbuf *nam)
1362 {
1363         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1364 #endif
1365         struct sctp_inpcb *inp;
1366         /*
1367          * Do the malloc first in case it blocks.
1368          */
1369 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1370         sin6 = kmalloc(sizeof *sin6, M_SONAME, M_WAITOK | M_ZERO);
1371 #else
1372         nam->m_len = sizeof(*sin6);
1373 #endif
1374         bzero(sin6, sizeof(*sin6));
1375         sin6->sin6_family = AF_INET6;
1376         sin6->sin6_len = sizeof(*sin6);
1377
1378         inp = (struct sctp_inpcb *)so->so_pcb;
1379         if (!inp) {
1380 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1381                 kfree(sin6, M_SONAME);
1382 #endif
1383                 return ECONNRESET;
1384         }
1385
1386         sin6->sin6_port = inp->sctp_lport;
1387         if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1388                 /* For the bound all case you get back 0 */
1389                 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1390                         struct sctp_tcb *stcb;
1391                         struct sockaddr_in6 *sin_a6;
1392                         struct sctp_nets *net;
1393                         int fnd;
1394
1395                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1396                         if (stcb == NULL) {
1397                                 goto notConn6;
1398                         }
1399                         fnd = 0;
1400                         sin_a6 = NULL;
1401                         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1402                                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1403                                 if (sin_a6->sin6_family == AF_INET6) {
1404                                         fnd = 1;
1405                                         break;
1406                                 }
1407                         }
1408                         if ((!fnd) || (sin_a6 == NULL)) {
1409                                 /* punt */
1410                                 goto notConn6;
1411                         }
1412                         sin6->sin6_addr = sctp_ipv6_source_address_selection(
1413                             inp, stcb, (struct route *)&net->ro, net, 0);
1414
1415                 } else {
1416                         /* For the bound all case you get back 0 */
1417                 notConn6:
1418                         memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1419                 }
1420         } else {
1421                 /* Take the first IPv6 address in the list */
1422                 struct sctp_laddr *laddr;
1423                 int fnd = 0;
1424                 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1425                         if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
1426                                 struct sockaddr_in6 *sin_a;
1427                                 sin_a = (struct sockaddr_in6 *)laddr->ifa->ifa_addr;
1428                                 sin6->sin6_addr = sin_a->sin6_addr;
1429                                 fnd = 1;
1430                                 break;
1431                         }
1432                 }
1433                 if (!fnd) {
1434 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1435                         kfree(sin6, M_SONAME);
1436 #endif
1437                         return ENOENT;
1438                 }
1439         }
1440         /* Scoping things for v6 */
1441         if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
1442                 /* skip ifp check below */
1443                 in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1444         else
1445                 sin6->sin6_scope_id = 0;        /*XXX*/
1446 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1447         (*addr) = (struct sockaddr *)sin6;
1448 #endif
1449         return (0);
1450 }
1451
1452 static int
1453 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1454 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1455 {
1456         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
1457 #else
1458 sctp6_peeraddr(struct socket *so, struct mbuf *nam)
1459 {
1460         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1461 #endif
1462         int fnd;
1463         struct sockaddr_in6 *sin_a6;
1464         struct sctp_inpcb *inp;
1465         struct sctp_tcb *stcb;
1466         struct sctp_nets *net;
1467         /*
1468          * Do the malloc first in case it blocks.
1469          */
1470         inp = (struct sctp_inpcb *)so->so_pcb;
1471         if (!(inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1472                 /* UDP type and listeners will drop out here */
1473                 return (ENOTCONN);
1474         }
1475 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1476         sin6 = kmalloc(sizeof *sin6, M_SONAME, M_WAITOK | M_ZERO);
1477 #else
1478         nam->m_len = sizeof(*sin6);
1479 #endif
1480         bzero(sin6, sizeof(*sin6));
1481         sin6->sin6_family = AF_INET6;
1482         sin6->sin6_len = sizeof(*sin6);
1483
1484         /* We must recapture incase we blocked */
1485         inp = (struct sctp_inpcb *)so->so_pcb;
1486         if (!inp) {
1487 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1488                 kfree(sin6, M_SONAME);
1489 #endif
1490                 return ECONNRESET;
1491         }
1492         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1493         if (stcb == NULL) {
1494 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1495                 kfree(sin6, M_SONAME);
1496 #endif
1497                 return ECONNRESET;
1498         }
1499         fnd = 0;
1500         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1501                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1502                 if (sin_a6->sin6_family == AF_INET6) {
1503                         fnd = 1;
1504                         sin6->sin6_port = stcb->rport;
1505                         sin6->sin6_addr = sin_a6->sin6_addr;
1506                         break;
1507                 }
1508         }
1509         if (!fnd) {
1510                 /* No IPv4 address */
1511 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1512                 kfree(sin6, M_SONAME);
1513 #endif
1514                 return ENOENT;
1515         }
1516         in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1517 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1518         *addr = (struct sockaddr *)sin6;
1519 #endif
1520         return (0);
1521 }
1522
1523 static void
1524 sctp6_in6getaddr(netmsg_t msg)
1525 {
1526         struct socket *so = msg->sockaddr.base.nm_so;;
1527         struct sockaddr **nam = msg->sockaddr.nm_nam;
1528         struct sockaddr *addr;
1529         struct in6pcb *inp6 = sotoin6pcb(so);
1530         int error;
1531
1532         if (inp6 == NULL) {
1533                 error = EINVAL;
1534                 goto out;
1535         }
1536
1537         crit_enter();
1538         /* allow v6 addresses precedence */
1539         error = sctp6_getaddr(so, nam);
1540         if (error) {
1541                 /* try v4 next if v6 failed */
1542                 error = sctp_ingetaddr_oncpu(so, nam);
1543                 if (error) {
1544                         crit_exit();
1545                         goto out;
1546                 }
1547 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1548                 addr = *nam;
1549 #endif
1550                 /* if I'm V6ONLY, convert it to v4-mapped */
1551                 if (
1552 #if defined(__OpenBSD__)
1553              (0) /* we always do dual bind */
1554 #elif defined (__NetBSD__)
1555              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1556 #else
1557              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1558 #endif
1559                     ) {
1560                         struct sockaddr_in6 sin6;
1561                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1562                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1563 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1564                         nam->m_len = sizeof(sin6);
1565 #endif
1566 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1567                 } else {
1568                         nam->m_len = sizeof(struct sockaddr_in);
1569 #endif
1570                 }
1571 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1572         } else {
1573                 nam->m_len = sizeof(struct sockaddr_in6);
1574 #endif
1575         }
1576         crit_exit();
1577 out:
1578         lwkt_replymsg(&msg->lmsg, error);
1579 }
1580
1581 static void
1582 sctp6_getpeeraddr(netmsg_t msg)
1583 {
1584         struct socket *so = msg->peeraddr.base.nm_so;
1585         struct sockaddr **nam = msg->peeraddr.nm_nam;
1586         struct sockaddr *addr = *nam;
1587         struct in6pcb *inp6 = sotoin6pcb(so);
1588         int error;
1589
1590         if (inp6 == NULL) {
1591                 error = EINVAL;
1592                 goto out;
1593         }
1594
1595         crit_enter();
1596         /* allow v6 addresses precedence */
1597         error = sctp6_peeraddr(so, nam);
1598         if (error) {
1599                 /* try v4 next if v6 failed */
1600                 error = sctp_peeraddr_oncpu(so, nam);
1601                 if (error) {
1602                         crit_exit();
1603                         goto out;
1604                 }
1605                 /* if I'm V6ONLY, convert it to v4-mapped */
1606                 if (
1607 #if defined(__OpenBSD__)
1608              (0) /* we always do dual bind */
1609 #elif defined (__NetBSD__)
1610              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1611 #else
1612              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1613 #endif
1614                     ) {
1615                         struct sockaddr_in6 sin6;
1616                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1617                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1618 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1619                         nam->m_len = sizeof(sin6);
1620 #endif
1621 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1622                 } else {
1623                         nam->m_len = sizeof(struct sockaddr_in);
1624 #endif
1625                 }
1626 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1627         } else {
1628                 nam->m_len = sizeof(struct sockaddr_in6);
1629 #endif
1630         }
1631         crit_exit();
1632 out:
1633         lwkt_replymsg(&msg->lmsg, error);
1634 }
1635
1636 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1637 struct pr_usrreqs sctp6_usrreqs = {
1638         .pru_abort = sctp6_abort,
1639         .pru_accept = sctp_accept,
1640         .pru_attach = sctp6_attach,
1641         .pru_bind = sctp6_bind,
1642         .pru_connect = sctp6_connect,
1643         .pru_connect2 = pr_generic_notsupp,
1644         .pru_control = in6_control_dispatch,
1645         .pru_detach = sctp6_detach,
1646         .pru_disconnect = sctp6_disconnect,
1647         .pru_listen = sctp_listen,
1648         .pru_peeraddr = sctp6_getpeeraddr,
1649         .pru_rcvd = sctp_usr_recvd,
1650         .pru_rcvoob = pr_generic_notsupp,
1651         .pru_send = sctp6_send,
1652         .pru_sense = pru_sense_null,
1653         .pru_shutdown = sctp_shutdown,
1654         .pru_sockaddr = sctp6_in6getaddr,
1655         .pru_sosend = sctp_sosend,
1656         .pru_soreceive = soreceive
1657 };
1658
1659 #else
1660
1661 #error x
1662
1663 int
1664 sctp6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
1665              struct mbuf *control, struct proc *p)
1666 {
1667         int s;
1668         int error = 0;
1669         int family;
1670
1671 #if defined(__OpenBSD__)
1672         p = curproc;
1673 #endif
1674         s = splsoftnet();
1675         family = so->so_proto->pr_domain->dom_family;
1676
1677         if (req == PRU_CONTROL) {
1678                 switch (family) {
1679                 case PF_INET:
1680                         error = in_control(so, (long)m, (caddr_t)nam,
1681                             (struct ifnet *)control
1682 #if defined(__NetBSD__)
1683                              , p
1684 #endif
1685                              );
1686 #ifdef INET6
1687                 case PF_INET6:
1688                         error = in6_control(so, (long)m, (caddr_t)nam,
1689                             (struct ifnet *)control, p);
1690 #endif
1691                 default:
1692                         error = EAFNOSUPPORT;
1693                 }
1694                 splx(s);
1695                 return (error);
1696         }
1697 #ifdef __NetBSD__
1698         if (req == PRU_PURGEIF) {
1699                 struct ifnet *ifn;
1700                 struct ifaddr *ifa;
1701                 ifn = (struct ifnet *)control;
1702                 TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
1703                         if (ifa->ifa_addr->sa_family == family) {
1704                                 sctp_delete_ip_address(ifa);
1705                         }
1706                 }
1707                 switch (family) {
1708                 case PF_INET:
1709                         in_purgeif (ifn);
1710                         break;
1711 #ifdef INET6
1712                 case PF_INET6:
1713                         in6_purgeif (ifn);
1714                         break;
1715 #endif
1716                 default:
1717                         splx(s);
1718                         return (EAFNOSUPPORT);
1719                 }
1720                 splx(s);
1721                 return (0);
1722         }
1723 #endif
1724         switch (req) {
1725         case PRU_ATTACH:
1726                 error = sctp6_attach(so, family, p);
1727                 break;
1728         case PRU_DETACH:
1729                 error = sctp6_detach(so);
1730                 break;
1731         case PRU_BIND:
1732                 if (nam == NULL)
1733                         return (EINVAL);
1734                 error = sctp6_bind(so, nam, p);
1735                 break;
1736         case PRU_LISTEN:
1737                 error = sctp_listen(so, p);
1738                 break;
1739         case PRU_CONNECT:
1740                 if (nam == NULL)
1741                         return (EINVAL);
1742                 error = sctp6_connect(so, nam, p);
1743                 break;
1744         case PRU_DISCONNECT:
1745                 error = sctp6_disconnect(so);
1746                 break;
1747         case PRU_ACCEPT:
1748                 if (nam == NULL)
1749                         return (EINVAL);
1750                 error = sctp_accept(so, nam);
1751                 break;
1752         case PRU_SHUTDOWN:
1753                 error = sctp_shutdown(so);
1754                 break;
1755
1756         case PRU_RCVD:
1757                 /*
1758                  * For OpenBSD and NetBSD, this is real ugly. The (mbuf *)
1759                  * nam that is passed (by soreceive()) is the int flags
1760                  * cast as a (mbuf *) yuck!
1761                  */
1762                 error = sctp_usr_recvd(so, (int)((long)nam));
1763                 break;
1764
1765         case PRU_SEND:
1766                 /* Flags are ignored */
1767                 error = sctp6_send(so, 0, m, nam, control, p);
1768                 break;
1769         case PRU_ABORT:
1770                 error = sctp6_abort(so);
1771                 break;
1772
1773         case PRU_SENSE:
1774                 error = 0;
1775                 break;
1776         case PRU_RCVOOB:
1777                 error = EAFNOSUPPORT;
1778                 break;
1779         case PRU_SENDOOB:
1780                 error = EAFNOSUPPORT;
1781                 break;
1782         case PRU_PEERADDR:
1783                 error = sctp6_getpeeraddr(so, nam);
1784                 break;
1785         case PRU_SOCKADDR:
1786                 error = sctp6_in6getaddr(so, nam);
1787                 break;
1788         case PRU_SLOWTIMO:
1789                 error = 0;
1790                 break;
1791         default:
1792                 break;
1793         }
1794         splx(s);
1795         return (error);
1796 }
1797 #endif