devfs - Allow clone code to reuse an existing device (2)
[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 static int sctp6_bind_oncpu(struct socket *so, struct sockaddr *addr, thread_t td);
128
129
130 extern int sctp_no_csum_on_loopback;
131
132 int
133 sctp6_input(struct mbuf **mp, int *offp, int proto)
134 {
135         struct mbuf *m = *mp;
136         struct ip6_hdr *ip6;
137         struct sctphdr *sh;
138         struct sctp_inpcb *in6p = NULL;
139         struct sctp_nets *net;
140         int refcount_up = 0;
141         u_int32_t check, calc_check;
142         struct inpcb *in6p_ip;
143         struct sctp_chunkhdr *ch;
144         struct mbuf *opts = NULL;
145         int length, mlen, offset, iphlen;
146         u_int8_t ecn_bits;
147         struct sctp_tcb *stcb = NULL;
148         int off = *offp;
149
150         ip6 = mtod(m, struct ip6_hdr *);
151 #ifndef PULLDOWN_TEST
152         /* If PULLDOWN_TEST off, must be in a single mbuf. */
153         IP6_EXTHDR_CHECK(m, off, (int)(sizeof(*sh) + sizeof(*ch)), IPPROTO_DONE);
154         sh = (struct sctphdr *)((caddr_t)ip6 + off);
155         ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(*sh));
156 #else
157         /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
158         IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch));
159         if (sh == NULL) {
160                 sctp_pegs[SCTP_HDR_DROPS]++;
161                 return IPPROTO_DONE;
162         }
163         ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
164 #endif
165
166         iphlen = off;
167         offset = iphlen + sizeof(*sh) + sizeof(*ch);
168
169 #if defined(NFAITH) && NFAITH > 0
170 #if defined(__FreeBSD_cc_version) && __FreeBSD_cc_version <= 430000
171 #if defined(NFAITH) && 0 < NFAITH
172         if (faithprefix(&ip6h->ip6_dst)) {
173                 /* XXX send icmp6 host/port unreach? */
174                 goto bad;
175         }
176 #endif
177 #else
178
179 #ifdef __FreeBSD__
180         if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
181                 /* XXX send icmp6 host/port unreach? */
182                 goto bad;
183         }
184 #else
185         if (faithprefix(&ip6->ip6_dst))
186                 goto bad;
187 #endif
188 #endif /* __FreeBSD_cc_version */
189
190 #endif /* NFAITH defined and > 0 */
191         sctp_pegs[SCTP_INPKTS]++;
192 #ifdef SCTP_DEBUG
193         if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
194                 kprintf("V6 input gets a packet iphlen:%d pktlen:%d\n", iphlen, m->m_pkthdr.len);
195         }
196 #endif
197         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
198                 /* No multi-cast support in SCTP */
199                 sctp_pegs[SCTP_IN_MCAST]++;
200                 goto bad;
201         }
202         /* destination port of 0 is illegal, based on RFC2960. */
203         if (sh->dest_port == 0)
204                 goto bad;
205         if ((sctp_no_csum_on_loopback == 0) ||
206            (m->m_pkthdr.rcvif == NULL) ||
207            (m->m_pkthdr.rcvif->if_type != IFT_LOOP)) {
208                 /* we do NOT validate things from the loopback if the
209                  * sysctl is set to 1.
210                  */
211                 check = sh->checksum;           /* save incoming checksum */
212                 if ((check == 0) && (sctp_no_csum_on_loopback)) {
213                         /* special hook for where we got a local address
214                          * somehow routed across a non IFT_LOOP type interface
215                          */
216                         if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))
217                                 goto sctp_skip_csum;
218                 }
219                 sh->checksum = 0;               /* prepare for calc */
220                 calc_check = sctp_calculate_sum(m, &mlen, iphlen);
221                 if (calc_check != check) {
222 #ifdef SCTP_DEBUG
223                         if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
224                                 kprintf("Bad CSUM on SCTP packet calc_check:%x check:%x  m:%p mlen:%d iphlen:%d\n",
225                                        calc_check, check, m,
226                                        mlen, iphlen);
227                         }
228 #endif
229                         stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
230                                                          sh, ch, &in6p, &net);
231                         /* in6p's ref-count increased && stcb locked */
232                         if ((in6p) && (stcb)) {
233                                 sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
234                                 sctp_chunk_output(in6p, stcb, 2);
235                         }  else if ((in6p != NULL) && (stcb == NULL)) {
236                                 refcount_up = 1;
237                         }
238                         sctp_pegs[SCTP_BAD_CSUM]++;
239                         goto bad;
240                 }
241                 sh->checksum = calc_check;
242         } else {
243 sctp_skip_csum:
244                 mlen = m->m_pkthdr.len;
245         }
246         net = NULL;
247         /*
248          * Locate pcb and tcb for datagram
249          * sctp_findassociation_addr() wants IP/SCTP/first chunk header...
250          */
251 #ifdef SCTP_DEBUG
252         if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
253                 kprintf("V6 Find the association\n");
254         }
255 #endif
256         stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
257             sh, ch, &in6p, &net);
258         /* in6p's ref-count increased */
259         if (in6p == NULL) {
260                 struct sctp_init_chunk *init_chk, chunk_buf;
261
262                 sctp_pegs[SCTP_NOPORTS]++;
263                 if (ch->chunk_type == SCTP_INITIATION) {
264                         /* we do a trick here to get the INIT tag,
265                          * dig in and get the tag from the INIT and
266                          * put it in the common header.
267                          */
268                         init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
269                             iphlen + sizeof(*sh), sizeof(*init_chk),
270                             (u_int8_t *)&chunk_buf);
271                         sh->v_tag = init_chk->init.initiate_tag;
272                 }
273                 sctp_send_abort(m, iphlen, sh, 0, NULL);
274                 goto bad;
275         } else if (stcb == NULL) {
276                 refcount_up = 1;
277         }
278         in6p_ip = (struct inpcb *)in6p;
279 #ifdef IPSEC
280         /*
281          * Check AH/ESP integrity.
282          */
283 #ifdef __OpenBSD__
284         {
285                 struct inpcb *i_inp;
286                 struct m_tag *mtag;
287                 struct tdb_ident *tdbi;
288                 struct tdb *tdb;
289                 int error;
290
291                 /* Find most recent IPsec tag */
292                 i_inp = (struct inpcb *)in6p;
293                 mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
294                 crit_enter();
295                 if (mtag != NULL) {
296                         tdbi = (struct tdb_ident *)(mtag + 1);
297                         tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
298                 } else
299                         tdb = NULL;
300
301                 ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
302                     tdb, i_inp);
303                 if (error) {
304                         crit_exit();
305                         goto bad;
306                 }
307
308                 /* Latch SA */
309                 if (i_inp->inp_tdb_in != tdb) {
310                         if (tdb) {
311                                 tdb_add_inp(tdb, i_inp, 1);
312                                 if (i_inp->inp_ipo == NULL) {
313                                         i_inp->inp_ipo = ipsec_add_policy(i_inp,
314                                             af, IPSP_DIRECTION_OUT);
315                                         if (i_inp->inp_ipo == NULL) {
316                                                 crit_exit();
317                                                 goto bad;
318                                         }
319                                 }
320                                 if (i_inp->inp_ipo->ipo_dstid == NULL &&
321                                     tdb->tdb_srcid != NULL) {
322                                         i_inp->inp_ipo->ipo_dstid =
323                                             tdb->tdb_srcid;
324                                         tdb->tdb_srcid->ref_count++;
325                                 }
326                                 if (i_inp->inp_ipsec_remotecred == NULL &&
327                                     tdb->tdb_remote_cred != NULL) {
328                                         i_inp->inp_ipsec_remotecred =
329                                             tdb->tdb_remote_cred;
330                                         tdb->tdb_remote_cred->ref_count++;
331                                 }
332                                 if (i_inp->inp_ipsec_remoteauth == NULL &&
333                                     tdb->tdb_remote_auth != NULL) {
334                                         i_inp->inp_ipsec_remoteauth =
335                                             tdb->tdb_remote_auth;
336                                         tdb->tdb_remote_auth->ref_count++;
337                                 }
338                         } else { /* Just reset */
339                                 TAILQ_REMOVE(&i_inp->inp_tdb_in->tdb_inp_in,
340                                     i_inp, binp_tdb_in_next);
341                                 i_inp->inp_tdb_in = NULL;
342                         }
343                 }
344                 crit_exit();
345         }
346 #else
347         if (ipsec6_in_reject_so(m, in6p->sctp_socket)) {
348 /* XXX */
349 #ifndef __APPLE__
350                 /* FIX ME: need to find right stat for __APPLE__ */
351                 ipsec6stat.in_polvio++;
352 #endif
353                 goto bad;
354         }
355 #endif
356 #endif /*IPSEC*/
357
358         /*
359          * Construct sockaddr format source address.
360          * Stuff source address and datagram in user buffer.
361          */
362         if ((in6p->ip_inp.inp.inp_flags & INP_CONTROLOPTS)
363 #ifndef __OpenBSD__
364             || (in6p->sctp_socket->so_options & SO_TIMESTAMP)
365 #endif
366             ) {
367 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
368 #if (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version < 501113) || \
369     defined(__APPLE__) || defined(__DragonFly__)
370                 ip6_savecontrol(in6p_ip, &opts, ip6, m);
371 #elif defined(__FreeBSD__) && (__FreeBSD_version >= 440000 || (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version >= 501113))
372                 ip6_savecontrol(in6p_ip, m, &opts);
373 #else
374                 ip6_savecontrol(in6p_ip, m, &opts, NULL);
375 #endif
376 #else
377                 ip6_savecontrol((struct in6pcb *)in6p_ip, m, &opts);
378 #endif
379         }
380
381         /*
382          * CONTROL chunk processing
383          */
384         length = ntohs(ip6->ip6_plen) + iphlen;
385         offset -= sizeof(*ch);
386         ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
387         crit_enter();
388         sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
389             in6p, stcb, net, ecn_bits);
390         /* inp's ref-count reduced && stcb unlocked */
391         crit_exit();
392         /* XXX this stuff below gets moved to appropriate parts later... */
393         if (m)
394                 m_freem(m);
395         if (opts)
396                 m_freem(opts);
397
398         if ((in6p) && refcount_up){
399                 /* reduce ref-count */
400                 SCTP_INP_WLOCK(in6p);
401                 SCTP_INP_DECR_REF(in6p);
402                 SCTP_INP_WUNLOCK(in6p);
403         }
404
405         return IPPROTO_DONE;
406
407 bad:
408         if (stcb)
409                 SCTP_TCB_UNLOCK(stcb);
410
411         if ((in6p) && refcount_up){
412                 /* reduce ref-count */
413                 SCTP_INP_WLOCK(in6p);
414                 SCTP_INP_DECR_REF(in6p);
415                 SCTP_INP_WUNLOCK(in6p);
416         }
417         if (m)
418                 m_freem(m);
419         if (opts)
420                 m_freem(opts);
421         return IPPROTO_DONE;
422 }
423
424
425 static void
426 sctp6_notify_mbuf(struct sctp_inpcb *inp,
427                   struct icmp6_hdr *icmp6,
428                   struct sctphdr *sh,
429                   struct sctp_tcb *stcb,
430                   struct sctp_nets *net)
431 {
432         unsigned int nxtsz;
433
434         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
435             (icmp6 == NULL) || (sh == NULL)) {
436                 goto out;
437         }
438
439         /* First do we even look at it? */
440         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
441                 goto out;
442
443         if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
444                 /* not PACKET TO BIG */
445                 goto out;
446         }
447         /*
448          * ok we need to look closely. We could even get smarter and
449          * look at anyone that we sent to in case we get a different
450          * ICMP that tells us there is no way to reach a host, but for
451          * this impl, all we care about is MTU discovery.
452          */
453         nxtsz = ntohl(icmp6->icmp6_mtu);
454         /* Stop any PMTU timer */
455         sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
456
457         /* Adjust destination size limit */
458         if (net->mtu > nxtsz) {
459                 net->mtu = nxtsz;
460         }
461         /* now what about the ep? */
462         if (stcb->asoc.smallest_mtu > nxtsz) {
463                 struct sctp_tmit_chunk *chk;
464                 struct sctp_stream_out *strm;
465                 /* Adjust that too */
466                 stcb->asoc.smallest_mtu = nxtsz;
467                 /* now off to subtract IP_DF flag if needed */
468
469                 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
470                         if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
471                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
472                         }
473                 }
474                 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
475                         if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
476                                 /*
477                                  * For this guy we also mark for immediate
478                                  * resend since we sent to big of chunk
479                                  */
480                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
481                                 if (chk->sent != SCTP_DATAGRAM_RESEND)
482                                         stcb->asoc.sent_queue_retran_cnt++;
483                                 chk->sent = SCTP_DATAGRAM_RESEND;
484                                 chk->rec.data.doing_fast_retransmit = 0;
485
486                                 chk->sent = SCTP_DATAGRAM_RESEND;
487                                 /* Clear any time so NO RTT is being done */
488                                 chk->sent_rcv_time.tv_sec = 0;
489                                 chk->sent_rcv_time.tv_usec = 0;
490                                 stcb->asoc.total_flight -= chk->send_size;
491                                 net->flight_size -= chk->send_size;
492                         }
493                 }
494                 TAILQ_FOREACH(strm, &stcb->asoc.out_wheel, next_spoke) {
495                         TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) {
496                                 if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
497                                         chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
498                                 }
499                         }
500                 }
501         }
502         sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
503 out:
504         if (inp) {
505                 /* reduce inp's ref-count */
506                 SCTP_INP_WLOCK(inp);
507                 SCTP_INP_DECR_REF(inp);
508                 SCTP_INP_WUNLOCK(inp);
509         }
510         if (stcb)
511                 SCTP_TCB_UNLOCK(stcb);
512 }
513
514
515 void
516 sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
517 {
518         struct sctphdr sh;
519         struct ip6ctlparam *ip6cp = NULL;
520         int cm;
521
522         if (pktdst->sa_family != AF_INET6 ||
523             pktdst->sa_len != sizeof(struct sockaddr_in6))
524                 return;
525
526         if ((unsigned)cmd >= PRC_NCMDS)
527                 return;
528         if (PRC_IS_REDIRECT(cmd)) {
529                 d = NULL;
530         } else if (inet6ctlerrmap[cmd] == 0) {
531                 return;
532         }
533
534         /* if the parameter is from icmp6, decode it. */
535         if (d != NULL) {
536                 ip6cp = (struct ip6ctlparam *)d;
537         } else {
538                 ip6cp = NULL;
539         }
540
541         if (ip6cp) {
542                 /*
543                  * XXX: We assume that when IPV6 is non NULL,
544                  * M and OFF are valid.
545                  */
546                 /* check if we can safely examine src and dst ports */
547                 struct sctp_inpcb *inp;
548                 struct sctp_tcb *stcb;
549                 struct sctp_nets *net;
550                 struct sockaddr_in6 final;
551
552                 if (ip6cp->ip6c_m == NULL ||
553                     (size_t)ip6cp->ip6c_m->m_pkthdr.len < (ip6cp->ip6c_off + sizeof(sh)))
554                         return;
555
556                 bzero(&sh, sizeof(sh));
557                 bzero(&final, sizeof(final));
558                 inp = NULL;
559                 net = NULL;
560                 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
561                     (caddr_t)&sh);
562                 ip6cp->ip6c_src->sin6_port = sh.src_port;
563                 final.sin6_len = sizeof(final);
564                 final.sin6_family = AF_INET6;
565 #if defined(__FreeBSD__) && __FreeBSD_cc_version < 440000
566                 final.sin6_addr = *ip6cp->ip6c_finaldst;
567 #else
568                 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
569 #endif /* __FreeBSD_cc_version */
570                 final.sin6_port = sh.dest_port;
571                 crit_enter();
572                 stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src,
573                                                     (struct sockaddr *)&final,
574                                                     &inp, &net, 1);
575                 /* inp's ref-count increased && stcb locked */
576                 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
577                         if (cmd == PRC_MSGSIZE) {
578                                 sctp6_notify_mbuf(inp,
579                                                   ip6cp->ip6c_icmp6,
580                                                   &sh,
581                                                   stcb,
582                                                   net);
583                                 /* inp's ref-count reduced && stcb unlocked */
584                         } else {
585                                 if (cmd == PRC_HOSTDEAD) {
586                                         cm = EHOSTUNREACH;
587                                 } else {
588                                         cm = inet6ctlerrmap[cmd];
589                                 }
590                                 sctp_notify(inp, cm, &sh,
591                                             (struct sockaddr *)&final,
592                                             stcb, net);
593                                 /* inp's ref-count reduced && stcb unlocked */
594                         }
595                 } else {
596                         if (PRC_IS_REDIRECT(cmd) && inp) {
597 #ifdef __OpenBSD__
598                                 in_rtchange((struct inpcb *)inp,
599                                             inetctlerrmap[cmd]);
600 #else
601                                 in6_rtchange((struct in6pcb *)inp,
602                                              inet6ctlerrmap[cmd]);
603 #endif
604                         }
605                         if (inp) {
606                                 /* reduce inp's ref-count */
607                                 SCTP_INP_WLOCK(inp);
608                                 SCTP_INP_DECR_REF(inp);
609                                 SCTP_INP_WUNLOCK(inp);
610                         }
611                         if (stcb)
612                                 SCTP_TCB_UNLOCK(stcb);
613                 }
614                 crit_exit();
615         }
616 }
617
618 /*
619  * this routine can probably be collasped into the one in sctp_userreq.c
620  * since they do the same thing and now we lookup with a sockaddr
621  */
622 #ifdef __FreeBSD__
623 static int
624 sctp6_getcred(SYSCTL_HANDLER_ARGS)
625 {
626         struct sockaddr_in6 addrs[2];
627         struct sctp_inpcb *inp;
628         struct sctp_nets *net;
629         struct sctp_tcb *stcb;
630         int error;
631
632 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
633         error = suser(req->td);
634 #else
635         error = suser(req->p);
636 #endif
637         if (error)
638                 return (error);
639
640         if (req->newlen != sizeof(addrs))
641                 return (EINVAL);
642         if (req->oldlen != sizeof(struct ucred))
643                 return (EINVAL);
644         error = SYSCTL_IN(req, addrs, sizeof(addrs));
645         if (error)
646                 return (error);
647         crit_enter();
648
649         stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
650                                            sin6tosa(&addrs[1]),
651                                            &inp, &net, 1);
652         if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
653                 error = ENOENT;
654                 if (inp) {
655                         SCTP_INP_WLOCK(inp);
656                         SCTP_INP_DECR_REF(inp);
657                         SCTP_INP_WUNLOCK(inp);
658                 }
659                 goto out;
660         }
661         error = SYSCTL_OUT(req, inp->sctp_socket->so_cred,
662                            sizeof(struct ucred));
663
664         SCTP_TCB_UNLOCK (stcb);
665 out:
666         crit_exit();
667         return (error);
668 }
669
670 SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
671             0, 0,
672             sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
673
674 #endif
675
676 /*
677  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
678  *       will sofree() it when we return.
679  */
680 static void
681 sctp6_abort(netmsg_t msg)
682 {
683         struct socket *so = msg->abort.base.nm_so;
684         struct sctp_inpcb *inp;
685         int error;
686
687         inp = (struct sctp_inpcb *)so->so_pcb;
688         if (inp) {
689                 soisdisconnected(so);
690                 sctp_inpcb_free(inp, 1);
691                 error = 0;
692         } else {
693                 error = EINVAL;
694         }
695         lwkt_replymsg(&msg->lmsg, error);
696 }
697
698 static void
699 sctp6_attach(netmsg_t msg)
700 {
701         struct socket *so = msg->attach.base.nm_so;
702         struct in6pcb *inp6;
703         int error;
704         struct sctp_inpcb *inp;
705
706         inp = (struct sctp_inpcb *)so->so_pcb;
707         if (inp != NULL) {
708                 error = EINVAL;
709                 goto out;
710         }
711
712         if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
713                 error = soreserve(so, sctp_sendspace, sctp_recvspace, NULL);
714                 if (error)
715                         goto out;
716         }
717         crit_enter();
718         error = sctp_inpcb_alloc(so);
719         crit_exit();
720         if (error)
721                 goto out;
722         inp = (struct sctp_inpcb *)so->so_pcb;
723         inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;     /* I'm v6! */
724         inp6 = (struct in6pcb *)inp;
725
726         inp6->in6p_hops = -1;           /* use kernel default */
727         inp6->in6p_cksum = -1;  /* just to be sure */
728 #ifdef INET
729         /*
730          * XXX: ugly!!
731          * IPv4 TTL initialization is necessary for an IPv6 socket as well,
732          * because the socket may be bound to an IPv6 wildcard address,
733          * which may match an IPv4-mapped IPv6 address.
734          */
735 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
736         inp6->inp_ip_ttl = ip_defttl;
737 #else
738         inp->inp_ip_ttl = ip_defttl;
739 #endif
740 #endif
741         /*
742          * Hmm what about the IPSEC stuff that is missing here but
743          * in sctp_attach()?
744          */
745         error = 0;
746 out:
747         lwkt_replymsg(&msg->lmsg, error);
748 }
749
750 static void
751 sctp6_bind(netmsg_t msg)
752 {
753         int error;
754
755         error = sctp6_bind_oncpu(msg->bind.base.nm_so,
756                                  msg->bind.nm_nam,
757                                  msg->bind.nm_td);
758         lwkt_replymsg(&msg->lmsg, error);
759 }
760
761 static int
762 sctp6_bind_oncpu(struct socket *so, struct sockaddr *addr, thread_t td)
763 {
764         struct sctp_inpcb *inp;
765         int error;
766
767         inp = (struct sctp_inpcb *)so->so_pcb;
768         if (inp == NULL) {
769                 error = EINVAL;
770                 goto out;
771         }
772
773         if (addr != NULL) {
774                 if (addr->sa_family == AF_INET) {
775                         /* can't bind v4 addr to v6 only socket! */
776                         error = EINVAL;
777                         goto out;
778                 } else {
779                         struct sockaddr_in6 *sin6_p;
780                         sin6_p = (struct sockaddr_in6 *)addr;
781
782                         if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
783                                 /* can't bind v4-mapped addrs either! */
784                                 /* NOTE: we don't support SIIT */
785                                 error = EINVAL;
786                                 goto out;
787                         }
788                 }
789         }
790         crit_enter();
791         error = sctp_inpcb_bind(so, addr, td);
792         crit_exit();
793 out:
794         return error;
795 }
796
797 /*This could be made common with sctp_detach() since they are identical */
798 static void
799 sctp6_detach(netmsg_t msg)
800 {
801         struct socket *so = msg->detach.base.nm_so;
802         struct sctp_inpcb *inp;
803         int error;
804
805         inp = (struct sctp_inpcb *)so->so_pcb;
806         if (inp == NULL) {
807                 error = EINVAL;
808                 goto out;
809         }
810         crit_enter();
811         if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
812             (so->so_rcv.ssb_cc > 0))
813                 sctp_inpcb_free(inp, 1);
814         else
815                 sctp_inpcb_free(inp, 0);
816         crit_exit();
817         error = 0;
818 out:
819         lwkt_replymsg(&msg->lmsg, error);
820 }
821
822 static void
823 sctp6_disconnect(netmsg_t msg)
824 {
825         struct socket *so = msg->disconnect.base.nm_so;
826         struct sctp_inpcb *inp;
827         int error;
828
829         crit_enter();
830         inp = (struct sctp_inpcb *)so->so_pcb;
831         if (inp == NULL) {
832                 crit_exit();
833                 error = ENOTCONN;
834                 goto out;
835         }
836         if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
837                 if (LIST_EMPTY(&inp->sctp_asoc_list)) {
838                         /* No connection */
839                         crit_exit();
840                         error = ENOTCONN;
841                 } else {
842                         int some_on_streamwheel = 0;
843                         struct sctp_association *asoc;
844                         struct sctp_tcb *stcb;
845
846                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
847                         if (stcb == NULL) {
848                                 crit_exit();
849                                 error = EINVAL;
850                                 goto out;
851                         }
852                         asoc = &stcb->asoc;
853                         if (!TAILQ_EMPTY(&asoc->out_wheel)) {
854                                 /* Check to see if some data queued */
855                                 struct sctp_stream_out *outs;
856                                 TAILQ_FOREACH(outs, &asoc->out_wheel,
857                                               next_spoke) {
858                                         if (!TAILQ_EMPTY(&outs->outqueue)) {
859                                                 some_on_streamwheel = 1;
860                                                 break;
861                                         }
862                                 }
863                         }
864
865                         if (TAILQ_EMPTY(&asoc->send_queue) &&
866                             TAILQ_EMPTY(&asoc->sent_queue) &&
867                             (some_on_streamwheel == 0)) {
868                                 /* nothing queued to send, so I'm done... */
869                                 if ((SCTP_GET_STATE(asoc) !=
870                                      SCTP_STATE_SHUTDOWN_SENT) &&
871                                     (SCTP_GET_STATE(asoc) !=
872                                      SCTP_STATE_SHUTDOWN_ACK_SENT)) {
873                                         /* only send SHUTDOWN the first time */
874 #ifdef SCTP_DEBUG
875                                         if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
876                                                 kprintf("%s:%d sends a shutdown\n",
877                                                        __FILE__,
878                                                        __LINE__
879                                                         );
880                                         }
881 #endif
882                                         sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
883                                         sctp_chunk_output(stcb->sctp_ep, stcb, 1);
884                                         asoc->state = SCTP_STATE_SHUTDOWN_SENT;
885                                         sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
886                                                          stcb->sctp_ep, stcb,
887                                                          asoc->primary_destination);
888                                         sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
889                                                          stcb->sctp_ep, stcb,
890                                                          asoc->primary_destination);
891                                 }
892                         } else {
893                                 /*
894                                  * we still got (or just got) data to send,
895                                  * so set SHUTDOWN_PENDING
896                                  */
897                                 /*
898                                  * XXX sockets draft says that MSG_EOF should
899                                  * be sent with no data.  currently, we will
900                                  * allow user data to be sent first and move
901                                  * to SHUTDOWN-PENDING
902                                  */
903                                 asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
904                         }
905                         crit_exit();
906                         error = 0;
907                 }
908         } else {
909                 /* UDP model does not support this */
910                 crit_exit();
911                 error = EOPNOTSUPP;
912         }
913 out:
914         lwkt_replymsg(&msg->lmsg, error);
915 }
916
917 static
918 void
919 sctp6_send(netmsg_t msg)
920 {
921         struct socket *so = msg->send.base.nm_so;
922         struct mbuf *m = msg->send.nm_m;
923         struct mbuf *control = msg->send.nm_control;
924         struct sockaddr *addr = msg->send.nm_addr;
925         struct sctp_inpcb *inp;
926         struct in6pcb *inp6;
927         int flags = msg->send.nm_flags;
928 #ifdef INET
929         struct sockaddr_in6 *sin6;
930 #endif /* INET */
931         int error;
932         /* No SPL needed since sctp_output does this */
933
934         inp = (struct sctp_inpcb *)so->so_pcb;
935         if (inp == NULL) {
936                 if (control) {
937                         m_freem(control);
938                         control = NULL;
939                 }
940                 m_freem(m);
941                 error = EINVAL;
942                 goto out;
943         }
944         inp6 = (struct in6pcb *)inp;
945         /* For the TCP model we may get a NULL addr, if we
946          * are a connected socket thats ok.
947          */
948         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
949             (addr == NULL)) {
950                 goto connected_type;
951         }
952         if (addr == NULL) {
953                 m_freem(m);
954                 if (control) {
955                         m_freem(control);
956                         control = NULL;
957                 }
958                 error = EDESTADDRREQ;
959                 goto out;
960         }
961
962 #ifdef INET
963         sin6 = (struct sockaddr_in6 *)addr;
964         /*
965          * We discard datagrams destined to a v4 addr or v4-mapped addr
966          */
967         if (addr->sa_family == AF_INET) {
968                 error = EINVAL;
969                 goto out;
970         }
971         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
972                 /* mapped addresses aren't enabled */
973                 error = EINVAL;
974                 goto out;
975         }
976 #endif /* INET */
977 connected_type:
978         /* now what about control */
979         if (control) {
980                 if (inp->control) {
981                         kprintf("huh? control set?\n");
982                         m_freem(inp->control);
983                         inp->control = NULL;
984                 }
985                 inp->control = control;
986         }
987         /* add it in possibly */
988         if ((inp->pkt) &&
989             (inp->pkt->m_flags & M_PKTHDR)) {
990                 struct mbuf *x;
991                 int c_len;
992
993                 c_len = 0;
994                 /* How big is it */
995                 for (x=m;x;x = x->m_next) {
996                         c_len += x->m_len;
997                 }
998                 inp->pkt->m_pkthdr.len += c_len;
999         }
1000         /* Place the data */
1001         if (inp->pkt) {
1002                 inp->pkt_last->m_next = m;
1003                 inp->pkt_last = m;
1004         } else {
1005                 inp->pkt_last = inp->pkt = m;
1006         }
1007         if (
1008 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1009             /* FreeBSD and MacOSX uses a flag passed */
1010             (!(flags & PRUS_MORETOCOME))
1011 #elif defined(__NetBSD__)
1012             /* NetBSD uses the so_state field */
1013             (!(so->so_state & SS_MORETOCOME))
1014 #else
1015             1   /* Open BSD does not have any "more to come" indication */
1016 #endif
1017             ) {
1018                 /*
1019                  * note with the current version this code will only be
1020                  * used by OpenBSD, NetBSD and FreeBSD have methods for
1021                  * re-defining sosend() to use sctp_sosend().  One can
1022                  * optionaly switch back to this code (by changing back
1023                  * the defininitions but this is not advisable.
1024                  */
1025                 error = sctp_output(inp, inp->pkt, addr,
1026                                     inp->control, msg->send.nm_td, flags);
1027                 inp->pkt = NULL;
1028                 inp->control = NULL;
1029         } else {
1030                 error = 0;
1031         }
1032 out:
1033         lwkt_replymsg(&msg->lmsg, error);
1034 }
1035
1036 static void
1037 sctp6_connect(netmsg_t msg)
1038 {
1039         struct socket *so = msg->connect.base.nm_so;
1040         struct sockaddr *addr = msg->connect.nm_nam;
1041         struct sctp_inpcb *inp;
1042         struct in6pcb *inp6;
1043         struct sctp_tcb *stcb;
1044 #ifdef INET
1045         struct sockaddr_in6 *sin6;
1046 #endif /* INET */
1047         int error = 0;
1048
1049         crit_enter();
1050         inp6 = (struct in6pcb *)so->so_pcb;
1051         inp = (struct sctp_inpcb *)so->so_pcb;
1052         if (inp == NULL) {
1053                 crit_exit();
1054                 error = ECONNRESET;     /* I made the same as TCP since
1055                                          * we are not setup? */
1056                 goto out;
1057         }
1058         SCTP_ASOC_CREATE_LOCK(inp);
1059         SCTP_INP_RLOCK(inp);
1060         if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1061             SCTP_PCB_FLAGS_UNBOUND) {
1062                 /* Bind a ephemeral port */
1063                 SCTP_INP_RUNLOCK(inp);
1064                 error = sctp6_bind_oncpu(so, NULL, msg->connect.nm_td);
1065                 if (error) {
1066                         crit_exit();
1067                         SCTP_ASOC_CREATE_UNLOCK(inp);
1068                         goto out;
1069                 }
1070                 SCTP_INP_RLOCK(inp);
1071         }
1072
1073         if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1074             (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1075                 /* We are already connected AND the TCP model */
1076                 crit_exit();
1077                 SCTP_INP_RUNLOCK(inp);
1078                 SCTP_ASOC_CREATE_UNLOCK(inp);
1079                 error = EADDRINUSE;
1080                 goto out;
1081         }
1082
1083 #ifdef INET
1084         sin6 = (struct sockaddr_in6 *)addr;
1085         /*
1086          * Ignore connections destined to a v4 addr or v4-mapped addr
1087          */
1088         if (addr->sa_family == AF_INET) {
1089                 crit_exit();
1090                 SCTP_INP_RUNLOCK(inp);
1091                 SCTP_ASOC_CREATE_UNLOCK(inp);
1092                 error = EINVAL;
1093                 goto out;
1094         }
1095         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1096                 /* mapped addresses aren't enabled */
1097                 crit_exit();
1098                 SCTP_INP_RUNLOCK(inp);
1099                 SCTP_ASOC_CREATE_UNLOCK(inp);
1100                 error = EINVAL;
1101                 goto out;
1102         } else
1103 #endif /* INET */
1104                 addr = addr;    /* for true v6 address case */
1105
1106         /* Now do we connect? */
1107         if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1108                 stcb = LIST_FIRST(&inp->sctp_asoc_list);
1109                 if (stcb)
1110                         SCTP_TCB_UNLOCK (stcb);
1111                 SCTP_INP_RUNLOCK(inp);
1112         }else {
1113                 SCTP_INP_RUNLOCK(inp);
1114                 SCTP_INP_WLOCK(inp);
1115                 SCTP_INP_INCR_REF(inp);
1116                 SCTP_INP_WUNLOCK(inp);
1117                 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
1118                 if (stcb == NULL) {
1119                         SCTP_INP_WLOCK(inp);
1120                         SCTP_INP_DECR_REF(inp);
1121                         SCTP_INP_WUNLOCK(inp);
1122                 }
1123         }
1124
1125         if (stcb != NULL) {
1126                 /* Already have or am bring up an association */
1127                 SCTP_ASOC_CREATE_UNLOCK(inp);
1128                 SCTP_TCB_UNLOCK (stcb);
1129                 crit_exit();
1130                 error = EALREADY;
1131                 goto out;
1132         }
1133         /* We are GOOD to go */
1134         stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0);
1135         SCTP_ASOC_CREATE_UNLOCK(inp);
1136         if (stcb == NULL) {
1137                 /* Gak! no memory */
1138                 crit_exit();
1139                 goto out;
1140         }
1141         if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1142                 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1143                 /* Set the connected flag so we can queue data */
1144                 soisconnecting(so);
1145         }
1146         stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1147         SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1148         sctp_send_initiate(inp, stcb);
1149         SCTP_TCB_UNLOCK (stcb);
1150         crit_exit();
1151 out:
1152         lwkt_replymsg(&msg->lmsg, error);
1153 }
1154
1155 static int
1156 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1157 sctp6_getaddr(struct socket *so, struct sockaddr **addr)
1158 {
1159         struct sockaddr_in6 *sin6;
1160 #else
1161 sctp6_getaddr(struct socket *so, struct mbuf *nam)
1162 {
1163         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1164 #endif
1165         struct sctp_inpcb *inp;
1166         /*
1167          * Do the malloc first in case it blocks.
1168          */
1169 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1170         sin6 = kmalloc(sizeof *sin6, M_SONAME, M_WAITOK | M_ZERO);
1171 #else
1172         nam->m_len = sizeof(*sin6);
1173 #endif
1174         bzero(sin6, sizeof(*sin6));
1175         sin6->sin6_family = AF_INET6;
1176         sin6->sin6_len = sizeof(*sin6);
1177
1178         inp = (struct sctp_inpcb *)so->so_pcb;
1179         if (!inp) {
1180 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1181                 kfree(sin6, M_SONAME);
1182 #endif
1183                 return ECONNRESET;
1184         }
1185
1186         sin6->sin6_port = inp->sctp_lport;
1187         if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1188                 /* For the bound all case you get back 0 */
1189                 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1190                         struct sctp_tcb *stcb;
1191                         struct sockaddr_in6 *sin_a6;
1192                         struct sctp_nets *net;
1193                         int fnd;
1194
1195                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1196                         if (stcb == NULL) {
1197                                 goto notConn6;
1198                         }
1199                         fnd = 0;
1200                         sin_a6 = NULL;
1201                         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1202                                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1203                                 if (sin_a6->sin6_family == AF_INET6) {
1204                                         fnd = 1;
1205                                         break;
1206                                 }
1207                         }
1208                         if ((!fnd) || (sin_a6 == NULL)) {
1209                                 /* punt */
1210                                 goto notConn6;
1211                         }
1212                         sin6->sin6_addr = sctp_ipv6_source_address_selection(
1213                             inp, stcb, (struct route *)&net->ro, net, 0);
1214
1215                 } else {
1216                         /* For the bound all case you get back 0 */
1217                 notConn6:
1218                         memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1219                 }
1220         } else {
1221                 /* Take the first IPv6 address in the list */
1222                 struct sctp_laddr *laddr;
1223                 int fnd = 0;
1224                 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1225                         if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
1226                                 struct sockaddr_in6 *sin_a;
1227                                 sin_a = (struct sockaddr_in6 *)laddr->ifa->ifa_addr;
1228                                 sin6->sin6_addr = sin_a->sin6_addr;
1229                                 fnd = 1;
1230                                 break;
1231                         }
1232                 }
1233                 if (!fnd) {
1234 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1235                         kfree(sin6, M_SONAME);
1236 #endif
1237                         return ENOENT;
1238                 }
1239         }
1240         /* Scoping things for v6 */
1241         if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
1242                 /* skip ifp check below */
1243                 in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1244         else
1245                 sin6->sin6_scope_id = 0;        /*XXX*/
1246 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1247         (*addr) = (struct sockaddr *)sin6;
1248 #endif
1249         return (0);
1250 }
1251
1252 static int
1253 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1254 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1255 {
1256         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
1257 #else
1258 sctp6_peeraddr(struct socket *so, struct mbuf *nam)
1259 {
1260         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1261 #endif
1262         int fnd;
1263         struct sockaddr_in6 *sin_a6;
1264         struct sctp_inpcb *inp;
1265         struct sctp_tcb *stcb;
1266         struct sctp_nets *net;
1267         /*
1268          * Do the malloc first in case it blocks.
1269          */
1270         inp = (struct sctp_inpcb *)so->so_pcb;
1271         if (!(inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1272                 /* UDP type and listeners will drop out here */
1273                 return (ENOTCONN);
1274         }
1275 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1276         sin6 = kmalloc(sizeof *sin6, M_SONAME, M_WAITOK | M_ZERO);
1277 #else
1278         nam->m_len = sizeof(*sin6);
1279 #endif
1280         bzero(sin6, sizeof(*sin6));
1281         sin6->sin6_family = AF_INET6;
1282         sin6->sin6_len = sizeof(*sin6);
1283
1284         /* We must recapture incase we blocked */
1285         inp = (struct sctp_inpcb *)so->so_pcb;
1286         if (!inp) {
1287 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1288                 kfree(sin6, M_SONAME);
1289 #endif
1290                 return ECONNRESET;
1291         }
1292         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1293         if (stcb == NULL) {
1294 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1295                 kfree(sin6, M_SONAME);
1296 #endif
1297                 return ECONNRESET;
1298         }
1299         fnd = 0;
1300         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1301                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1302                 if (sin_a6->sin6_family == AF_INET6) {
1303                         fnd = 1;
1304                         sin6->sin6_port = stcb->rport;
1305                         sin6->sin6_addr = sin_a6->sin6_addr;
1306                         break;
1307                 }
1308         }
1309         if (!fnd) {
1310                 /* No IPv4 address */
1311 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1312                 kfree(sin6, M_SONAME);
1313 #endif
1314                 return ENOENT;
1315         }
1316         in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1317 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1318         *addr = (struct sockaddr *)sin6;
1319 #endif
1320         return (0);
1321 }
1322
1323 static void
1324 sctp6_in6getaddr(netmsg_t msg)
1325 {
1326         struct socket *so = msg->sockaddr.base.nm_so;
1327         struct sockaddr **nam = msg->sockaddr.nm_nam;
1328         struct in6pcb *inp6 = sotoin6pcb(so);
1329         int error;
1330
1331         if (inp6 == NULL) {
1332                 error = EINVAL;
1333                 goto out;
1334         }
1335
1336         crit_enter();
1337         /* allow v6 addresses precedence */
1338         error = sctp6_getaddr(so, nam);
1339         crit_exit();
1340 out:
1341         lwkt_replymsg(&msg->lmsg, error);
1342 }
1343
1344 static void
1345 sctp6_getpeeraddr(netmsg_t msg)
1346 {
1347         struct socket *so = msg->peeraddr.base.nm_so;
1348         struct sockaddr **nam = msg->peeraddr.nm_nam;
1349         struct in6pcb *inp6 = sotoin6pcb(so);
1350         int error;
1351
1352         if (inp6 == NULL) {
1353                 error = EINVAL;
1354                 goto out;
1355         }
1356
1357         crit_enter();
1358         /* allow v6 addresses precedence */
1359         error = sctp6_peeraddr(so, nam);
1360         crit_exit();
1361 out:
1362         lwkt_replymsg(&msg->lmsg, error);
1363 }
1364
1365 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1366 struct pr_usrreqs sctp6_usrreqs = {
1367         .pru_abort = sctp6_abort,
1368         .pru_accept = sctp_accept,
1369         .pru_attach = sctp6_attach,
1370         .pru_bind = sctp6_bind,
1371         .pru_connect = sctp6_connect,
1372         .pru_connect2 = pr_generic_notsupp,
1373         .pru_control = in6_control_dispatch,
1374         .pru_detach = sctp6_detach,
1375         .pru_disconnect = sctp6_disconnect,
1376         .pru_listen = sctp_listen,
1377         .pru_peeraddr = sctp6_getpeeraddr,
1378         .pru_rcvd = sctp_usr_recvd,
1379         .pru_rcvoob = pr_generic_notsupp,
1380         .pru_send = sctp6_send,
1381         .pru_sense = pru_sense_null,
1382         .pru_shutdown = sctp_shutdown,
1383         .pru_sockaddr = sctp6_in6getaddr,
1384         .pru_sosend = sctp_sosend,
1385         .pru_soreceive = soreceive
1386 };
1387
1388 #else
1389
1390 #error x
1391
1392 int
1393 sctp6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
1394              struct mbuf *control, struct proc *p)
1395 {
1396         int s;
1397         int error = 0;
1398         int family;
1399
1400 #if defined(__OpenBSD__)
1401         p = curproc;
1402 #endif
1403         s = splsoftnet();
1404         family = so->so_proto->pr_domain->dom_family;
1405
1406         if (req == PRU_CONTROL) {
1407                 switch (family) {
1408                 case PF_INET:
1409                         error = in_control((long)m, (caddr_t)nam,
1410                             (struct ifnet *)control
1411 #if defined(__NetBSD__)
1412                              , p
1413 #endif
1414                              );
1415 #ifdef INET6
1416                 case PF_INET6:
1417                         error = in6_control((long)m, (caddr_t)nam,
1418                             (struct ifnet *)control, p);
1419 #endif
1420                 default:
1421                         error = EAFNOSUPPORT;
1422                 }
1423                 splx(s);
1424                 return (error);
1425         }
1426 #ifdef __NetBSD__
1427         if (req == PRU_PURGEIF) {
1428                 struct ifnet *ifn;
1429                 struct ifaddr *ifa;
1430                 ifn = (struct ifnet *)control;
1431                 TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
1432                         if (ifa->ifa_addr->sa_family == family) {
1433                                 sctp_delete_ip_address(ifa);
1434                         }
1435                 }
1436                 switch (family) {
1437                 case PF_INET:
1438                         in_purgeif (ifn);
1439                         break;
1440 #ifdef INET6
1441                 case PF_INET6:
1442                         in6_purgeif (ifn);
1443                         break;
1444 #endif
1445                 default:
1446                         splx(s);
1447                         return (EAFNOSUPPORT);
1448                 }
1449                 splx(s);
1450                 return (0);
1451         }
1452 #endif
1453         switch (req) {
1454         case PRU_ATTACH:
1455                 error = sctp6_attach(so, family, p);
1456                 break;
1457         case PRU_DETACH:
1458                 error = sctp6_detach(so);
1459                 break;
1460         case PRU_BIND:
1461                 if (nam == NULL)
1462                         return (EINVAL);
1463                 error = sctp6_bind(so, nam, p);
1464                 break;
1465         case PRU_LISTEN:
1466                 error = sctp_listen(so, p);
1467                 break;
1468         case PRU_CONNECT:
1469                 if (nam == NULL)
1470                         return (EINVAL);
1471                 error = sctp6_connect(so, nam, p);
1472                 break;
1473         case PRU_DISCONNECT:
1474                 error = sctp6_disconnect(so);
1475                 break;
1476         case PRU_ACCEPT:
1477                 if (nam == NULL)
1478                         return (EINVAL);
1479                 error = sctp_accept(so, nam);
1480                 break;
1481         case PRU_SHUTDOWN:
1482                 error = sctp_shutdown(so);
1483                 break;
1484
1485         case PRU_RCVD:
1486                 /*
1487                  * For OpenBSD and NetBSD, this is real ugly. The (mbuf *)
1488                  * nam that is passed (by soreceive()) is the int flags
1489                  * cast as a (mbuf *) yuck!
1490                  */
1491                 error = sctp_usr_recvd(so, (int)((long)nam));
1492                 break;
1493
1494         case PRU_SEND:
1495                 /* Flags are ignored */
1496                 error = sctp6_send(so, 0, m, nam, control, p);
1497                 break;
1498         case PRU_ABORT:
1499                 error = sctp6_abort(so);
1500                 break;
1501
1502         case PRU_SENSE:
1503                 error = 0;
1504                 break;
1505         case PRU_RCVOOB:
1506                 error = EAFNOSUPPORT;
1507                 break;
1508         case PRU_SENDOOB:
1509                 error = EAFNOSUPPORT;
1510                 break;
1511         case PRU_PEERADDR:
1512                 error = sctp6_getpeeraddr(so, nam);
1513                 break;
1514         case PRU_SOCKADDR:
1515                 error = sctp6_in6getaddr(so, nam);
1516                 break;
1517         case PRU_SLOWTIMO:
1518                 error = 0;
1519                 break;
1520         default:
1521                 break;
1522         }
1523         splx(s);
1524         return (error);
1525 }
1526 #endif