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