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