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