]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sys/netinet6/sctp6_usrreq.c
MFC r236087:
[FreeBSD/stable/9.git] / sys / netinet6 / sctp6_usrreq.c
1 /*-
2  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * a) Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  * b) Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the distribution.
15  *
16  * c) Neither the name of Cisco Systems, Inc. nor the names of its
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <netinet/sctp_os.h>
37 #include <sys/proc.h>
38 #include <netinet/sctp_pcb.h>
39 #include <netinet/sctp_header.h>
40 #include <netinet/sctp_var.h>
41 #if defined(INET6)
42 #include <netinet6/sctp6_var.h>
43 #endif
44 #include <netinet/sctp_sysctl.h>
45 #include <netinet/sctp_output.h>
46 #include <netinet/sctp_uio.h>
47 #include <netinet/sctp_asconf.h>
48 #include <netinet/sctputil.h>
49 #include <netinet/sctp_indata.h>
50 #include <netinet/sctp_timer.h>
51 #include <netinet/sctp_auth.h>
52 #include <netinet/sctp_input.h>
53 #include <netinet/sctp_output.h>
54 #include <netinet/sctp_bsd_addr.h>
55 #include <netinet/sctp_crc32.h>
56 #include <netinet/udp.h>
57
58 #ifdef IPSEC
59 #include <netipsec/ipsec.h>
60 #if defined(INET6)
61 #include <netipsec/ipsec6.h>
62 #endif                          /* INET6 */
63 #endif                          /* IPSEC */
64
65 extern struct protosw inetsw[];
66
67 int
68 sctp6_input(struct mbuf **i_pak, int *offp, int proto)
69 {
70         struct mbuf *m;
71         struct ip6_hdr *ip6;
72         struct sctphdr *sh;
73         struct sctp_inpcb *in6p = NULL;
74         struct sctp_nets *net;
75         int refcount_up = 0;
76         uint32_t vrf_id = 0;
77
78 #ifdef IPSEC
79         struct inpcb *in6p_ip;
80
81 #endif
82         struct sctp_chunkhdr *ch;
83         int length, offset, iphlen;
84         uint8_t ecn_bits;
85         struct sctp_tcb *stcb = NULL;
86         int pkt_len = 0;
87
88 #if !defined(SCTP_WITH_NO_CSUM)
89         uint32_t check, calc_check;
90
91 #endif
92         int off = *offp;
93         uint16_t port = 0;
94
95         /* get the VRF and table id's */
96         if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
97                 SCTP_RELEASE_PKT(*i_pak);
98                 return (-1);
99         }
100         m = SCTP_HEADER_TO_CHAIN(*i_pak);
101         pkt_len = SCTP_HEADER_LEN((*i_pak));
102
103 #ifdef  SCTP_PACKET_LOGGING
104         sctp_packet_log(m, pkt_len);
105 #endif
106         ip6 = mtod(m, struct ip6_hdr *);
107         /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
108         IP6_EXTHDR_GET(sh, struct sctphdr *, m, off,
109             (int)(sizeof(*sh) + sizeof(*ch)));
110         if (sh == NULL) {
111                 SCTP_STAT_INCR(sctps_hdrops);
112                 return (IPPROTO_DONE);
113         }
114         ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
115         iphlen = off;
116         offset = iphlen + sizeof(*sh) + sizeof(*ch);
117         SCTPDBG(SCTP_DEBUG_INPUT1,
118             "sctp6_input() length:%d iphlen:%d\n", pkt_len, iphlen);
119
120
121 #if defined(NFAITH) && NFAITH > 0
122
123         if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) {
124                 /* XXX send icmp6 host/port unreach? */
125                 goto bad;
126         }
127 #endif                          /* NFAITH defined and > 0 */
128         SCTP_STAT_INCR(sctps_recvpackets);
129         SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
130         SCTPDBG(SCTP_DEBUG_INPUT1, "V6 input gets a packet iphlen:%d pktlen:%d\n",
131             iphlen, pkt_len);
132         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
133                 /* No multi-cast support in SCTP */
134                 goto bad;
135         }
136         /* destination port of 0 is illegal, based on RFC2960. */
137         if (sh->dest_port == 0)
138                 goto bad;
139
140         SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
141             "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
142             m->m_pkthdr.len,
143             if_name(m->m_pkthdr.rcvif),
144             m->m_pkthdr.csum_flags);
145 #if defined(SCTP_WITH_NO_CSUM)
146         SCTP_STAT_INCR(sctps_recvnocrc);
147 #else
148         if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
149                 SCTP_STAT_INCR(sctps_recvhwcrc);
150                 goto sctp_skip_csum;
151         }
152         check = sh->checksum;   /* save incoming checksum */
153         sh->checksum = 0;       /* prepare for calc */
154         calc_check = sctp_calculate_cksum(m, iphlen);
155         SCTP_STAT_INCR(sctps_recvswcrc);
156         if (calc_check != check) {
157                 SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x  m:%p phlen:%d\n",
158                     calc_check, check, m, iphlen);
159                 stcb = sctp_findassociation_addr(m, offset - sizeof(*ch),
160                     sh, ch, &in6p, &net, vrf_id);
161                 if ((net) && (port)) {
162                         if (net->port == 0) {
163                                 sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
164                         }
165                         net->port = port;
166                 }
167                 if ((net != NULL) && (m->m_flags & M_FLOWID)) {
168                         net->flowid = m->m_pkthdr.flowid;
169 #ifdef INVARIANTS
170                         net->flowidset = 1;
171 #endif
172                 }
173                 /* in6p's ref-count increased && stcb locked */
174                 if ((in6p) && (stcb)) {
175                         sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
176                         sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
177                 } else if ((in6p != NULL) && (stcb == NULL)) {
178                         refcount_up = 1;
179                 }
180                 SCTP_STAT_INCR(sctps_badsum);
181                 SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
182                 goto bad;
183         }
184         sh->checksum = calc_check;
185
186 sctp_skip_csum:
187 #endif
188         net = NULL;
189         /*
190          * Locate pcb and tcb for datagram sctp_findassociation_addr() wants
191          * IP/SCTP/first chunk header...
192          */
193         stcb = sctp_findassociation_addr(m, offset - sizeof(*ch),
194             sh, ch, &in6p, &net, vrf_id);
195         if ((net) && (port)) {
196                 if (net->port == 0) {
197                         sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
198                 }
199                 net->port = port;
200         }
201         if ((net != NULL) && (m->m_flags & M_FLOWID)) {
202                 net->flowid = m->m_pkthdr.flowid;
203 #ifdef INVARIANTS
204                 net->flowidset = 1;
205 #endif
206         }
207         /* in6p's ref-count increased */
208         if (in6p == NULL) {
209                 struct sctp_init_chunk *init_chk, chunk_buf;
210
211                 SCTP_STAT_INCR(sctps_noport);
212                 if (ch->chunk_type == SCTP_INITIATION) {
213                         /*
214                          * we do a trick here to get the INIT tag, dig in
215                          * and get the tag from the INIT and put it in the
216                          * common header.
217                          */
218                         init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
219                             iphlen + sizeof(*sh), sizeof(*init_chk),
220                             (uint8_t *) & chunk_buf);
221                         if (init_chk)
222                                 sh->v_tag = init_chk->init.initiate_tag;
223                         else
224                                 sh->v_tag = 0;
225                 }
226                 if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
227                         sctp_send_shutdown_complete2(m, sh, vrf_id, port);
228                         goto bad;
229                 }
230                 if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
231                         goto bad;
232                 }
233                 if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) {
234                         if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
235                             ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
236                             (ch->chunk_type != SCTP_INIT))) {
237                                 sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id, port);
238                         }
239                 }
240                 goto bad;
241         } else if (stcb == NULL) {
242                 refcount_up = 1;
243         }
244 #ifdef IPSEC
245         /*
246          * Check AH/ESP integrity.
247          */
248         in6p_ip = (struct inpcb *)in6p;
249         if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) {
250 /* XXX */
251                 MODULE_GLOBAL(ipsec6stat).in_polvio++;
252                 goto bad;
253         }
254 #endif                          /* IPSEC */
255
256         /*
257          * CONTROL chunk processing
258          */
259         offset -= sizeof(*ch);
260         ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
261
262         /* Length now holds the total packet length payload + iphlen */
263         length = ntohs(ip6->ip6_plen) + iphlen;
264
265         /* sa_ignore NO_NULL_CHK */
266         sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
267             in6p, stcb, net, ecn_bits, vrf_id, port);
268         /* inp's ref-count reduced && stcb unlocked */
269         /* XXX this stuff below gets moved to appropriate parts later... */
270         if (m)
271                 sctp_m_freem(m);
272         if ((in6p) && refcount_up) {
273                 /* reduce ref-count */
274                 SCTP_INP_WLOCK(in6p);
275                 SCTP_INP_DECR_REF(in6p);
276                 SCTP_INP_WUNLOCK(in6p);
277         }
278         return (IPPROTO_DONE);
279
280 bad:
281         if (stcb) {
282                 SCTP_TCB_UNLOCK(stcb);
283         }
284         if ((in6p) && refcount_up) {
285                 /* reduce ref-count */
286                 SCTP_INP_WLOCK(in6p);
287                 SCTP_INP_DECR_REF(in6p);
288                 SCTP_INP_WUNLOCK(in6p);
289         }
290         if (m)
291                 sctp_m_freem(m);
292         return (IPPROTO_DONE);
293 }
294
295
296 static void
297 sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6,
298     struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net)
299 {
300         uint32_t nxtsz;
301
302         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
303             (icmp6 == NULL) || (sh == NULL)) {
304                 goto out;
305         }
306         /* First do we even look at it? */
307         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
308                 goto out;
309
310         if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
311                 /* not PACKET TO BIG */
312                 goto out;
313         }
314         /*
315          * ok we need to look closely. We could even get smarter and look at
316          * anyone that we sent to in case we get a different ICMP that tells
317          * us there is no way to reach a host, but for this impl, all we
318          * care about is MTU discovery.
319          */
320         nxtsz = ntohl(icmp6->icmp6_mtu);
321         /* Stop any PMTU timer */
322         sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1);
323
324         /* Adjust destination size limit */
325         if (net->mtu > nxtsz) {
326                 net->mtu = nxtsz;
327                 if (net->port) {
328                         net->mtu -= sizeof(struct udphdr);
329                 }
330         }
331         /* now what about the ep? */
332         if (stcb->asoc.smallest_mtu > nxtsz) {
333                 struct sctp_tmit_chunk *chk;
334
335                 /* Adjust that too */
336                 stcb->asoc.smallest_mtu = nxtsz;
337                 /* now off to subtract IP_DF flag if needed */
338
339                 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
340                         if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
341                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
342                         }
343                 }
344                 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
345                         if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
346                                 /*
347                                  * For this guy we also mark for immediate
348                                  * resend since we sent to big of chunk
349                                  */
350                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
351                                 if (chk->sent != SCTP_DATAGRAM_RESEND)
352                                         stcb->asoc.sent_queue_retran_cnt++;
353                                 chk->sent = SCTP_DATAGRAM_RESEND;
354                                 chk->rec.data.doing_fast_retransmit = 0;
355
356                                 chk->sent = SCTP_DATAGRAM_RESEND;
357                                 /* Clear any time so NO RTT is being done */
358                                 chk->sent_rcv_time.tv_sec = 0;
359                                 chk->sent_rcv_time.tv_usec = 0;
360                                 stcb->asoc.total_flight -= chk->send_size;
361                                 net->flight_size -= chk->send_size;
362                         }
363                 }
364         }
365         sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
366 out:
367         if (stcb) {
368                 SCTP_TCB_UNLOCK(stcb);
369         }
370 }
371
372
373 void
374 sctp6_notify(struct sctp_inpcb *inp,
375     struct icmp6_hdr *icmph,
376     struct sctphdr *sh,
377     struct sockaddr *to,
378     struct sctp_tcb *stcb,
379     struct sctp_nets *net)
380 {
381 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
382         struct socket *so;
383
384 #endif
385
386         /* protection */
387         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
388             (sh == NULL) || (to == NULL)) {
389                 if (stcb)
390                         SCTP_TCB_UNLOCK(stcb);
391                 return;
392         }
393         /* First job is to verify the vtag matches what I would send */
394         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
395                 SCTP_TCB_UNLOCK(stcb);
396                 return;
397         }
398         if (icmph->icmp6_type != ICMP_UNREACH) {
399                 /* We only care about unreachable */
400                 SCTP_TCB_UNLOCK(stcb);
401                 return;
402         }
403         if ((icmph->icmp6_code == ICMP_UNREACH_NET) ||
404             (icmph->icmp6_code == ICMP_UNREACH_HOST) ||
405             (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) ||
406             (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) ||
407             (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) ||
408             (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) ||
409             (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) ||
410             (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) {
411
412                 /*
413                  * Hmm reachablity problems we must examine closely. If its
414                  * not reachable, we may have lost a network. Or if there is
415                  * NO protocol at the other end named SCTP. well we consider
416                  * it a OOTB abort.
417                  */
418                 if (net->dest_state & SCTP_ADDR_REACHABLE) {
419                         /* Ok that destination is NOT reachable */
420                         net->dest_state &= ~SCTP_ADDR_REACHABLE;
421                         net->dest_state &= ~SCTP_ADDR_PF;
422                         sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
423                             stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
424                 }
425                 SCTP_TCB_UNLOCK(stcb);
426         } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) ||
427             (icmph->icmp6_code == ICMP_UNREACH_PORT)) {
428                 /*
429                  * Here the peer is either playing tricks on us, including
430                  * an address that belongs to someone who does not support
431                  * SCTP OR was a userland implementation that shutdown and
432                  * now is dead. In either case treat it like a OOTB abort
433                  * with no TCB
434                  */
435                 sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
436 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
437                 so = SCTP_INP_SO(inp);
438                 atomic_add_int(&stcb->asoc.refcnt, 1);
439                 SCTP_TCB_UNLOCK(stcb);
440                 SCTP_SOCKET_LOCK(so, 1);
441                 SCTP_TCB_LOCK(stcb);
442                 atomic_subtract_int(&stcb->asoc.refcnt, 1);
443 #endif
444                 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
445 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
446                 SCTP_SOCKET_UNLOCK(so, 1);
447                 /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
448 #endif
449                 /* no need to unlock here, since the TCB is gone */
450         } else {
451                 SCTP_TCB_UNLOCK(stcb);
452         }
453 }
454
455
456
457 void
458 sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
459 {
460         struct sctphdr sh;
461         struct ip6ctlparam *ip6cp = NULL;
462         uint32_t vrf_id;
463
464         vrf_id = SCTP_DEFAULT_VRFID;
465
466         if (pktdst->sa_family != AF_INET6 ||
467             pktdst->sa_len != sizeof(struct sockaddr_in6))
468                 return;
469
470         if ((unsigned)cmd >= PRC_NCMDS)
471                 return;
472         if (PRC_IS_REDIRECT(cmd)) {
473                 d = NULL;
474         } else if (inet6ctlerrmap[cmd] == 0) {
475                 return;
476         }
477         /* if the parameter is from icmp6, decode it. */
478         if (d != NULL) {
479                 ip6cp = (struct ip6ctlparam *)d;
480         } else {
481                 ip6cp = (struct ip6ctlparam *)NULL;
482         }
483
484         if (ip6cp) {
485                 /*
486                  * XXX: We assume that when IPV6 is non NULL, M and OFF are
487                  * valid.
488                  */
489                 /* check if we can safely examine src and dst ports */
490                 struct sctp_inpcb *inp = NULL;
491                 struct sctp_tcb *stcb = NULL;
492                 struct sctp_nets *net = NULL;
493                 struct sockaddr_in6 final;
494
495                 if (ip6cp->ip6c_m == NULL)
496                         return;
497
498                 bzero(&sh, sizeof(sh));
499                 bzero(&final, sizeof(final));
500                 inp = NULL;
501                 net = NULL;
502                 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
503                     (caddr_t)&sh);
504                 ip6cp->ip6c_src->sin6_port = sh.src_port;
505                 final.sin6_len = sizeof(final);
506                 final.sin6_family = AF_INET6;
507                 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
508                 final.sin6_port = sh.dest_port;
509                 stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src,
510                     (struct sockaddr *)&final,
511                     &inp, &net, 1, vrf_id);
512                 /* inp's ref-count increased && stcb locked */
513                 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
514                         if (cmd == PRC_MSGSIZE) {
515                                 sctp6_notify_mbuf(inp,
516                                     ip6cp->ip6c_icmp6,
517                                     &sh,
518                                     stcb,
519                                     net);
520                                 /* inp's ref-count reduced && stcb unlocked */
521                         } else {
522                                 sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh,
523                                     (struct sockaddr *)&final,
524                                     stcb, net);
525                                 /* inp's ref-count reduced && stcb unlocked */
526                         }
527                 } else {
528                         if (PRC_IS_REDIRECT(cmd) && inp) {
529                                 in6_rtchange((struct in6pcb *)inp,
530                                     inet6ctlerrmap[cmd]);
531                         }
532                         if (inp) {
533                                 /* reduce inp's ref-count */
534                                 SCTP_INP_WLOCK(inp);
535                                 SCTP_INP_DECR_REF(inp);
536                                 SCTP_INP_WUNLOCK(inp);
537                         }
538                         if (stcb)
539                                 SCTP_TCB_UNLOCK(stcb);
540                 }
541         }
542 }
543
544 /*
545  * this routine can probably be collasped into the one in sctp_userreq.c
546  * since they do the same thing and now we lookup with a sockaddr
547  */
548 static int
549 sctp6_getcred(SYSCTL_HANDLER_ARGS)
550 {
551         struct xucred xuc;
552         struct sockaddr_in6 addrs[2];
553         struct sctp_inpcb *inp;
554         struct sctp_nets *net;
555         struct sctp_tcb *stcb;
556         int error;
557         uint32_t vrf_id;
558
559         vrf_id = SCTP_DEFAULT_VRFID;
560
561         error = priv_check(req->td, PRIV_NETINET_GETCRED);
562         if (error)
563                 return (error);
564
565         if (req->newlen != sizeof(addrs)) {
566                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
567                 return (EINVAL);
568         }
569         if (req->oldlen != sizeof(struct ucred)) {
570                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
571                 return (EINVAL);
572         }
573         error = SYSCTL_IN(req, addrs, sizeof(addrs));
574         if (error)
575                 return (error);
576
577         stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
578             sin6tosa(&addrs[1]),
579             &inp, &net, 1, vrf_id);
580         if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
581                 if ((inp != NULL) && (stcb == NULL)) {
582                         /* reduce ref-count */
583                         SCTP_INP_WLOCK(inp);
584                         SCTP_INP_DECR_REF(inp);
585                         goto cred_can_cont;
586                 }
587                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
588                 error = ENOENT;
589                 goto out;
590         }
591         SCTP_TCB_UNLOCK(stcb);
592         /*
593          * We use the write lock here, only since in the error leg we need
594          * it. If we used RLOCK, then we would have to
595          * wlock/decr/unlock/rlock. Which in theory could create a hole.
596          * Better to use higher wlock.
597          */
598         SCTP_INP_WLOCK(inp);
599 cred_can_cont:
600         error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
601         if (error) {
602                 SCTP_INP_WUNLOCK(inp);
603                 goto out;
604         }
605         cru2x(inp->sctp_socket->so_cred, &xuc);
606         SCTP_INP_WUNLOCK(inp);
607         error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
608 out:
609         return (error);
610 }
611
612 SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
613     0, 0,
614     sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
615
616
617 /* This is the same as the sctp_abort() could be made common */
618 static void
619 sctp6_abort(struct socket *so)
620 {
621         struct sctp_inpcb *inp;
622         uint32_t flags;
623
624         inp = (struct sctp_inpcb *)so->so_pcb;
625         if (inp == NULL) {
626                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
627                 return;
628         }
629 sctp_must_try_again:
630         flags = inp->sctp_flags;
631 #ifdef SCTP_LOG_CLOSING
632         sctp_log_closing(inp, NULL, 17);
633 #endif
634         if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
635             (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
636 #ifdef SCTP_LOG_CLOSING
637                 sctp_log_closing(inp, NULL, 16);
638 #endif
639                 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
640                     SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
641                 SOCK_LOCK(so);
642                 SCTP_SB_CLEAR(so->so_snd);
643                 /*
644                  * same for the rcv ones, they are only here for the
645                  * accounting/select.
646                  */
647                 SCTP_SB_CLEAR(so->so_rcv);
648                 /* Now null out the reference, we are completely detached. */
649                 so->so_pcb = NULL;
650                 SOCK_UNLOCK(so);
651         } else {
652                 flags = inp->sctp_flags;
653                 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
654                         goto sctp_must_try_again;
655                 }
656         }
657         return;
658 }
659
660 static int
661 sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
662 {
663         struct in6pcb *inp6;
664         int error;
665         struct sctp_inpcb *inp;
666         uint32_t vrf_id = SCTP_DEFAULT_VRFID;
667
668         inp = (struct sctp_inpcb *)so->so_pcb;
669         if (inp != NULL) {
670                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
671                 return (EINVAL);
672         }
673         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
674                 error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
675                 if (error)
676                         return (error);
677         }
678         error = sctp_inpcb_alloc(so, vrf_id);
679         if (error)
680                 return (error);
681         inp = (struct sctp_inpcb *)so->so_pcb;
682         SCTP_INP_WLOCK(inp);
683         inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;     /* I'm v6! */
684         inp6 = (struct in6pcb *)inp;
685
686         inp6->inp_vflag |= INP_IPV6;
687         inp6->in6p_hops = -1;   /* use kernel default */
688         inp6->in6p_cksum = -1;  /* just to be sure */
689 #ifdef INET
690         /*
691          * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
692          * socket as well, because the socket may be bound to an IPv6
693          * wildcard address, which may match an IPv4-mapped IPv6 address.
694          */
695         inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
696 #endif
697         /*
698          * Hmm what about the IPSEC stuff that is missing here but in
699          * sctp_attach()?
700          */
701         SCTP_INP_WUNLOCK(inp);
702         return (0);
703 }
704
705 static int
706 sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
707 {
708         struct sctp_inpcb *inp;
709         struct in6pcb *inp6;
710         int error;
711
712         inp = (struct sctp_inpcb *)so->so_pcb;
713         if (inp == NULL) {
714                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
715                 return (EINVAL);
716         }
717         if (addr) {
718                 switch (addr->sa_family) {
719 #ifdef INET
720                 case AF_INET:
721                         if (addr->sa_len != sizeof(struct sockaddr_in)) {
722                                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
723                                 return (EINVAL);
724                         }
725                         break;
726 #endif
727 #ifdef INET6
728                 case AF_INET6:
729                         if (addr->sa_len != sizeof(struct sockaddr_in6)) {
730                                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
731                                 return (EINVAL);
732                         }
733                         break;
734 #endif
735                 default:
736                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
737                         return (EINVAL);
738                 }
739         }
740         inp6 = (struct in6pcb *)inp;
741         inp6->inp_vflag &= ~INP_IPV4;
742         inp6->inp_vflag |= INP_IPV6;
743         if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
744                 switch (addr->sa_family) {
745 #ifdef INET
746                 case AF_INET:
747                         /* binding v4 addr to v6 socket, so reset flags */
748                         inp6->inp_vflag |= INP_IPV4;
749                         inp6->inp_vflag &= ~INP_IPV6;
750                         break;
751 #endif
752 #ifdef INET6
753                 case AF_INET6:
754                         {
755                                 struct sockaddr_in6 *sin6_p;
756
757                                 sin6_p = (struct sockaddr_in6 *)addr;
758
759                                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
760                                         inp6->inp_vflag |= INP_IPV4;
761                                 }
762 #ifdef INET
763                                 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
764                                         struct sockaddr_in sin;
765
766                                         in6_sin6_2_sin(&sin, sin6_p);
767                                         inp6->inp_vflag |= INP_IPV4;
768                                         inp6->inp_vflag &= ~INP_IPV6;
769                                         error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
770                                         return (error);
771                                 }
772 #endif
773                                 break;
774                         }
775 #endif
776                 default:
777                         break;
778                 }
779         } else if (addr != NULL) {
780                 struct sockaddr_in6 *sin6_p;
781
782                 /* IPV6_V6ONLY socket */
783 #ifdef INET
784                 if (addr->sa_family == AF_INET) {
785                         /* can't bind v4 addr to v6 only socket! */
786                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
787                         return (EINVAL);
788                 }
789 #endif
790                 sin6_p = (struct sockaddr_in6 *)addr;
791
792                 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
793                         /* can't bind v4-mapped addrs either! */
794                         /* NOTE: we don't support SIIT */
795                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
796                         return (EINVAL);
797                 }
798         }
799         error = sctp_inpcb_bind(so, addr, NULL, p);
800         return (error);
801 }
802
803
804 static void
805 sctp6_close(struct socket *so)
806 {
807         sctp_close(so);
808 }
809
810 /* This could be made common with sctp_detach() since they are identical */
811
812 static
813 int
814 sctp6_disconnect(struct socket *so)
815 {
816         return (sctp_disconnect(so));
817 }
818
819
820 int
821 sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
822     struct mbuf *control, struct thread *p);
823
824
825 static int
826 sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
827     struct mbuf *control, struct thread *p)
828 {
829         struct sctp_inpcb *inp;
830         struct in6pcb *inp6;
831
832 #ifdef INET
833         struct sockaddr_in6 *sin6;
834
835 #endif                          /* INET */
836         /* No SPL needed since sctp_output does this */
837
838         inp = (struct sctp_inpcb *)so->so_pcb;
839         if (inp == NULL) {
840                 if (control) {
841                         SCTP_RELEASE_PKT(control);
842                         control = NULL;
843                 }
844                 SCTP_RELEASE_PKT(m);
845                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
846                 return (EINVAL);
847         }
848         inp6 = (struct in6pcb *)inp;
849         /*
850          * For the TCP model we may get a NULL addr, if we are a connected
851          * socket thats ok.
852          */
853         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
854             (addr == NULL)) {
855                 goto connected_type;
856         }
857         if (addr == NULL) {
858                 SCTP_RELEASE_PKT(m);
859                 if (control) {
860                         SCTP_RELEASE_PKT(control);
861                         control = NULL;
862                 }
863                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
864                 return (EDESTADDRREQ);
865         }
866 #ifdef INET
867         sin6 = (struct sockaddr_in6 *)addr;
868         if (SCTP_IPV6_V6ONLY(inp6)) {
869                 /*
870                  * if IPV6_V6ONLY flag, we discard datagrams destined to a
871                  * v4 addr or v4-mapped addr
872                  */
873                 if (addr->sa_family == AF_INET) {
874                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
875                         return (EINVAL);
876                 }
877                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
878                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
879                         return (EINVAL);
880                 }
881         }
882         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
883                 if (!MODULE_GLOBAL(ip6_v6only)) {
884                         struct sockaddr_in sin;
885
886                         /* convert v4-mapped into v4 addr and send */
887                         in6_sin6_2_sin(&sin, sin6);
888                         return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin,
889                             control, p));
890                 } else {
891                         /* mapped addresses aren't enabled */
892                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
893                         return (EINVAL);
894                 }
895         }
896 #endif                          /* INET */
897 connected_type:
898         /* now what about control */
899         if (control) {
900                 if (inp->control) {
901                         SCTP_PRINTF("huh? control set?\n");
902                         SCTP_RELEASE_PKT(inp->control);
903                         inp->control = NULL;
904                 }
905                 inp->control = control;
906         }
907         /* Place the data */
908         if (inp->pkt) {
909                 SCTP_BUF_NEXT(inp->pkt_last) = m;
910                 inp->pkt_last = m;
911         } else {
912                 inp->pkt_last = inp->pkt = m;
913         }
914         if (
915         /* FreeBSD and MacOSX uses a flag passed */
916             ((flags & PRUS_MORETOCOME) == 0)
917             ) {
918                 /*
919                  * note with the current version this code will only be used
920                  * by OpenBSD, NetBSD and FreeBSD have methods for
921                  * re-defining sosend() to use sctp_sosend().  One can
922                  * optionaly switch back to this code (by changing back the
923                  * defininitions but this is not advisable.
924                  */
925                 int ret;
926
927                 ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
928                 inp->pkt = NULL;
929                 inp->control = NULL;
930                 return (ret);
931         } else {
932                 return (0);
933         }
934 }
935
936 static int
937 sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
938 {
939         uint32_t vrf_id;
940         int error = 0;
941         struct sctp_inpcb *inp;
942         struct in6pcb *inp6;
943         struct sctp_tcb *stcb;
944
945 #ifdef INET
946         struct sockaddr_in6 *sin6;
947         struct sockaddr_storage ss;
948
949 #endif
950
951         inp6 = (struct in6pcb *)so->so_pcb;
952         inp = (struct sctp_inpcb *)so->so_pcb;
953         if (inp == NULL) {
954                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
955                 return (ECONNRESET);    /* I made the same as TCP since we are
956                                          * not setup? */
957         }
958         if (addr == NULL) {
959                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
960                 return (EINVAL);
961         }
962         switch (addr->sa_family) {
963 #ifdef INET
964         case AF_INET:
965                 if (addr->sa_len != sizeof(struct sockaddr_in)) {
966                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
967                         return (EINVAL);
968                 }
969                 break;
970 #endif
971 #ifdef INET6
972         case AF_INET6:
973                 if (addr->sa_len != sizeof(struct sockaddr_in6)) {
974                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
975                         return (EINVAL);
976                 }
977                 break;
978 #endif
979         default:
980                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
981                 return (EINVAL);
982         }
983
984         vrf_id = inp->def_vrf_id;
985         SCTP_ASOC_CREATE_LOCK(inp);
986         SCTP_INP_RLOCK(inp);
987         if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
988             SCTP_PCB_FLAGS_UNBOUND) {
989                 /* Bind a ephemeral port */
990                 SCTP_INP_RUNLOCK(inp);
991                 error = sctp6_bind(so, NULL, p);
992                 if (error) {
993                         SCTP_ASOC_CREATE_UNLOCK(inp);
994
995                         return (error);
996                 }
997                 SCTP_INP_RLOCK(inp);
998         }
999         if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1000             (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1001                 /* We are already connected AND the TCP model */
1002                 SCTP_INP_RUNLOCK(inp);
1003                 SCTP_ASOC_CREATE_UNLOCK(inp);
1004                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
1005                 return (EADDRINUSE);
1006         }
1007 #ifdef INET
1008         sin6 = (struct sockaddr_in6 *)addr;
1009         if (SCTP_IPV6_V6ONLY(inp6)) {
1010                 /*
1011                  * if IPV6_V6ONLY flag, ignore connections destined to a v4
1012                  * addr or v4-mapped addr
1013                  */
1014                 if (addr->sa_family == AF_INET) {
1015                         SCTP_INP_RUNLOCK(inp);
1016                         SCTP_ASOC_CREATE_UNLOCK(inp);
1017                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1018                         return (EINVAL);
1019                 }
1020                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1021                         SCTP_INP_RUNLOCK(inp);
1022                         SCTP_ASOC_CREATE_UNLOCK(inp);
1023                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1024                         return (EINVAL);
1025                 }
1026         }
1027         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1028                 if (!MODULE_GLOBAL(ip6_v6only)) {
1029                         /* convert v4-mapped into v4 addr */
1030                         in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
1031                         addr = (struct sockaddr *)&ss;
1032                 } else {
1033                         /* mapped addresses aren't enabled */
1034                         SCTP_INP_RUNLOCK(inp);
1035                         SCTP_ASOC_CREATE_UNLOCK(inp);
1036                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1037                         return (EINVAL);
1038                 }
1039         }
1040 #endif                          /* INET */
1041         /* Now do we connect? */
1042         if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1043                 stcb = LIST_FIRST(&inp->sctp_asoc_list);
1044                 if (stcb) {
1045                         SCTP_TCB_UNLOCK(stcb);
1046                 }
1047                 SCTP_INP_RUNLOCK(inp);
1048         } else {
1049                 SCTP_INP_RUNLOCK(inp);
1050                 SCTP_INP_WLOCK(inp);
1051                 SCTP_INP_INCR_REF(inp);
1052                 SCTP_INP_WUNLOCK(inp);
1053                 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
1054                 if (stcb == NULL) {
1055                         SCTP_INP_WLOCK(inp);
1056                         SCTP_INP_DECR_REF(inp);
1057                         SCTP_INP_WUNLOCK(inp);
1058                 }
1059         }
1060
1061         if (stcb != NULL) {
1062                 /* Already have or am bring up an association */
1063                 SCTP_ASOC_CREATE_UNLOCK(inp);
1064                 SCTP_TCB_UNLOCK(stcb);
1065                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
1066                 return (EALREADY);
1067         }
1068         /* We are GOOD to go */
1069         stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
1070         SCTP_ASOC_CREATE_UNLOCK(inp);
1071         if (stcb == NULL) {
1072                 /* Gak! no memory */
1073                 return (error);
1074         }
1075         if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1076                 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1077                 /* Set the connected flag so we can queue data */
1078                 soisconnecting(so);
1079         }
1080         stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1081         (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1082
1083         /* initialize authentication parameters for the assoc */
1084         sctp_initialize_auth_params(inp, stcb);
1085
1086         sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
1087         SCTP_TCB_UNLOCK(stcb);
1088         return (error);
1089 }
1090
1091 static int
1092 sctp6_getaddr(struct socket *so, struct sockaddr **addr)
1093 {
1094         struct sockaddr_in6 *sin6;
1095         struct sctp_inpcb *inp;
1096         uint32_t vrf_id;
1097         struct sctp_ifa *sctp_ifa;
1098
1099         int error;
1100
1101         /*
1102          * Do the malloc first in case it blocks.
1103          */
1104         SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
1105         if (sin6 == NULL)
1106                 return (ENOMEM);
1107         sin6->sin6_family = AF_INET6;
1108         sin6->sin6_len = sizeof(*sin6);
1109
1110         inp = (struct sctp_inpcb *)so->so_pcb;
1111         if (inp == NULL) {
1112                 SCTP_FREE_SONAME(sin6);
1113                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1114                 return (ECONNRESET);
1115         }
1116         SCTP_INP_RLOCK(inp);
1117         sin6->sin6_port = inp->sctp_lport;
1118         if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1119                 /* For the bound all case you get back 0 */
1120                 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1121                         struct sctp_tcb *stcb;
1122                         struct sockaddr_in6 *sin_a6;
1123                         struct sctp_nets *net;
1124                         int fnd;
1125
1126                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1127                         if (stcb == NULL) {
1128                                 goto notConn6;
1129                         }
1130                         fnd = 0;
1131                         sin_a6 = NULL;
1132                         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1133                                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1134                                 if (sin_a6 == NULL)
1135                                         /* this will make coverity happy */
1136                                         continue;
1137
1138                                 if (sin_a6->sin6_family == AF_INET6) {
1139                                         fnd = 1;
1140                                         break;
1141                                 }
1142                         }
1143                         if ((!fnd) || (sin_a6 == NULL)) {
1144                                 /* punt */
1145                                 goto notConn6;
1146                         }
1147                         vrf_id = inp->def_vrf_id;
1148                         sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id);
1149                         if (sctp_ifa) {
1150                                 sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
1151                         }
1152                 } else {
1153                         /* For the bound all case you get back 0 */
1154         notConn6:
1155                         memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1156                 }
1157         } else {
1158                 /* Take the first IPv6 address in the list */
1159                 struct sctp_laddr *laddr;
1160                 int fnd = 0;
1161
1162                 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1163                         if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1164                                 struct sockaddr_in6 *sin_a;
1165
1166                                 sin_a = (struct sockaddr_in6 *)&laddr->ifa->address.sin6;
1167                                 sin6->sin6_addr = sin_a->sin6_addr;
1168                                 fnd = 1;
1169                                 break;
1170                         }
1171                 }
1172                 if (!fnd) {
1173                         SCTP_FREE_SONAME(sin6);
1174                         SCTP_INP_RUNLOCK(inp);
1175                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1176                         return (ENOENT);
1177                 }
1178         }
1179         SCTP_INP_RUNLOCK(inp);
1180         /* Scoping things for v6 */
1181         if ((error = sa6_recoverscope(sin6)) != 0) {
1182                 SCTP_FREE_SONAME(sin6);
1183                 return (error);
1184         }
1185         (*addr) = (struct sockaddr *)sin6;
1186         return (0);
1187 }
1188
1189 static int
1190 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1191 {
1192         struct sockaddr_in6 *sin6;
1193         int fnd;
1194         struct sockaddr_in6 *sin_a6;
1195         struct sctp_inpcb *inp;
1196         struct sctp_tcb *stcb;
1197         struct sctp_nets *net;
1198         int error;
1199
1200         /* Do the malloc first in case it blocks. */
1201         SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1202         if (sin6 == NULL)
1203                 return (ENOMEM);
1204         sin6->sin6_family = AF_INET6;
1205         sin6->sin6_len = sizeof(*sin6);
1206
1207         inp = (struct sctp_inpcb *)so->so_pcb;
1208         if ((inp == NULL) ||
1209             ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
1210                 /* UDP type and listeners will drop out here */
1211                 SCTP_FREE_SONAME(sin6);
1212                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
1213                 return (ENOTCONN);
1214         }
1215         SCTP_INP_RLOCK(inp);
1216         stcb = LIST_FIRST(&inp->sctp_asoc_list);
1217         if (stcb) {
1218                 SCTP_TCB_LOCK(stcb);
1219         }
1220         SCTP_INP_RUNLOCK(inp);
1221         if (stcb == NULL) {
1222                 SCTP_FREE_SONAME(sin6);
1223                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1224                 return (ECONNRESET);
1225         }
1226         fnd = 0;
1227         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1228                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1229                 if (sin_a6->sin6_family == AF_INET6) {
1230                         fnd = 1;
1231                         sin6->sin6_port = stcb->rport;
1232                         sin6->sin6_addr = sin_a6->sin6_addr;
1233                         break;
1234                 }
1235         }
1236         SCTP_TCB_UNLOCK(stcb);
1237         if (!fnd) {
1238                 /* No IPv4 address */
1239                 SCTP_FREE_SONAME(sin6);
1240                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1241                 return (ENOENT);
1242         }
1243         if ((error = sa6_recoverscope(sin6)) != 0)
1244                 return (error);
1245         *addr = (struct sockaddr *)sin6;
1246         return (0);
1247 }
1248
1249 static int
1250 sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1251 {
1252 #ifdef INET
1253         struct sockaddr *addr;
1254
1255 #endif
1256         struct in6pcb *inp6 = sotoin6pcb(so);
1257         int error;
1258
1259         if (inp6 == NULL) {
1260                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1261                 return (EINVAL);
1262         }
1263         /* allow v6 addresses precedence */
1264         error = sctp6_getaddr(so, nam);
1265 #ifdef INET
1266         if (error) {
1267                 /* try v4 next if v6 failed */
1268                 error = sctp_ingetaddr(so, nam);
1269                 if (error) {
1270                         return (error);
1271                 }
1272                 addr = *nam;
1273                 /* if I'm V6ONLY, convert it to v4-mapped */
1274                 if (SCTP_IPV6_V6ONLY(inp6)) {
1275                         struct sockaddr_in6 sin6;
1276
1277                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1278                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1279                 }
1280         }
1281 #endif
1282         return (error);
1283 }
1284
1285
1286 static int
1287 sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1288 {
1289 #ifdef INET
1290         struct sockaddr *addr;
1291
1292 #endif
1293         struct in6pcb *inp6 = sotoin6pcb(so);
1294         int error;
1295
1296         if (inp6 == NULL) {
1297                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1298                 return (EINVAL);
1299         }
1300         /* allow v6 addresses precedence */
1301         error = sctp6_peeraddr(so, nam);
1302 #ifdef INET
1303         if (error) {
1304                 /* try v4 next if v6 failed */
1305                 error = sctp_peeraddr(so, nam);
1306                 if (error) {
1307                         return (error);
1308                 }
1309                 addr = *nam;
1310                 /* if I'm V6ONLY, convert it to v4-mapped */
1311                 if (SCTP_IPV6_V6ONLY(inp6)) {
1312                         struct sockaddr_in6 sin6;
1313
1314                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1315                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1316                 }
1317         }
1318 #endif
1319         return (error);
1320 }
1321
1322 struct pr_usrreqs sctp6_usrreqs = {
1323         .pru_abort = sctp6_abort,
1324         .pru_accept = sctp_accept,
1325         .pru_attach = sctp6_attach,
1326         .pru_bind = sctp6_bind,
1327         .pru_connect = sctp6_connect,
1328         .pru_control = in6_control,
1329         .pru_close = sctp6_close,
1330         .pru_detach = sctp6_close,
1331         .pru_sopoll = sopoll_generic,
1332         .pru_flush = sctp_flush,
1333         .pru_disconnect = sctp6_disconnect,
1334         .pru_listen = sctp_listen,
1335         .pru_peeraddr = sctp6_getpeeraddr,
1336         .pru_send = sctp6_send,
1337         .pru_shutdown = sctp_shutdown,
1338         .pru_sockaddr = sctp6_in6getaddr,
1339         .pru_sosend = sctp_sosend,
1340         .pru_soreceive = sctp_soreceive
1341 };