17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
545916cd2Sjpk * Common Development and Distribution License (the "License").
645916cd2Sjpk * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2177c67f2fSkcpoon
227c478bd9Sstevel@tonic-gate /*
235dd46ab5SKacheong Poon * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <sys/stream.h>
297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
307c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
317c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
3245916cd2Sjpk #include <sys/tsol/tnet.h>
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate #include <netinet/in.h>
357c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
367c478bd9Sstevel@tonic-gate
37bd670b35SErik Nordmark #include <inet/ipsec_impl.h>
387c478bd9Sstevel@tonic-gate #include <inet/common.h>
397c478bd9Sstevel@tonic-gate #include <inet/ip.h>
407c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
41bd670b35SErik Nordmark #include <inet/ipsec_impl.h>
427c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
437c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h>
447c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
457c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h>
467c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
477c478bd9Sstevel@tonic-gate #include "sctp_asconf.h"
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate ssize_t
sctp_link_abort(mblk_t * mp,uint16_t serror,char * details,size_t len,int iserror,boolean_t tbit)507c478bd9Sstevel@tonic-gate sctp_link_abort(mblk_t *mp, uint16_t serror, char *details, size_t len,
517c478bd9Sstevel@tonic-gate int iserror, boolean_t tbit)
527c478bd9Sstevel@tonic-gate {
537c478bd9Sstevel@tonic-gate size_t alen;
547c478bd9Sstevel@tonic-gate mblk_t *amp;
557c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *acp;
567c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *eph;
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate ASSERT(mp != NULL && mp->b_cont == NULL);
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate alen = sizeof (*acp) + (serror != 0 ? (sizeof (*eph) + len) : 0);
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate amp = allocb(alen, BPRI_MED);
637c478bd9Sstevel@tonic-gate if (amp == NULL) {
647c478bd9Sstevel@tonic-gate return (-1);
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate amp->b_wptr = amp->b_rptr + alen;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate /* Chunk header */
707c478bd9Sstevel@tonic-gate acp = (sctp_chunk_hdr_t *)amp->b_rptr;
717c478bd9Sstevel@tonic-gate acp->sch_id = iserror ? CHUNK_ERROR : CHUNK_ABORT;
727c478bd9Sstevel@tonic-gate acp->sch_flags = 0;
737c478bd9Sstevel@tonic-gate acp->sch_len = htons(alen);
747c478bd9Sstevel@tonic-gate if (tbit)
757c478bd9Sstevel@tonic-gate SCTP_SET_TBIT(acp);
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate linkb(mp, amp);
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate if (serror == 0) {
807c478bd9Sstevel@tonic-gate return (alen);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate eph = (sctp_parm_hdr_t *)(acp + 1);
847c478bd9Sstevel@tonic-gate eph->sph_type = htons(serror);
857c478bd9Sstevel@tonic-gate eph->sph_len = htons(len + sizeof (*eph));
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate if (len > 0) {
887c478bd9Sstevel@tonic-gate bcopy(details, eph + 1, len);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate /* XXX pad */
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate return (alen);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate void
sctp_user_abort(sctp_t * sctp,mblk_t * data)97e6f13f86SKacheong Poon sctp_user_abort(sctp_t *sctp, mblk_t *data)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate mblk_t *mp;
1007c478bd9Sstevel@tonic-gate int len, hdrlen;
1017c478bd9Sstevel@tonic-gate char *cause;
1027c478bd9Sstevel@tonic-gate sctp_faddr_t *fp = sctp->sctp_current;
103*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ip_xmit_attr_t *ixa = fp->sf_ixa;
104f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps;
1057c478bd9Sstevel@tonic-gate
1065f621db6SAnil udupa /*
1075f621db6SAnil udupa * Don't need notification if connection is not yet setup,
1085f621db6SAnil udupa * call sctp_clean_death() to reclaim resources.
1095f621db6SAnil udupa * Any pending connect call(s) will error out.
1105f621db6SAnil udupa */
1115f621db6SAnil udupa if (sctp->sctp_state < SCTPS_COOKIE_WAIT) {
1125f621db6SAnil udupa sctp_clean_death(sctp, ECONNABORTED);
1135f621db6SAnil udupa return;
1145f621db6SAnil udupa }
1155f621db6SAnil udupa
1167c478bd9Sstevel@tonic-gate mp = sctp_make_mp(sctp, fp, 0);
11777c67f2fSkcpoon if (mp == NULL) {
118f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_user_abort_failed);
1197c478bd9Sstevel@tonic-gate return;
12077c67f2fSkcpoon }
12177c67f2fSkcpoon
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate * Create abort chunk.
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate if (data) {
126*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_isv4) {
1277c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr_len;
1287c478bd9Sstevel@tonic-gate } else {
1297c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr6_len;
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t);
1327c478bd9Sstevel@tonic-gate cause = (char *)data->b_rptr;
1337c478bd9Sstevel@tonic-gate len = data->b_wptr - data->b_rptr;
1347c478bd9Sstevel@tonic-gate
135*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (len + hdrlen > fp->sf_pmss) {
136*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India len = fp->sf_pmss - hdrlen;
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate } else {
1397c478bd9Sstevel@tonic-gate cause = NULL;
1407c478bd9Sstevel@tonic-gate len = 0;
1417c478bd9Sstevel@tonic-gate }
142e6f13f86SKacheong Poon /*
143e6f13f86SKacheong Poon * Since it is a user abort, we should have the sctp_t and hence
144e6f13f86SKacheong Poon * the correct verification tag. So we should not set the T-bit
145e6f13f86SKacheong Poon * in the ABORT.
146e6f13f86SKacheong Poon */
1477c478bd9Sstevel@tonic-gate if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0,
148e6f13f86SKacheong Poon B_FALSE)) < 0) {
1497c478bd9Sstevel@tonic-gate freemsg(mp);
1507c478bd9Sstevel@tonic-gate return;
1517c478bd9Sstevel@tonic-gate }
1525dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpAborted);
1537c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_opkts);
1547c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks);
1557c478bd9Sstevel@tonic-gate
156bd670b35SErik Nordmark sctp_set_iplen(sctp, mp, ixa);
157bd670b35SErik Nordmark ASSERT(ixa->ixa_ire != NULL);
158bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL);
159bd670b35SErik Nordmark
160bd670b35SErik Nordmark (void) conn_ip_output(mp, ixa);
161e6f13f86SKacheong Poon
162e6f13f86SKacheong Poon sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
163e6f13f86SKacheong Poon sctp_clean_death(sctp, ECONNABORTED);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate * If iserror == 0, sends an abort. If iserror != 0, sends an error.
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate void
sctp_send_abort(sctp_t * sctp,uint32_t vtag,uint16_t serror,char * details,size_t len,mblk_t * inmp,int iserror,boolean_t tbit,ip_recv_attr_t * ira)1707c478bd9Sstevel@tonic-gate sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details,
171bd670b35SErik Nordmark size_t len, mblk_t *inmp, int iserror, boolean_t tbit, ip_recv_attr_t *ira)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate mblk_t *hmp;
1757c478bd9Sstevel@tonic-gate uint32_t ip_hdr_len;
1767c478bd9Sstevel@tonic-gate ipha_t *iniph;
177bd670b35SErik Nordmark ipha_t *ahiph = NULL;
1787c478bd9Sstevel@tonic-gate ip6_t *inip6h;
179bd670b35SErik Nordmark ip6_t *ahip6h = NULL;
1807c478bd9Sstevel@tonic-gate sctp_hdr_t *sh;
1817c478bd9Sstevel@tonic-gate sctp_hdr_t *insh;
1827c478bd9Sstevel@tonic-gate size_t ahlen;
1837c478bd9Sstevel@tonic-gate uchar_t *p;
1847c478bd9Sstevel@tonic-gate ssize_t alen;
1857c478bd9Sstevel@tonic-gate int isv4;
186bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp;
187f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps;
188bd670b35SErik Nordmark ip_xmit_attr_t *ixa;
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
1917c478bd9Sstevel@tonic-gate if (isv4) {
1927c478bd9Sstevel@tonic-gate ahlen = sctp->sctp_hdr_len;
1937c478bd9Sstevel@tonic-gate } else {
1947c478bd9Sstevel@tonic-gate ahlen = sctp->sctp_hdr6_len;
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate
19745916cd2Sjpk /*
19845916cd2Sjpk * If this is a labeled system, then check to see if we're allowed to
19945916cd2Sjpk * send a response to this particular sender. If not, then just drop.
20045916cd2Sjpk */
201bd670b35SErik Nordmark if (is_system_labeled() && !tsol_can_reply_error(inmp, ira))
20245916cd2Sjpk return;
20345916cd2Sjpk
204bd670b35SErik Nordmark hmp = allocb(sctps->sctps_wroff_xtra + ahlen, BPRI_MED);
2057c478bd9Sstevel@tonic-gate if (hmp == NULL) {
2067c478bd9Sstevel@tonic-gate /* XXX no resources */
2077c478bd9Sstevel@tonic-gate return;
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate /* copy in the IP / SCTP header */
211f4b3ec61Sdh p = hmp->b_rptr + sctps->sctps_wroff_xtra;
2127c478bd9Sstevel@tonic-gate hmp->b_rptr = p;
2137c478bd9Sstevel@tonic-gate hmp->b_wptr = p + ahlen;
2147c478bd9Sstevel@tonic-gate if (isv4) {
2157c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len);
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate * Composite is likely incomplete at this point, so pull
2187c478bd9Sstevel@tonic-gate * info from the incoming IP / SCTP headers.
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate ahiph = (ipha_t *)p;
2217c478bd9Sstevel@tonic-gate iniph = (ipha_t *)inmp->b_rptr;
2227c478bd9Sstevel@tonic-gate ip_hdr_len = IPH_HDR_LENGTH(inmp->b_rptr);
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len);
2257c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(sh));
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate insh = (sctp_hdr_t *)((uchar_t *)iniph + ip_hdr_len);
2287c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(insh));
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate /* Copy in the peer's IP addr */
2317c478bd9Sstevel@tonic-gate ahiph->ipha_dst = iniph->ipha_src;
2327c478bd9Sstevel@tonic-gate ahiph->ipha_src = iniph->ipha_dst;
2337c478bd9Sstevel@tonic-gate } else {
2347c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len);
2357c478bd9Sstevel@tonic-gate ahip6h = (ip6_t *)p;
2367c478bd9Sstevel@tonic-gate inip6h = (ip6_t *)inmp->b_rptr;
237e6f13f86SKacheong Poon ip_hdr_len = ip_hdr_length_v6(inmp, inip6h);
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len);
2407c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(sh));
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate insh = (sctp_hdr_t *)((uchar_t *)inip6h + ip_hdr_len);
2437c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(insh));
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate /* Copy in the peer's IP addr */
2467c478bd9Sstevel@tonic-gate ahip6h->ip6_dst = inip6h->ip6_src;
2477c478bd9Sstevel@tonic-gate ahip6h->ip6_src = inip6h->ip6_dst;
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate /* Fill in the holes in the SCTP common header */
2517c478bd9Sstevel@tonic-gate sh->sh_sport = insh->sh_dport;
2527c478bd9Sstevel@tonic-gate sh->sh_dport = insh->sh_sport;
2537c478bd9Sstevel@tonic-gate sh->sh_verf = vtag;
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate /* Link in the abort chunk */
2567c478bd9Sstevel@tonic-gate if ((alen = sctp_link_abort(hmp, serror, details, len, iserror, tbit))
2577c478bd9Sstevel@tonic-gate < 0) {
2587c478bd9Sstevel@tonic-gate freemsg(hmp);
2597c478bd9Sstevel@tonic-gate return;
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate
262bd670b35SErik Nordmark /*
263bd670b35SErik Nordmark * Base the transmission on any routing-related socket options
264bd670b35SErik Nordmark * that have been set on the listener/connection.
265bd670b35SErik Nordmark */
266bd670b35SErik Nordmark ixa = conn_get_ixa_exclusive(connp);
267bd670b35SErik Nordmark if (ixa == NULL) {
268bd670b35SErik Nordmark freemsg(hmp);
269bd670b35SErik Nordmark return;
270bd670b35SErik Nordmark }
271bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_VERIFY_PMTU;
272bd670b35SErik Nordmark
273bd670b35SErik Nordmark ixa->ixa_pktlen = ahlen + alen;
2747c478bd9Sstevel@tonic-gate if (isv4) {
275bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_IS_IPV4;
276bd670b35SErik Nordmark ahiph->ipha_length = htons(ixa->ixa_pktlen);
277bd670b35SErik Nordmark ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr_len;
2787c478bd9Sstevel@tonic-gate } else {
279bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_IS_IPV4;
280bd670b35SErik Nordmark ahip6h->ip6_plen = htons(ixa->ixa_pktlen - IPV6_HDR_LEN);
281bd670b35SErik Nordmark ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr6_len;
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2845dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpAborted);
2857c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks);
2867c478bd9Sstevel@tonic-gate
287bd670b35SErik Nordmark if (is_system_labeled() && ixa->ixa_tsl != NULL) {
288bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL);
28945916cd2Sjpk
290bd670b35SErik Nordmark ixa->ixa_tsl = ira->ira_tsl; /* A multi-level responder */
29145916cd2Sjpk }
29245916cd2Sjpk
293bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IPSEC_SECURE) {
294bd670b35SErik Nordmark /*
295bd670b35SErik Nordmark * Apply IPsec based on how IPsec was applied to
296bd670b35SErik Nordmark * the packet that caused the abort.
297bd670b35SErik Nordmark */
298bd670b35SErik Nordmark if (!ipsec_in_to_out(ira, ixa, hmp, ahiph, ahip6h)) {
299bd670b35SErik Nordmark ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip;
30045916cd2Sjpk
301bd670b35SErik Nordmark BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
302bd670b35SErik Nordmark /* Note: mp already consumed and ip_drop_packet done */
303bd670b35SErik Nordmark ixa_refrele(ixa);
304bd670b35SErik Nordmark return;
305bd670b35SErik Nordmark }
306f4b3ec61Sdh } else {
307bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_NO_IPSEC;
308f4b3ec61Sdh }
309bd670b35SErik Nordmark
310bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts);
311bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_obchunks);
312bd670b35SErik Nordmark
313bd670b35SErik Nordmark (void) ip_output_simple(hmp, ixa);
314bd670b35SErik Nordmark ixa_refrele(ixa);
315bd670b35SErik Nordmark }
316bd670b35SErik Nordmark
317bd670b35SErik Nordmark /*
318bd670b35SErik Nordmark * OOTB version of the above.
319bd670b35SErik Nordmark * If iserror == 0, sends an abort. If iserror != 0, sends an error.
320bd670b35SErik Nordmark */
321bd670b35SErik Nordmark void
sctp_ootb_send_abort(uint32_t vtag,uint16_t serror,char * details,size_t len,const mblk_t * inmp,int iserror,boolean_t tbit,ip_recv_attr_t * ira,ip_stack_t * ipst)322bd670b35SErik Nordmark sctp_ootb_send_abort(uint32_t vtag, uint16_t serror, char *details,
323bd670b35SErik Nordmark size_t len, const mblk_t *inmp, int iserror, boolean_t tbit,
324bd670b35SErik Nordmark ip_recv_attr_t *ira, ip_stack_t *ipst)
325bd670b35SErik Nordmark {
326bd670b35SErik Nordmark uint32_t ip_hdr_len;
327bd670b35SErik Nordmark size_t ahlen;
328bd670b35SErik Nordmark ipha_t *ipha = NULL;
329bd670b35SErik Nordmark ip6_t *ip6h = NULL;
330bd670b35SErik Nordmark sctp_hdr_t *insctph;
331bd670b35SErik Nordmark int i;
332bd670b35SErik Nordmark uint16_t port;
333bd670b35SErik Nordmark ssize_t alen;
334bd670b35SErik Nordmark int isv4;
335bd670b35SErik Nordmark mblk_t *mp;
336bd670b35SErik Nordmark netstack_t *ns = ipst->ips_netstack;
337bd670b35SErik Nordmark sctp_stack_t *sctps = ns->netstack_sctp;
338bd670b35SErik Nordmark ip_xmit_attr_t ixas;
339bd670b35SErik Nordmark
340bd670b35SErik Nordmark bzero(&ixas, sizeof (ixas));
341bd670b35SErik Nordmark
342bd670b35SErik Nordmark isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
343bd670b35SErik Nordmark ip_hdr_len = ira->ira_ip_hdr_length;
344bd670b35SErik Nordmark ahlen = ip_hdr_len + sizeof (sctp_hdr_t);
345bd670b35SErik Nordmark
3467c478bd9Sstevel@tonic-gate /*
347bd670b35SErik Nordmark * If this is a labeled system, then check to see if we're allowed to
348bd670b35SErik Nordmark * send a response to this particular sender. If not, then just drop.
3497c478bd9Sstevel@tonic-gate */
350bd670b35SErik Nordmark if (is_system_labeled() && !tsol_can_reply_error(inmp, ira))
3517c478bd9Sstevel@tonic-gate return;
352bd670b35SErik Nordmark
353bd670b35SErik Nordmark mp = allocb(ahlen + sctps->sctps_wroff_xtra, BPRI_MED);
354bd670b35SErik Nordmark if (mp == NULL) {
3557c478bd9Sstevel@tonic-gate return;
3567c478bd9Sstevel@tonic-gate }
357bd670b35SErik Nordmark mp->b_rptr += sctps->sctps_wroff_xtra;
358bd670b35SErik Nordmark mp->b_wptr = mp->b_rptr + ahlen;
359bd670b35SErik Nordmark bcopy(inmp->b_rptr, mp->b_rptr, ahlen);
360bd670b35SErik Nordmark
3617c478bd9Sstevel@tonic-gate /*
362bd670b35SErik Nordmark * We follow the logic in tcp_xmit_early_reset() in that we skip
363bd670b35SErik Nordmark * reversing source route (i.e. replace all IP options with EOL).
3647c478bd9Sstevel@tonic-gate */
365bd670b35SErik Nordmark if (isv4) {
366bd670b35SErik Nordmark ipaddr_t v4addr;
367bd670b35SErik Nordmark
368bd670b35SErik Nordmark ipha = (ipha_t *)mp->b_rptr;
369bd670b35SErik Nordmark for (i = IP_SIMPLE_HDR_LENGTH; i < (int)ip_hdr_len; i++)
370bd670b35SErik Nordmark mp->b_rptr[i] = IPOPT_EOL;
371bd670b35SErik Nordmark /* Swap addresses */
372bd670b35SErik Nordmark ipha->ipha_length = htons(ahlen);
373bd670b35SErik Nordmark v4addr = ipha->ipha_src;
374bd670b35SErik Nordmark ipha->ipha_src = ipha->ipha_dst;
375bd670b35SErik Nordmark ipha->ipha_dst = v4addr;
376bd670b35SErik Nordmark ipha->ipha_ident = 0;
377bd670b35SErik Nordmark ipha->ipha_ttl = (uchar_t)sctps->sctps_ipv4_ttl;
378bd670b35SErik Nordmark
379bd670b35SErik Nordmark ixas.ixa_flags = IXAF_BASIC_SIMPLE_V4;
380bd670b35SErik Nordmark } else {
381bd670b35SErik Nordmark in6_addr_t v6addr;
382bd670b35SErik Nordmark
383bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr;
384bd670b35SErik Nordmark /* Remove any extension headers assuming partial overlay */
385bd670b35SErik Nordmark if (ip_hdr_len > IPV6_HDR_LEN) {
386bd670b35SErik Nordmark uint8_t *to;
387bd670b35SErik Nordmark
388bd670b35SErik Nordmark to = mp->b_rptr + ip_hdr_len - IPV6_HDR_LEN;
389bd670b35SErik Nordmark ovbcopy(ip6h, to, IPV6_HDR_LEN);
390bd670b35SErik Nordmark mp->b_rptr += ip_hdr_len - IPV6_HDR_LEN;
391bd670b35SErik Nordmark ip_hdr_len = IPV6_HDR_LEN;
392bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr;
393bd670b35SErik Nordmark ip6h->ip6_nxt = IPPROTO_SCTP;
394bd670b35SErik Nordmark ahlen = ip_hdr_len + sizeof (sctp_hdr_t);
395bd670b35SErik Nordmark }
396bd670b35SErik Nordmark ip6h->ip6_plen = htons(ahlen - IPV6_HDR_LEN);
397bd670b35SErik Nordmark v6addr = ip6h->ip6_src;
398bd670b35SErik Nordmark ip6h->ip6_src = ip6h->ip6_dst;
399bd670b35SErik Nordmark ip6h->ip6_dst = v6addr;
400bd670b35SErik Nordmark ip6h->ip6_hops = (uchar_t)sctps->sctps_ipv6_hoplimit;
401bd670b35SErik Nordmark
402bd670b35SErik Nordmark ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6;
403bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_dst)) {
404bd670b35SErik Nordmark ixas.ixa_flags |= IXAF_SCOPEID_SET;
405bd670b35SErik Nordmark ixas.ixa_scopeid = ira->ira_ruifindex;
406bd670b35SErik Nordmark }
407bd670b35SErik Nordmark }
408bd670b35SErik Nordmark insctph = (sctp_hdr_t *)(mp->b_rptr + ip_hdr_len);
409bd670b35SErik Nordmark
410bd670b35SErik Nordmark /* Swap ports. Verification tag is reused. */
411bd670b35SErik Nordmark port = insctph->sh_sport;
412bd670b35SErik Nordmark insctph->sh_sport = insctph->sh_dport;
413bd670b35SErik Nordmark insctph->sh_dport = port;
414bd670b35SErik Nordmark insctph->sh_verf = vtag;
415bd670b35SErik Nordmark
416bd670b35SErik Nordmark /* Link in the abort chunk */
417bd670b35SErik Nordmark if ((alen = sctp_link_abort(mp, serror, details, len, iserror, tbit))
418bd670b35SErik Nordmark < 0) {
419bd670b35SErik Nordmark freemsg(mp);
420bd670b35SErik Nordmark return;
421bd670b35SErik Nordmark }
422bd670b35SErik Nordmark
423bd670b35SErik Nordmark ixas.ixa_pktlen = ahlen + alen;
424bd670b35SErik Nordmark ixas.ixa_ip_hdr_length = ip_hdr_len;
425bd670b35SErik Nordmark
426bd670b35SErik Nordmark if (isv4) {
427bd670b35SErik Nordmark ipha->ipha_length = htons(ixas.ixa_pktlen);
428bd670b35SErik Nordmark } else {
429bd670b35SErik Nordmark ip6h->ip6_plen = htons(ixas.ixa_pktlen - IPV6_HDR_LEN);
4307c478bd9Sstevel@tonic-gate }
431bd670b35SErik Nordmark
432bd670b35SErik Nordmark ixas.ixa_protocol = IPPROTO_SCTP;
433bd670b35SErik Nordmark ixas.ixa_zoneid = ira->ira_zoneid;
434bd670b35SErik Nordmark ixas.ixa_ipst = ipst;
435bd670b35SErik Nordmark ixas.ixa_ifindex = 0;
436bd670b35SErik Nordmark
4375dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpAborted);
438bd670b35SErik Nordmark
439bd670b35SErik Nordmark if (is_system_labeled()) {
440bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL);
441bd670b35SErik Nordmark
442bd670b35SErik Nordmark ixas.ixa_tsl = ira->ira_tsl; /* A multi-level responder */
443bd670b35SErik Nordmark }
444bd670b35SErik Nordmark
445bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IPSEC_SECURE) {
446bd670b35SErik Nordmark /*
447bd670b35SErik Nordmark * Apply IPsec based on how IPsec was applied to
448bd670b35SErik Nordmark * the packet that was out of the blue.
449bd670b35SErik Nordmark */
450bd670b35SErik Nordmark if (!ipsec_in_to_out(ira, &ixas, mp, ipha, ip6h)) {
451bd670b35SErik Nordmark BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
452bd670b35SErik Nordmark /* Note: mp already consumed and ip_drop_packet done */
453bd670b35SErik Nordmark return;
454bd670b35SErik Nordmark }
455bd670b35SErik Nordmark } else {
456bd670b35SErik Nordmark /*
457bd670b35SErik Nordmark * This is in clear. The abort message we are building
458bd670b35SErik Nordmark * here should go out in clear, independent of our policy.
459bd670b35SErik Nordmark */
460bd670b35SErik Nordmark ixas.ixa_flags |= IXAF_NO_IPSEC;
461bd670b35SErik Nordmark }
462bd670b35SErik Nordmark
463bd670b35SErik Nordmark (void) ip_output_simple(mp, &ixas);
464bd670b35SErik Nordmark ixa_cleanup(&ixas);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4687c478bd9Sstevel@tonic-gate mblk_t *
sctp_make_err(sctp_t * sctp,uint16_t serror,void * details,size_t len)4697c478bd9Sstevel@tonic-gate sctp_make_err(sctp_t *sctp, uint16_t serror, void *details, size_t len)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate mblk_t *emp;
4737c478bd9Sstevel@tonic-gate size_t elen;
4747c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *ecp;
4757c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *eph;
4767c478bd9Sstevel@tonic-gate int pad;
4777c478bd9Sstevel@tonic-gate
4787f093707Skcpoon if ((pad = len % SCTP_ALIGN) != 0) {
4797f093707Skcpoon pad = SCTP_ALIGN - pad;
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate elen = sizeof (*ecp) + sizeof (*eph) + len;
4837c478bd9Sstevel@tonic-gate emp = allocb(elen + pad, BPRI_MED);
4847c478bd9Sstevel@tonic-gate if (emp == NULL) {
4857c478bd9Sstevel@tonic-gate return (NULL);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate emp->b_wptr = emp->b_rptr + elen + pad;
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate /* Chunk header */
4917c478bd9Sstevel@tonic-gate ecp = (sctp_chunk_hdr_t *)emp->b_rptr;
4927c478bd9Sstevel@tonic-gate ecp->sch_id = CHUNK_ERROR;
4937c478bd9Sstevel@tonic-gate ecp->sch_flags = 0;
4947c478bd9Sstevel@tonic-gate ecp->sch_len = htons(elen);
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate eph = (sctp_parm_hdr_t *)(ecp + 1);
4977c478bd9Sstevel@tonic-gate eph->sph_type = htons(serror);
4987c478bd9Sstevel@tonic-gate eph->sph_len = htons(len + sizeof (*eph));
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate if (len > 0) {
5017c478bd9Sstevel@tonic-gate bcopy(details, eph + 1, len);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate if (pad != 0) {
5057c478bd9Sstevel@tonic-gate bzero((uchar_t *)(eph + 1) + len, pad);
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate return (emp);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate
5117f093707Skcpoon /*
5127f093707Skcpoon * Called from sctp_input_data() to add one error chunk to the error
5137f093707Skcpoon * chunks list. The error chunks list will be processed at the end
5147f093707Skcpoon * of sctp_input_data() by calling sctp_process_err().
5157f093707Skcpoon */
5167c478bd9Sstevel@tonic-gate void
sctp_add_err(sctp_t * sctp,uint16_t serror,void * details,size_t len,sctp_faddr_t * dest)5177f093707Skcpoon sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len,
5187f093707Skcpoon sctp_faddr_t *dest)
5197c478bd9Sstevel@tonic-gate {
5207f093707Skcpoon sctp_stack_t *sctps = sctp->sctp_sctps;
5217f093707Skcpoon mblk_t *emp;
5227f093707Skcpoon uint32_t emp_len;
5237f093707Skcpoon uint32_t mss;
5247f093707Skcpoon mblk_t *sendmp;
5257f093707Skcpoon sctp_faddr_t *fp;
5267c478bd9Sstevel@tonic-gate
5277f093707Skcpoon emp = sctp_make_err(sctp, serror, details, len);
5287f093707Skcpoon if (emp == NULL)
5297f093707Skcpoon return;
5307f093707Skcpoon emp_len = MBLKL(emp);
5317f093707Skcpoon if (sctp->sctp_err_chunks != NULL) {
5327f093707Skcpoon fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks);
5337c478bd9Sstevel@tonic-gate } else {
5347f093707Skcpoon fp = dest;
5357f093707Skcpoon SCTP_SET_CHUNK_DEST(emp, dest);
5367f093707Skcpoon }
537*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India mss = fp->sf_pmss;
5387f093707Skcpoon
5397f093707Skcpoon /*
5407f093707Skcpoon * If the current output packet cannot include the new error chunk,
5417f093707Skcpoon * send out the current packet and then add the new error chunk
5427f093707Skcpoon * to the new output packet.
5437f093707Skcpoon */
5447f093707Skcpoon if (sctp->sctp_err_len + emp_len > mss) {
5457f093707Skcpoon if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
546f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_err_failed);
5477f093707Skcpoon /* Just free the latest error chunk. */
5487f093707Skcpoon freeb(emp);
5497c478bd9Sstevel@tonic-gate return;
5507c478bd9Sstevel@tonic-gate }
5517f093707Skcpoon sendmp->b_cont = sctp->sctp_err_chunks;
552*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, sendmp, fp->sf_ixa);
553*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(sendmp, fp->sf_ixa);
554bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts);
5557f093707Skcpoon
5567f093707Skcpoon sctp->sctp_err_chunks = emp;
5577f093707Skcpoon sctp->sctp_err_len = emp_len;
5587f093707Skcpoon SCTP_SET_CHUNK_DEST(emp, dest);
5597f093707Skcpoon } else {
5607f093707Skcpoon if (sctp->sctp_err_chunks != NULL)
5617f093707Skcpoon linkb(sctp->sctp_err_chunks, emp);
5627f093707Skcpoon else
5637f093707Skcpoon sctp->sctp_err_chunks = emp;
5647f093707Skcpoon sctp->sctp_err_len += emp_len;
5657c478bd9Sstevel@tonic-gate }
5667f093707Skcpoon /* Assume that we will send it out... */
5677c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks);
5687f093707Skcpoon }
5697c478bd9Sstevel@tonic-gate
5707f093707Skcpoon /*
5717f093707Skcpoon * Called from sctp_input_data() to send out error chunks created during
5727f093707Skcpoon * the processing of all the chunks in an incoming packet.
5737f093707Skcpoon */
5747f093707Skcpoon void
sctp_process_err(sctp_t * sctp)5757f093707Skcpoon sctp_process_err(sctp_t *sctp)
5767f093707Skcpoon {
5777f093707Skcpoon sctp_stack_t *sctps = sctp->sctp_sctps;
5787f093707Skcpoon mblk_t *errmp;
5797f093707Skcpoon mblk_t *sendmp;
580bd670b35SErik Nordmark sctp_faddr_t *fp;
5817f093707Skcpoon
5827f093707Skcpoon ASSERT(sctp->sctp_err_chunks != NULL);
5837f093707Skcpoon errmp = sctp->sctp_err_chunks;
584bd670b35SErik Nordmark fp = SCTP_CHUNK_DEST(errmp);
585bd670b35SErik Nordmark if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
5867f093707Skcpoon SCTP_KSTAT(sctps, sctp_send_err_failed);
5877f093707Skcpoon freemsg(errmp);
5887f093707Skcpoon goto done;
5897f093707Skcpoon }
5907f093707Skcpoon sendmp->b_cont = errmp;
591*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, sendmp, fp->sf_ixa);
592*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(sendmp, fp->sf_ixa);
593bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts);
5947f093707Skcpoon done:
5957f093707Skcpoon sctp->sctp_err_chunks = NULL;
5967f093707Skcpoon sctp->sctp_err_len = 0;
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate /*
6007c478bd9Sstevel@tonic-gate * Returns 0 on non-fatal error, otherwise a system error on fatal
6017c478bd9Sstevel@tonic-gate * error.
6027c478bd9Sstevel@tonic-gate */
6037c478bd9Sstevel@tonic-gate int
sctp_handle_error(sctp_t * sctp,sctp_hdr_t * sctph,sctp_chunk_hdr_t * ch,mblk_t * mp,ip_recv_attr_t * ira)6047c478bd9Sstevel@tonic-gate sctp_handle_error(sctp_t *sctp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ch,
605bd670b35SErik Nordmark mblk_t *mp, ip_recv_attr_t *ira)
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *errh;
6087c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *uch;
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate if (ch->sch_len == htons(sizeof (*ch))) {
6117c478bd9Sstevel@tonic-gate /* no error cause given */
6127c478bd9Sstevel@tonic-gate return (0);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate errh = (sctp_parm_hdr_t *)(ch + 1);
6158dfac042SAnil udupa sctp_error_event(sctp, ch, B_FALSE);
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate switch (errh->sph_type) {
6187c478bd9Sstevel@tonic-gate /*
6197c478bd9Sstevel@tonic-gate * Both BAD_SID and NO_USR_DATA errors
6207c478bd9Sstevel@tonic-gate * indicate a serious bug in our stack,
6217c478bd9Sstevel@tonic-gate * so complain and abort the association.
6227c478bd9Sstevel@tonic-gate */
6237c478bd9Sstevel@tonic-gate case SCTP_ERR_BAD_SID:
6247c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "BUG! send to invalid SID");
625bd670b35SErik Nordmark sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0,
626bd670b35SErik Nordmark ira);
6277c478bd9Sstevel@tonic-gate return (ECONNABORTED);
6287c478bd9Sstevel@tonic-gate case SCTP_ERR_NO_USR_DATA:
6297c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "BUG! no usr data");
630bd670b35SErik Nordmark sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0,
631bd670b35SErik Nordmark ira);
6327c478bd9Sstevel@tonic-gate return (ECONNABORTED);
6337c478bd9Sstevel@tonic-gate case SCTP_ERR_UNREC_CHUNK:
6347c478bd9Sstevel@tonic-gate /* Pull out the unrecognized chunk type */
6357c478bd9Sstevel@tonic-gate if (ntohs(errh->sph_len) < (sizeof (*errh) + sizeof (*uch))) {
6367c478bd9Sstevel@tonic-gate /* Not enough to process */
6377c478bd9Sstevel@tonic-gate return (0);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate uch = (sctp_chunk_hdr_t *)(errh + 1);
6407c478bd9Sstevel@tonic-gate if (uch->sch_id == CHUNK_ASCONF) {
6417c478bd9Sstevel@tonic-gate /* Turn on ASCONF sending */
6427c478bd9Sstevel@tonic-gate sctp->sctp_understands_asconf = B_FALSE;
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate * Hand off to asconf to clear out the unacked
6457c478bd9Sstevel@tonic-gate * asconf chunk.
6467c478bd9Sstevel@tonic-gate */
6477c478bd9Sstevel@tonic-gate if (ntohs(uch->sch_len) !=
6487c478bd9Sstevel@tonic-gate (ntohs(errh->sph_len) - sizeof (*errh))) {
6497c478bd9Sstevel@tonic-gate /* malformed */
6507c478bd9Sstevel@tonic-gate dprint(0, ("Malformed Unrec Chunk error\n"));
6517c478bd9Sstevel@tonic-gate return (0);
6527c478bd9Sstevel@tonic-gate }
6531d8c4025Svi sctp_asconf_free_cxmit(sctp, uch);
6547c478bd9Sstevel@tonic-gate return (0);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate /* Else drop it */
6577c478bd9Sstevel@tonic-gate break;
6587c478bd9Sstevel@tonic-gate default:
6597c478bd9Sstevel@tonic-gate break;
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate
6627c478bd9Sstevel@tonic-gate return (0);
6637c478bd9Sstevel@tonic-gate }
664