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