/dev/random was almost always returning 0 bytes. This was due to several
[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.5 2006/01/14 11:44:25 swildner 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 #include <sys/thread2.h>
69 #include <net/if.h>
70 #include <net/route.h>
71 #include <net/if_types.h>
72 #include <netinet/in.h>
73 #include <netinet/in_systm.h>
74 #include <netinet/ip.h>
75 #include <netinet/in_pcb.h>
76 #include <netinet/in_var.h>
77 #include <netinet/ip_var.h>
78 #include <netinet/sctp_pcb.h>
79 #include <netinet/sctp_header.h>
80 #include <netinet/sctp_var.h>
81 #include <netinet/sctputil.h>
82 #include <netinet/sctp_output.h>
83 #include <netinet/sctp_input.h>
84 #include <netinet/sctp_asconf.h>
85 #include <netinet6/ip6_var.h>
86 #include <netinet/ip6.h>
87 #if !defined(__OpenBSD__)
88 #include <netinet6/in6_pcb.h>
89 #endif
90 #include <netinet/icmp6.h>
91 #include <netinet6/sctp6_var.h>
92 #include <netinet6/ip6protosw.h>
93 #include <netinet6/nd6.h>
94
95 #ifdef IPSEC
96 #ifndef __OpenBSD__
97 #include <netinet6/ipsec.h>
98 #else
99 #undef IPSEC
100 #endif
101 #endif /*IPSEC*/
102
103 #if defined(NFAITH) && NFAITH > 0
104 #include <net/if_faith.h>
105 #endif
106
107 #include <net/net_osdep.h>
108
109 extern struct protosw inetsw[];
110
111 #if defined(HAVE_NRL_INPCB) || defined(__FreeBSD__) || defined(__DragonFly__)
112 #ifndef in6pcb
113 #define in6pcb          inpcb
114 #endif
115 #ifndef sotoin6pcb
116 #define sotoin6pcb      sotoinpcb
117 #endif
118 #endif
119
120 #ifdef SCTP_DEBUG
121 extern u_int32_t sctp_debug_on;
122 #endif
123
124 static  int sctp6_detach(struct socket *so);
125
126 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
127 extern void in6_sin_2_v4mapsin6 (struct sockaddr_in *sin,
128                                  struct sockaddr_in6 *sin6);
129 extern void in6_sin6_2_sin (struct sockaddr_in *,
130                             struct sockaddr_in6 *sin6);
131 extern void in6_sin6_2_sin_in_sock(struct sockaddr *nam);
132
133 /*
134  * Convert sockaddr_in6 to sockaddr_in.  Original sockaddr_in6 must be
135  * v4 mapped addr or v4 compat addr
136  */
137 void
138 in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
139 {
140         bzero(sin, sizeof(*sin));
141         sin->sin_len = sizeof(struct sockaddr_in);
142         sin->sin_family = AF_INET;
143         sin->sin_port = sin6->sin6_port;
144         sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
145 }
146
147 /* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
148 void
149 in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
150 {
151         bzero(sin6, sizeof(*sin6));
152         sin6->sin6_len = sizeof(struct sockaddr_in6);
153         sin6->sin6_family = AF_INET6;
154         sin6->sin6_port = sin->sin_port;
155         sin6->sin6_addr.s6_addr32[0] = 0;
156         sin6->sin6_addr.s6_addr32[1] = 0;
157         sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
158         sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
159 }
160
161 /* Convert sockaddr_in6 into sockaddr_in. */
162 void
163 in6_sin6_2_sin_in_sock(struct sockaddr *nam)
164 {
165         struct sockaddr_in *sin_p;
166         struct sockaddr_in6 sin6;
167
168         /* save original sockaddr_in6 addr and convert it to sockaddr_in  */
169         sin6 = *(struct sockaddr_in6 *)nam;
170         sin_p = (struct sockaddr_in *)nam;
171         in6_sin6_2_sin(sin_p, &sin6);
172 }
173
174 #endif /* !(__FreeBSD__ || __APPLE__) */
175
176 extern int sctp_no_csum_on_loopback;
177
178 int
179 #if defined(__APPLE__)
180 sctp6_input(struct mbuf **mp, int *offp)
181 #else
182 sctp6_input(struct mbuf **mp, int *offp, int proto)
183 #endif
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                 printf("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                                 printf("Bad CSUM on SCTP packet calc_check:%x check:%x  m:%x mlen:%d iphlen:%d\n",
275                                        calc_check, check, (u_int)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((struct sctp_inpcb *)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                 printf("V6 Find the association\n");
304         }
305 #endif
306         stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
307             sh, ch, &in6p, &net);
308         /* in6p's ref-count increased */
309         if (in6p == NULL) {
310                 struct sctp_init_chunk *init_chk, chunk_buf;
311
312                 sctp_pegs[SCTP_NOPORTS]++;
313                 if (ch->chunk_type == SCTP_INITIATION) {
314                         /* we do a trick here to get the INIT tag,
315                          * dig in and get the tag from the INIT and
316                          * put it in the common header.
317                          */
318                         init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
319                             iphlen + sizeof(*sh), sizeof(*init_chk),
320                             (u_int8_t *)&chunk_buf);
321                         sh->v_tag = init_chk->init.initiate_tag;
322                 }
323                 sctp_send_abort(m, iphlen, sh, 0, NULL);
324                 goto bad;
325         } else if (stcb == NULL) {
326                 refcount_up = 1;
327         }
328         in6p_ip = (struct inpcb *)in6p;
329 #ifdef IPSEC
330         /*
331          * Check AH/ESP integrity.
332          */
333 #ifdef __OpenBSD__
334         {
335                 struct inpcb *i_inp;
336                 struct m_tag *mtag;
337                 struct tdb_ident *tdbi;
338                 struct tdb *tdb;
339                 int error;
340
341                 /* Find most recent IPsec tag */
342                 i_inp = (struct inpcb *)in6p;
343                 mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
344                 crit_enter();
345                 if (mtag != NULL) {
346                         tdbi = (struct tdb_ident *)(mtag + 1);
347                         tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
348                 } else
349                         tdb = NULL;
350
351                 ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
352                     tdb, i_inp);
353                 if (error) {
354                         crit_exit();
355                         goto bad;
356                 }
357
358                 /* Latch SA */
359                 if (i_inp->inp_tdb_in != tdb) {
360                         if (tdb) {
361                                 tdb_add_inp(tdb, i_inp, 1);
362                                 if (i_inp->inp_ipo == NULL) {
363                                         i_inp->inp_ipo = ipsec_add_policy(i_inp,
364                                             af, IPSP_DIRECTION_OUT);
365                                         if (i_inp->inp_ipo == NULL) {
366                                                 crit_exit();
367                                                 goto bad;
368                                         }
369                                 }
370                                 if (i_inp->inp_ipo->ipo_dstid == NULL &&
371                                     tdb->tdb_srcid != NULL) {
372                                         i_inp->inp_ipo->ipo_dstid =
373                                             tdb->tdb_srcid;
374                                         tdb->tdb_srcid->ref_count++;
375                                 }
376                                 if (i_inp->inp_ipsec_remotecred == NULL &&
377                                     tdb->tdb_remote_cred != NULL) {
378                                         i_inp->inp_ipsec_remotecred =
379                                             tdb->tdb_remote_cred;
380                                         tdb->tdb_remote_cred->ref_count++;
381                                 }
382                                 if (i_inp->inp_ipsec_remoteauth == NULL &&
383                                     tdb->tdb_remote_auth != NULL) {
384                                         i_inp->inp_ipsec_remoteauth =
385                                             tdb->tdb_remote_auth;
386                                         tdb->tdb_remote_auth->ref_count++;
387                                 }
388                         } else { /* Just reset */
389                                 TAILQ_REMOVE(&i_inp->inp_tdb_in->tdb_inp_in,
390                                     i_inp, binp_tdb_in_next);
391                                 i_inp->inp_tdb_in = NULL;
392                         }
393                 }
394                 crit_exit();
395         }
396 #else
397         if (ipsec6_in_reject_so(m, in6p->sctp_socket)) {
398 /* XXX */
399 #ifndef __APPLE__
400                 /* FIX ME: need to find right stat for __APPLE__ */
401                 ipsec6stat.in_polvio++;
402 #endif
403                 goto bad;
404         }
405 #endif
406 #endif /*IPSEC*/
407
408         /*
409          * Construct sockaddr format source address.
410          * Stuff source address and datagram in user buffer.
411          */
412         if ((in6p->ip_inp.inp.inp_flags & INP_CONTROLOPTS)
413 #ifndef __OpenBSD__
414             || (in6p->sctp_socket->so_options & SO_TIMESTAMP)
415 #endif
416             ) {
417 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
418 #if (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version < 501113) || \
419     defined(__APPLE__) || defined(__DragonFly__)
420                 ip6_savecontrol(in6p_ip, &opts, ip6, m);
421 #elif __FreeBSD_version >= 440000 || (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version >= 501113)
422                 ip6_savecontrol(in6p_ip, m, &opts);
423 #else
424                 ip6_savecontrol(in6p_ip, m, &opts, NULL);
425 #endif
426 #else
427                 ip6_savecontrol((struct in6pcb *)in6p_ip, m, &opts);
428 #endif
429         }
430
431         /*
432          * CONTROL chunk processing
433          */
434         length = ntohs(ip6->ip6_plen) + iphlen;
435         offset -= sizeof(*ch);
436         ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
437         crit_enter();
438         sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
439             in6p, stcb, net, ecn_bits);
440         /* inp's ref-count reduced && stcb unlocked */
441         crit_exit();
442         /* XXX this stuff below gets moved to appropriate parts later... */
443         if (m)
444                 m_freem(m);
445         if (opts)
446                 m_freem(opts);
447
448         if ((in6p) && refcount_up){
449                 /* reduce ref-count */
450                 SCTP_INP_WLOCK(in6p);
451                 SCTP_INP_DECR_REF(in6p);
452                 SCTP_INP_WUNLOCK(in6p);
453         }
454
455         return IPPROTO_DONE;
456
457 bad:
458         if (stcb)
459                 SCTP_TCB_UNLOCK(stcb);
460
461         if ((in6p) && refcount_up){
462                 /* reduce ref-count */
463                 SCTP_INP_WLOCK(in6p);
464                 SCTP_INP_DECR_REF(in6p);
465                 SCTP_INP_WUNLOCK(in6p);
466         }
467         if (m)
468                 m_freem(m);
469         if (opts)
470                 m_freem(opts);
471         return IPPROTO_DONE;
472 }
473
474
475 static void
476 sctp6_notify_mbuf(struct sctp_inpcb *inp,
477                   struct icmp6_hdr *icmp6,
478                   struct sctphdr *sh,
479                   struct sctp_tcb *stcb,
480                   struct sctp_nets *net)
481 {
482         unsigned int nxtsz;
483
484         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
485             (icmp6 == NULL) || (sh == NULL)) {
486                 goto out;
487         }
488
489         /* First do we even look at it? */
490         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
491                 goto out;
492
493         if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
494                 /* not PACKET TO BIG */
495                 goto out;
496         }
497         /*
498          * ok we need to look closely. We could even get smarter and
499          * look at anyone that we sent to in case we get a different
500          * ICMP that tells us there is no way to reach a host, but for
501          * this impl, all we care about is MTU discovery.
502          */
503         nxtsz = ntohl(icmp6->icmp6_mtu);
504         /* Stop any PMTU timer */
505         sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
506
507         /* Adjust destination size limit */
508         if (net->mtu > nxtsz) {
509                 net->mtu = nxtsz;
510         }
511         /* now what about the ep? */
512         if (stcb->asoc.smallest_mtu > nxtsz) {
513                 struct sctp_tmit_chunk *chk;
514                 struct sctp_stream_out *strm;
515                 /* Adjust that too */
516                 stcb->asoc.smallest_mtu = nxtsz;
517                 /* now off to subtract IP_DF flag if needed */
518
519                 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
520                         if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
521                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
522                         }
523                 }
524                 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
525                         if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
526                                 /*
527                                  * For this guy we also mark for immediate
528                                  * resend since we sent to big of chunk
529                                  */
530                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
531                                 if (chk->sent != SCTP_DATAGRAM_RESEND)
532                                         stcb->asoc.sent_queue_retran_cnt++;
533                                 chk->sent = SCTP_DATAGRAM_RESEND;
534                                 chk->rec.data.doing_fast_retransmit = 0;
535
536                                 chk->sent = SCTP_DATAGRAM_RESEND;
537                                 /* Clear any time so NO RTT is being done */
538                                 chk->sent_rcv_time.tv_sec = 0;
539                                 chk->sent_rcv_time.tv_usec = 0;
540                                 stcb->asoc.total_flight -= chk->send_size;
541                                 net->flight_size -= chk->send_size;
542                         }
543                 }
544                 TAILQ_FOREACH(strm, &stcb->asoc.out_wheel, next_spoke) {
545                         TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) {
546                                 if ((chk->send_size+IP_HDR_SIZE) > nxtsz) {
547                                         chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
548                                 }
549                         }
550                 }
551         }
552         sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
553 out:
554         if (inp) {
555                 /* reduce inp's ref-count */
556                 SCTP_INP_WLOCK(inp);
557                 SCTP_INP_DECR_REF(inp);
558                 SCTP_INP_WUNLOCK(inp);
559         }
560         if (stcb)
561                 SCTP_TCB_UNLOCK(stcb);
562 }
563
564
565 void
566 sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
567 {
568         struct sctphdr sh;
569         struct ip6ctlparam *ip6cp = NULL;
570         int cm;
571
572         if (pktdst->sa_family != AF_INET6 ||
573             pktdst->sa_len != sizeof(struct sockaddr_in6))
574                 return;
575
576         if ((unsigned)cmd >= PRC_NCMDS)
577                 return;
578         if (PRC_IS_REDIRECT(cmd)) {
579                 d = NULL;
580         } else if (inet6ctlerrmap[cmd] == 0) {
581                 return;
582         }
583
584         /* if the parameter is from icmp6, decode it. */
585         if (d != NULL) {
586                 ip6cp = (struct ip6ctlparam *)d;
587         } else {
588                 ip6cp = (struct ip6ctlparam *)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 /* This is the same as the sctp_abort() could be made common */
727 static int
728 sctp6_abort(struct socket *so)
729 {
730         struct sctp_inpcb *inp;
731
732         inp = (struct sctp_inpcb *)so->so_pcb;
733         if (inp == 0)
734                 return EINVAL;  /* ??? possible? panic instead? */
735         soisdisconnected(so);
736         crit_enter();
737         sctp_inpcb_free(inp, 1);
738         crit_exit();
739         return 0;
740 }
741
742 static int
743 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
744 sctp6_attach(struct socket *so, int proto, struct thread *p)
745 #elif defined(__DragonFly__)
746 sctp6_attach(struct socket *so, int proto, struct pru_attach_info *ai)
747 #else
748 sctp6_attach(struct socket *so, int proto, struct proc *p)
749 #endif
750 {
751         struct in6pcb *inp6;
752         int error;
753         struct sctp_inpcb *inp;
754
755         inp = (struct sctp_inpcb *)so->so_pcb;
756         if (inp != NULL)
757                 return EINVAL;
758
759         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
760                 error = soreserve(so, sctp_sendspace, sctp_recvspace, NULL);
761                 if (error)
762                         return error;
763         }
764         crit_enter();
765         error = sctp_inpcb_alloc(so);
766         crit_exit();
767         if (error)
768                 return error;
769         inp = (struct sctp_inpcb *)so->so_pcb;
770         inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;     /* I'm v6! */
771         inp6 = (struct in6pcb *)inp;
772
773 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
774         inp6->inp_vflag |= INP_IPV6;
775 #else
776 #if defined(__OpenBSD__)
777         inp->ip_inp.inp.inp_flags |= INP_IPV6;
778 #else
779         inp->inp_vflag |=  INP_IPV6;
780 #endif
781 #endif
782 #if defined(__NetBSD__)
783         if (ip6_v6only) {
784                 inp6->in6p_flags |= IN6P_IPV6_V6ONLY;
785         }
786         so->so_send = sctp_sosend;
787 #endif
788         inp6->in6p_hops = -1;           /* use kernel default */
789         inp6->in6p_cksum = -1;  /* just to be sure */
790 #ifdef INET
791         /*
792          * XXX: ugly!!
793          * IPv4 TTL initialization is necessary for an IPv6 socket as well,
794          * because the socket may be bound to an IPv6 wildcard address,
795          * which may match an IPv4-mapped IPv6 address.
796          */
797 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
798         inp6->inp_ip_ttl = ip_defttl;
799 #else
800         inp->inp_ip_ttl = ip_defttl;
801 #endif
802 #endif
803         /*
804          * Hmm what about the IPSEC stuff that is missing here but
805          * in sctp_attach()?
806          */
807         return 0;
808 }
809
810 static int
811 #if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__DragonFly__)
812 sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
813 {
814 #else
815 #if defined(__FreeBSD__) || defined(__APPLE__)
816 sctp6_bind(struct socket *so, struct sockaddr *addr, struct proc *p)
817 {
818 #else
819 sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
820 {
821         struct sockaddr *addr = nam ?  mtod(nam, struct sockaddr *) : NULL;
822 #endif
823 #endif
824         struct sctp_inpcb *inp;
825         struct in6pcb *inp6;
826         int error;
827
828         inp = (struct sctp_inpcb *)so->so_pcb;
829         if (inp == 0)
830                 return EINVAL;
831
832         inp6 = (struct in6pcb *)inp;
833 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
834         inp6->inp_vflag &= ~INP_IPV4;
835         inp6->inp_vflag |= INP_IPV6;
836 #else
837 #if defined(__OpenBSD__)
838         inp->ip_inp.inp.inp_flags &= ~INP_IPV4;
839         inp->ip_inp.inp.inp_flags |= INP_IPV6;
840 #else
841         inp->inp_vflag &= ~INP_IPV4;
842         inp->inp_vflag |= INP_IPV6;
843 #endif
844 #endif
845         if (addr != NULL &&
846 #if defined(__OpenBSD__)
847              (0) /* we always do dual bind */
848 #elif defined (__NetBSD__)
849              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
850 #else
851              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
852 #endif
853              == 0) {
854                 if (addr->sa_family == AF_INET) {
855                         /* binding v4 addr to v6 socket, so reset flags */
856 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
857                         inp6->inp_vflag |= INP_IPV4;
858                         inp6->inp_vflag &= ~INP_IPV6;
859 #else
860 #if defined(__OpenBSD__)
861                         inp->ip_inp.inp.inp_flags |= INP_IPV4;
862                         inp->ip_inp.inp.inp_flags &= ~INP_IPV6;
863 #else
864                         inp->inp_vflag |= INP_IPV4;
865                         inp->inp_vflag &= ~INP_IPV6;
866 #endif
867 #endif
868                 } else {
869                         struct sockaddr_in6 *sin6_p;
870                         sin6_p = (struct sockaddr_in6 *)addr;
871
872                         if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
873 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
874                           inp6->inp_vflag |= INP_IPV4;
875 #else
876 #if defined(__OpenBSD__)
877                           inp->ip_inp.inp.inp_flags |= INP_IPV4;
878 #else
879                           inp->inp_vflag |= INP_IPV4;
880 #endif
881 #endif
882                         }
883                         else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
884                                 struct sockaddr_in sin;
885                                 in6_sin6_2_sin(&sin, sin6_p);
886 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
887                                 inp6->inp_vflag |= INP_IPV4;
888                                 inp6->inp_vflag &= ~INP_IPV6;
889 #else
890 #if defined(__OpenBSD__)
891                                 inp->ip_inp.inp.inp_flags |= INP_IPV4;
892                                 inp->ip_inp.inp.inp_flags &= ~INP_IPV6;
893
894 #else
895                                 inp->inp_vflag |= INP_IPV4;
896                                 inp->inp_vflag &= ~INP_IPV6;
897 #endif
898 #endif
899                                 crit_enter();
900                                 error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, p);
901                                 crit_exit();
902                                 return error;
903                         }
904                 }
905         } else if (addr != NULL) {
906                 /* IPV6_V6ONLY socket */
907                 if (addr->sa_family == AF_INET) {
908                         /* can't bind v4 addr to v6 only socket! */
909                         return EINVAL;
910                 } else {
911                         struct sockaddr_in6 *sin6_p;
912                         sin6_p = (struct sockaddr_in6 *)addr;
913
914                         if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr))
915                                 /* can't bind v4-mapped addrs either! */
916                                 /* NOTE: we don't support SIIT */
917                                 return EINVAL;
918                 }
919         }
920         crit_enter();
921         error = sctp_inpcb_bind(so, addr, p);
922         crit_exit();
923         return error;
924 }
925
926 /*This could be made common with sctp_detach() since they are identical */
927 static int
928 sctp6_detach(struct socket *so)
929 {
930         struct sctp_inpcb *inp;
931
932         inp = (struct sctp_inpcb *)so->so_pcb;
933         if (inp == 0)
934                 return EINVAL;
935         crit_enter();
936         if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
937             (so->so_rcv.sb_cc > 0))
938                 sctp_inpcb_free(inp, 1);
939         else
940                 sctp_inpcb_free(inp, 0);
941         crit_exit();
942         return 0;
943 }
944
945 static int
946 sctp6_disconnect(struct socket *so)
947 {
948         struct sctp_inpcb *inp;
949
950         crit_enter();
951         inp = (struct sctp_inpcb *)so->so_pcb;
952         if (inp == NULL) {
953                 crit_exit();
954                 return (ENOTCONN);
955         }
956         if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
957                 if (LIST_EMPTY(&inp->sctp_asoc_list)) {
958                         /* No connection */
959                         crit_exit();
960                         return (ENOTCONN);
961                 } else {
962                         int some_on_streamwheel = 0;
963                         struct sctp_association *asoc;
964                         struct sctp_tcb *stcb;
965
966                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
967                         if (stcb == NULL) {
968                                 crit_exit();
969                                 return (EINVAL);
970                         }
971                         asoc = &stcb->asoc;
972                         if (!TAILQ_EMPTY(&asoc->out_wheel)) {
973                                 /* Check to see if some data queued */
974                                 struct sctp_stream_out *outs;
975                                 TAILQ_FOREACH(outs, &asoc->out_wheel,
976                                               next_spoke) {
977                                         if (!TAILQ_EMPTY(&outs->outqueue)) {
978                                                 some_on_streamwheel = 1;
979                                                 break;
980                                         }
981                                 }
982                         }
983
984                         if (TAILQ_EMPTY(&asoc->send_queue) &&
985                             TAILQ_EMPTY(&asoc->sent_queue) &&
986                             (some_on_streamwheel == 0)) {
987                                 /* nothing queued to send, so I'm done... */
988                                 if ((SCTP_GET_STATE(asoc) !=
989                                      SCTP_STATE_SHUTDOWN_SENT) &&
990                                     (SCTP_GET_STATE(asoc) !=
991                                      SCTP_STATE_SHUTDOWN_ACK_SENT)) {
992                                         /* only send SHUTDOWN the first time */
993 #ifdef SCTP_DEBUG
994                                         if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
995                                                 printf("%s:%d sends a shutdown\n",
996                                                        __FILE__,
997                                                        __LINE__
998                                                         );
999                                         }
1000 #endif
1001                                         sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
1002                                         sctp_chunk_output(stcb->sctp_ep, stcb, 1);
1003                                         asoc->state = SCTP_STATE_SHUTDOWN_SENT;
1004                                         sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1005                                                          stcb->sctp_ep, stcb,
1006                                                          asoc->primary_destination);
1007                                         sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1008                                                          stcb->sctp_ep, stcb,
1009                                                          asoc->primary_destination);
1010                                 }
1011                         } else {
1012                                 /*
1013                                  * we still got (or just got) data to send,
1014                                  * so set SHUTDOWN_PENDING
1015                                  */
1016                                 /*
1017                                  * XXX sockets draft says that MSG_EOF should
1018                                  * be sent with no data.  currently, we will
1019                                  * allow user data to be sent first and move
1020                                  * to SHUTDOWN-PENDING
1021                                  */
1022                                 asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1023                         }
1024                         crit_exit();
1025                         return (0);
1026                 }
1027         } else {
1028                 /* UDP model does not support this */
1029                 crit_exit();
1030                 return EOPNOTSUPP;
1031         }
1032 }
1033
1034 int
1035 #if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__DragonFly__)
1036 sctp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1037           struct mbuf *control, struct thread *p);
1038 #else
1039 sctp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1040           struct mbuf *control, struct proc *p);
1041 #endif
1042
1043
1044 static int
1045 #if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__DragonFly__)
1046 sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1047            struct mbuf *control, struct thread *p)
1048 {
1049 #else
1050 #if defined(__FreeBSD__) || defined(__APPLE__)
1051 sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1052            struct mbuf *control, struct proc *p)
1053 {
1054 #else
1055 sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
1056            struct mbuf *control, struct proc *p)
1057 {
1058         struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *) : NULL;
1059 #endif
1060 #endif
1061         struct sctp_inpcb *inp;
1062         struct inpcb *in_inp;
1063         struct in6pcb *inp6;
1064 #ifdef INET
1065         struct sockaddr_in6 *sin6;
1066 #endif /* INET */
1067         /* No SPL needed since sctp_output does this */
1068
1069         inp = (struct sctp_inpcb *)so->so_pcb;
1070         if (inp == NULL) {
1071                 if (control) {
1072                         m_freem(control);
1073                         control = NULL;
1074                 }
1075                 m_freem(m);
1076                 return EINVAL;
1077         }
1078         in_inp = (struct inpcb *)inp;
1079         inp6 = (struct in6pcb *)inp;
1080         /* For the TCP model we may get a NULL addr, if we
1081          * are a connected socket thats ok.
1082          */
1083         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
1084             (addr == NULL)) {
1085                 goto connected_type;
1086         }
1087         if (addr == NULL) {
1088                 m_freem(m);
1089                 if (control) {
1090                         m_freem(control);
1091                         control = NULL;
1092                 }
1093                 return (EDESTADDRREQ);
1094         }
1095
1096 #ifdef INET
1097         sin6 = (struct sockaddr_in6 *)addr;
1098         if (
1099
1100 #if defined(__OpenBSD__)
1101              (0) /* we always do dual bind */
1102 #elif defined (__NetBSD__)
1103              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1104 #else
1105              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1106 #endif
1107             ) {
1108                 /*
1109                  * if IPV6_V6ONLY flag, we discard datagrams
1110                  * destined to a v4 addr or v4-mapped addr
1111                  */
1112                 if (addr->sa_family == AF_INET) {
1113                         return EINVAL;
1114                 }
1115                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1116                         return EINVAL;
1117                 }
1118         }
1119
1120         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1121                 if (!ip6_v6only) {
1122                         struct sockaddr_in sin;
1123                         /* convert v4-mapped into v4 addr and send */
1124                         in6_sin6_2_sin(&sin, sin6);
1125                         return sctp_send(so, flags,  m, (struct sockaddr *)&sin,
1126                                            control, p);
1127                 } else {
1128                         /* mapped addresses aren't enabled */
1129                         return EINVAL;
1130                 }
1131         }
1132 #endif /* INET */
1133  connected_type:
1134         /* now what about control */
1135         if (control) {
1136                 if (inp->control) {
1137                         printf("huh? control set?\n");
1138                         m_freem(inp->control);
1139                         inp->control = NULL;
1140                 }
1141                 inp->control = control;
1142         }
1143         /* add it in possibly */
1144         if ((inp->pkt) &&
1145             (inp->pkt->m_flags & M_PKTHDR)) {
1146                 struct mbuf *x;
1147                 int c_len;
1148
1149                 c_len = 0;
1150                 /* How big is it */
1151                 for (x=m;x;x = x->m_next) {
1152                         c_len += x->m_len;
1153                 }
1154                 inp->pkt->m_pkthdr.len += c_len;
1155         }
1156         /* Place the data */
1157         if (inp->pkt) {
1158                 inp->pkt_last->m_next = m;
1159                 inp->pkt_last = m;
1160         } else {
1161                 inp->pkt_last = inp->pkt = m;
1162         }
1163         if (
1164 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1165             /* FreeBSD and MacOSX uses a flag passed */
1166             ((flags & PRUS_MORETOCOME) == 0)
1167 #elif defined(__NetBSD__)
1168             /* NetBSD uses the so_state field */
1169             ((so->so_state & SS_MORETOCOME) == 0)
1170 #else
1171             1   /* Open BSD does not have any "more to come" indication */
1172 #endif
1173             ) {
1174                 /*
1175                  * note with the current version this code will only be
1176                  * used by OpenBSD, NetBSD and FreeBSD have methods for
1177                  * re-defining sosend() to use sctp_sosend().  One can
1178                  * optionaly switch back to this code (by changing back
1179                  * the defininitions but this is not advisable.
1180                  */
1181                 int ret;
1182                 ret = sctp_output(inp, inp->pkt , addr, inp->control, p, flags);
1183                 inp->pkt = NULL;
1184                 inp->control = NULL;
1185                 return (ret);
1186         } else {
1187                 return (0);
1188         }
1189 }
1190
1191 static int
1192 #if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__DragonFly__)
1193 sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
1194 {
1195 #else
1196 #if defined(__FreeBSD__) || defined(__APPLE__)
1197 sctp6_connect(struct socket *so, struct sockaddr *addr, struct proc *p)
1198 {
1199 #else
1200 sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
1201 {
1202         struct sockaddr *addr = mtod(nam, struct sockaddr *);
1203 #endif
1204 #endif
1205         int error = 0;
1206         struct sctp_inpcb *inp;
1207         struct in6pcb *inp6;
1208         struct sctp_tcb *stcb;
1209 #ifdef INET
1210         struct sockaddr_in6 *sin6;
1211         struct sockaddr_storage ss;
1212 #endif /* INET */
1213
1214         crit_enter();
1215         inp6 = (struct in6pcb *)so->so_pcb;
1216         inp = (struct sctp_inpcb *)so->so_pcb;
1217         if (inp == 0) {
1218                 crit_exit();
1219                 return (ECONNRESET);    /* I made the same as TCP since
1220                                          * we are not setup? */
1221         }
1222         SCTP_ASOC_CREATE_LOCK(inp);
1223         SCTP_INP_RLOCK(inp);
1224         if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1225             SCTP_PCB_FLAGS_UNBOUND) {
1226                 /* Bind a ephemeral port */
1227                 SCTP_INP_RUNLOCK(inp);
1228                 error = sctp6_bind(so, NULL, p);
1229                 if (error) {
1230                         crit_exit();
1231                         SCTP_ASOC_CREATE_UNLOCK(inp);
1232
1233                         return (error);
1234                 }
1235                 SCTP_INP_RLOCK(inp);
1236         }
1237
1238         if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1239             (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1240                 /* We are already connected AND the TCP model */
1241                 crit_exit();
1242                 SCTP_INP_RUNLOCK(inp);
1243                 SCTP_ASOC_CREATE_UNLOCK(inp);
1244                 return (EADDRINUSE);
1245         }
1246
1247 #ifdef INET
1248         sin6 = (struct sockaddr_in6 *)addr;
1249         if (
1250 #if defined(__OpenBSD__)
1251              (0) /* we always do dual bind */
1252 #elif defined (__NetBSD__)
1253              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1254 #else
1255              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1256 #endif
1257             ) {
1258                 /*
1259                  * if IPV6_V6ONLY flag, ignore connections
1260                  * destined to a v4 addr or v4-mapped addr
1261                  */
1262                 if (addr->sa_family == AF_INET) {
1263                         crit_exit();
1264                         SCTP_INP_RUNLOCK(inp);
1265                         SCTP_ASOC_CREATE_UNLOCK(inp);
1266                         return EINVAL;
1267                 }
1268                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1269                         crit_exit();
1270                         SCTP_INP_RUNLOCK(inp);
1271                         SCTP_ASOC_CREATE_UNLOCK(inp);
1272                         return EINVAL;
1273                 }
1274         }
1275
1276         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1277                 if (!ip6_v6only) {
1278                         /* convert v4-mapped into v4 addr */
1279                         in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
1280                         addr = (struct sockaddr *)&ss;
1281                 } else {
1282                         /* mapped addresses aren't enabled */
1283                         crit_exit();
1284                         SCTP_INP_RUNLOCK(inp);
1285                         SCTP_ASOC_CREATE_UNLOCK(inp);
1286                         return EINVAL;
1287                 }
1288         } else
1289 #endif /* INET */
1290                 addr = addr;    /* for true v6 address case */
1291
1292         /* Now do we connect? */
1293         if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1294                 stcb = LIST_FIRST(&inp->sctp_asoc_list);
1295                 if (stcb)
1296                         SCTP_TCB_UNLOCK (stcb);
1297                 SCTP_INP_RUNLOCK(inp);
1298         }else {
1299                 SCTP_INP_RUNLOCK(inp);
1300                 SCTP_INP_WLOCK(inp);
1301                 SCTP_INP_INCR_REF(inp);
1302                 SCTP_INP_WUNLOCK(inp);
1303                 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
1304                 if (stcb == NULL) {
1305                         SCTP_INP_WLOCK(inp);
1306                         SCTP_INP_DECR_REF(inp);
1307                         SCTP_INP_WUNLOCK(inp);
1308                 }
1309         }
1310
1311         if (stcb != NULL) {
1312                 /* Already have or am bring up an association */
1313                 SCTP_ASOC_CREATE_UNLOCK(inp);
1314                 SCTP_TCB_UNLOCK (stcb);
1315                 crit_exit();
1316                 return (EALREADY);
1317         }
1318         /* We are GOOD to go */
1319         stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0);
1320         SCTP_ASOC_CREATE_UNLOCK(inp);
1321         if (stcb == NULL) {
1322                 /* Gak! no memory */
1323                 crit_exit();
1324                 return (error);
1325         }
1326         if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1327                 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1328                 /* Set the connected flag so we can queue data */
1329                 soisconnecting(so);
1330         }
1331         stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1332         SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1333         sctp_send_initiate(inp, stcb);
1334         SCTP_TCB_UNLOCK (stcb);
1335         crit_exit();
1336         return error;
1337 }
1338
1339 static int
1340 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1341 sctp6_getaddr(struct socket *so, struct sockaddr **addr)
1342 {
1343         struct sockaddr_in6 *sin6;
1344 #else
1345 sctp6_getaddr(struct socket *so, struct mbuf *nam)
1346 {
1347         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1348 #endif
1349         struct sctp_inpcb *inp;
1350         /*
1351          * Do the malloc first in case it blocks.
1352          */
1353 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1354         MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME,
1355                M_WAITOK | M_ZERO);
1356 #else
1357         nam->m_len = sizeof(*sin6);
1358 #endif
1359         bzero(sin6, sizeof(*sin6));
1360         sin6->sin6_family = AF_INET6;
1361         sin6->sin6_len = sizeof(*sin6);
1362
1363         inp = (struct sctp_inpcb *)so->so_pcb;
1364         if (!inp) {
1365 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1366                 FREE(sin6, M_SONAME);
1367 #endif
1368                 return ECONNRESET;
1369         }
1370
1371         sin6->sin6_port = inp->sctp_lport;
1372         if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1373                 /* For the bound all case you get back 0 */
1374                 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1375                         struct sctp_tcb *stcb;
1376                         struct sockaddr_in6 *sin_a6;
1377                         struct sctp_nets *net;
1378                         int fnd;
1379
1380                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1381                         if (stcb == NULL) {
1382                                 goto notConn6;
1383                         }
1384                         fnd = 0;
1385                         sin_a6 = NULL;
1386                         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1387                                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1388                                 if (sin_a6->sin6_family == AF_INET6) {
1389                                         fnd = 1;
1390                                         break;
1391                                 }
1392                         }
1393                         if ((!fnd) || (sin_a6 == NULL)) {
1394                                 /* punt */
1395                                 goto notConn6;
1396                         }
1397                         sin6->sin6_addr = sctp_ipv6_source_address_selection(
1398                             inp, stcb, (struct route *)&net->ro, net, 0);
1399
1400                 } else {
1401                         /* For the bound all case you get back 0 */
1402                 notConn6:
1403                         memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1404                 }
1405         } else {
1406                 /* Take the first IPv6 address in the list */
1407                 struct sctp_laddr *laddr;
1408                 int fnd = 0;
1409                 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1410                         if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
1411                                 struct sockaddr_in6 *sin_a;
1412                                 sin_a = (struct sockaddr_in6 *)laddr->ifa->ifa_addr;
1413                                 sin6->sin6_addr = sin_a->sin6_addr;
1414                                 fnd = 1;
1415                                 break;
1416                         }
1417                 }
1418                 if (!fnd) {
1419 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1420                         FREE(sin6, M_SONAME);
1421 #endif
1422                         return ENOENT;
1423                 }
1424         }
1425         /* Scoping things for v6 */
1426         if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
1427                 /* skip ifp check below */
1428                 in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1429         else
1430                 sin6->sin6_scope_id = 0;        /*XXX*/
1431 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1432         (*addr) = (struct sockaddr *)sin6;
1433 #endif
1434         return (0);
1435 }
1436
1437 static int
1438 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1439 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1440 {
1441         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
1442 #else
1443 sctp6_peeraddr(struct socket *so, struct mbuf *nam)
1444 {
1445         struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1446 #endif
1447         int fnd;
1448         struct sockaddr_in6 *sin_a6;
1449         struct sctp_inpcb *inp;
1450         struct sctp_tcb *stcb;
1451         struct sctp_nets *net;
1452         /*
1453          * Do the malloc first in case it blocks.
1454          */
1455         inp = (struct sctp_inpcb *)so->so_pcb;
1456         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
1457                 /* UDP type and listeners will drop out here */
1458                 return (ENOTCONN);
1459         }
1460 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1461         MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME,
1462                M_WAITOK | M_ZERO);
1463 #else
1464         nam->m_len = sizeof(*sin6);
1465 #endif
1466         bzero(sin6, sizeof(*sin6));
1467         sin6->sin6_family = AF_INET6;
1468         sin6->sin6_len = sizeof(*sin6);
1469
1470         /* We must recapture incase we blocked */
1471         inp = (struct sctp_inpcb *)so->so_pcb;
1472         if (!inp) {
1473 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1474                 FREE(sin6, M_SONAME);
1475 #endif
1476                 return ECONNRESET;
1477         }
1478         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1479         if (stcb == NULL) {
1480 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1481                 FREE(sin6, M_SONAME);
1482 #endif
1483                 return ECONNRESET;
1484         }
1485         fnd = 0;
1486         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1487                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1488                 if (sin_a6->sin6_family == AF_INET6) {
1489                         fnd = 1;
1490                         sin6->sin6_port = stcb->rport;
1491                         sin6->sin6_addr = sin_a6->sin6_addr;
1492                         break;
1493                 }
1494         }
1495         if (!fnd) {
1496                 /* No IPv4 address */
1497 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1498                 FREE(sin6, M_SONAME);
1499 #endif
1500                 return ENOENT;
1501         }
1502         in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1503 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1504         *addr = (struct sockaddr *)sin6;
1505 #endif
1506         return (0);
1507 }
1508
1509 static int
1510 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1511 sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1512 {
1513         struct sockaddr *addr;
1514 #else
1515 sctp6_in6getaddr(struct socket *so, struct mbuf *nam)
1516 {
1517         struct sockaddr *addr = mtod(nam, struct sockaddr *);
1518 #endif
1519         struct in6pcb *inp6 = sotoin6pcb(so);
1520         int error;
1521
1522         if (inp6 == NULL)
1523                 return EINVAL;
1524
1525         crit_enter();
1526         /* allow v6 addresses precedence */
1527         error = sctp6_getaddr(so, nam);
1528         if (error) {
1529                 /* try v4 next if v6 failed */
1530                 error = sctp_ingetaddr(so, nam);
1531                 if (error) {
1532                         crit_exit();
1533                         return (error);
1534                 }
1535 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1536                 addr = *nam;
1537 #endif
1538                 /* if I'm V6ONLY, convert it to v4-mapped */
1539                 if (
1540 #if defined(__OpenBSD__)
1541              (0) /* we always do dual bind */
1542 #elif defined (__NetBSD__)
1543              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1544 #else
1545              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1546 #endif
1547                     ) {
1548                         struct sockaddr_in6 sin6;
1549                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1550                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1551 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1552                         nam->m_len = sizeof(sin6);
1553 #endif
1554 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1555                 } else {
1556                         nam->m_len = sizeof(struct sockaddr_in);
1557 #endif
1558                 }
1559 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1560         } else {
1561                 nam->m_len = sizeof(struct sockaddr_in6);
1562 #endif
1563         }
1564         crit_exit();
1565         return (error);
1566 }
1567
1568
1569 static int
1570 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1571 sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1572 {
1573         struct sockaddr *addr = *nam;
1574 #else
1575 sctp6_getpeeraddr(struct socket *so, struct mbuf *nam)
1576 {
1577         struct sockaddr *addr = mtod(nam, struct sockaddr *);
1578 #endif
1579         struct in6pcb *inp6 = sotoin6pcb(so);
1580         int error;
1581
1582         if (inp6 == NULL)
1583                 return EINVAL;
1584
1585         crit_enter();
1586         /* allow v6 addresses precedence */
1587         error = sctp6_peeraddr(so, nam);
1588         if (error) {
1589                 /* try v4 next if v6 failed */
1590                 error = sctp_peeraddr(so, nam);
1591                 if (error) {
1592                         crit_exit();
1593                         return (error);
1594                 }
1595                 /* if I'm V6ONLY, convert it to v4-mapped */
1596                 if (
1597 #if defined(__OpenBSD__)
1598              (0) /* we always do dual bind */
1599 #elif defined (__NetBSD__)
1600              (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
1601 #else
1602              (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1603 #endif
1604                     ) {
1605                         struct sockaddr_in6 sin6;
1606                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1607                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1608 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1609                         nam->m_len = sizeof(sin6);
1610 #endif
1611 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1612                 } else {
1613                         nam->m_len = sizeof(struct sockaddr_in);
1614 #endif
1615                 }
1616 #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__))
1617         } else {
1618                 nam->m_len = sizeof(struct sockaddr_in6);
1619 #endif
1620         }
1621         crit_exit();
1622         return error;
1623 }
1624
1625 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
1626 struct pr_usrreqs sctp6_usrreqs = {
1627         sctp6_abort, sctp_accept, sctp6_attach, sctp6_bind,
1628         sctp6_connect, pru_connect2_notsupp, in6_control,
1629         sctp6_detach, sctp6_disconnect, sctp_listen, sctp6_getpeeraddr,
1630         sctp_usr_recvd, pru_rcvoob_notsupp, sctp6_send, pru_sense_null,
1631         sctp_shutdown, sctp6_in6getaddr, sctp_sosend, soreceive, sopoll
1632 };
1633
1634 #else
1635
1636 int
1637 sctp6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
1638              struct mbuf *control, struct proc *p)
1639 {
1640         int s;
1641         int error = 0;
1642         int family;
1643
1644 #if defined(__OpenBSD__)
1645         p = curproc;
1646 #endif
1647         s = splsoftnet();
1648         family = so->so_proto->pr_domain->dom_family;
1649
1650         if (req == PRU_CONTROL) {
1651                 switch (family) {
1652                 case PF_INET:
1653                         error = in_control(so, (long)m, (caddr_t)nam,
1654                             (struct ifnet *)control
1655 #if defined(__NetBSD__)
1656                              , p
1657 #endif
1658                              );
1659 #ifdef INET6
1660                 case PF_INET6:
1661                         error = in6_control(so, (long)m, (caddr_t)nam,
1662                             (struct ifnet *)control, p);
1663 #endif
1664                 default:
1665                         error = EAFNOSUPPORT;
1666                 }
1667                 splx(s);
1668                 return (error);
1669         }
1670 #ifdef __NetBSD__
1671         if (req == PRU_PURGEIF) {
1672                 struct ifnet *ifn;
1673                 struct ifaddr *ifa;
1674                 ifn = (struct ifnet *)control;
1675                 TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
1676                         if (ifa->ifa_addr->sa_family == family) {
1677                                 sctp_delete_ip_address(ifa);
1678                         }
1679                 }
1680                 switch (family) {
1681                 case PF_INET:
1682                         in_purgeif (ifn);
1683                         break;
1684 #ifdef INET6
1685                 case PF_INET6:
1686                         in6_purgeif (ifn);
1687                         break;
1688 #endif
1689                 default:
1690                         splx(s);
1691                         return (EAFNOSUPPORT);
1692                 }
1693                 splx(s);
1694                 return (0);
1695         }
1696 #endif
1697         switch (req) {
1698         case PRU_ATTACH:
1699                 error = sctp6_attach(so, family, p);
1700                 break;
1701         case PRU_DETACH:
1702                 error = sctp6_detach(so);
1703                 break;
1704         case PRU_BIND:
1705                 if (nam == NULL)
1706                         return (EINVAL);
1707                 error = sctp6_bind(so, nam, p);
1708                 break;
1709         case PRU_LISTEN:
1710                 error = sctp_listen(so, p);
1711                 break;
1712         case PRU_CONNECT:
1713                 if (nam == NULL)
1714                         return (EINVAL);
1715                 error = sctp6_connect(so, nam, p);
1716                 break;
1717         case PRU_DISCONNECT:
1718                 error = sctp6_disconnect(so);
1719                 break;
1720         case PRU_ACCEPT:
1721                 if (nam == NULL)
1722                         return (EINVAL);
1723                 error = sctp_accept(so, nam);
1724                 break;
1725         case PRU_SHUTDOWN:
1726                 error = sctp_shutdown(so);
1727                 break;
1728
1729         case PRU_RCVD:
1730                 /*
1731                  * For OpenBSD and NetBSD, this is real ugly. The (mbuf *)
1732                  * nam that is passed (by soreceive()) is the int flags
1733                  * cast as a (mbuf *) yuck!
1734                  */
1735                 error = sctp_usr_recvd(so, (int)((long)nam));
1736                 break;
1737
1738         case PRU_SEND:
1739                 /* Flags are ignored */
1740                 error = sctp6_send(so, 0, m, nam, control, p);
1741                 break;
1742         case PRU_ABORT:
1743                 error = sctp6_abort(so);
1744                 break;
1745
1746         case PRU_SENSE:
1747                 error = 0;
1748                 break;
1749         case PRU_RCVOOB:
1750                 error = EAFNOSUPPORT;
1751                 break;
1752         case PRU_SENDOOB:
1753                 error = EAFNOSUPPORT;
1754                 break;
1755         case PRU_PEERADDR:
1756                 error = sctp6_getpeeraddr(so, nam);
1757                 break;
1758         case PRU_SOCKADDR:
1759                 error = sctp6_in6getaddr(so, nam);
1760                 break;
1761         case PRU_SLOWTIMO:
1762                 error = 0;
1763                 break;
1764         default:
1765                 break;
1766         }
1767         splx(s);
1768         return (error);
1769 }
1770 #endif