Home | History | Annotate | Download | only in sctp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <sys/systm.h>
     29 #include <sys/stream.h>
     30 #include <sys/cmn_err.h>
     31 #include <sys/ddi.h>
     32 #include <sys/strsubr.h>
     33 #include <sys/tsol/tnet.h>
     34 
     35 #include <netinet/in.h>
     36 #include <netinet/ip6.h>
     37 
     38 #include <inet/ipsec_impl.h>
     39 #include <inet/common.h>
     40 #include <inet/ip.h>
     41 #include <inet/ip6.h>
     42 #include <inet/ipsec_impl.h>
     43 #include <inet/mib2.h>
     44 #include <inet/sctp_ip.h>
     45 #include <inet/ipclassifier.h>
     46 #include <inet/ip_ire.h>
     47 #include "sctp_impl.h"
     48 #include "sctp_asconf.h"
     49 
     50 ssize_t
     51 sctp_link_abort(mblk_t *mp, uint16_t serror, char *details, size_t len,
     52     int iserror, boolean_t tbit)
     53 {
     54 	size_t alen;
     55 	mblk_t *amp;
     56 	sctp_chunk_hdr_t *acp;
     57 	sctp_parm_hdr_t *eph;
     58 
     59 	ASSERT(mp != NULL && mp->b_cont == NULL);
     60 
     61 	alen = sizeof (*acp) + (serror != 0 ? (sizeof (*eph) + len) : 0);
     62 
     63 	amp = allocb(alen, BPRI_MED);
     64 	if (amp == NULL) {
     65 		return (-1);
     66 	}
     67 
     68 	amp->b_wptr = amp->b_rptr + alen;
     69 
     70 	/* Chunk header */
     71 	acp = (sctp_chunk_hdr_t *)amp->b_rptr;
     72 	acp->sch_id = iserror ? CHUNK_ERROR : CHUNK_ABORT;
     73 	acp->sch_flags = 0;
     74 	acp->sch_len = htons(alen);
     75 	if (tbit)
     76 		SCTP_SET_TBIT(acp);
     77 
     78 	linkb(mp, amp);
     79 
     80 	if (serror == 0) {
     81 		return (alen);
     82 	}
     83 
     84 	eph = (sctp_parm_hdr_t *)(acp + 1);
     85 	eph->sph_type = htons(serror);
     86 	eph->sph_len = htons(len + sizeof (*eph));
     87 
     88 	if (len > 0) {
     89 		bcopy(details, eph + 1, len);
     90 	}
     91 
     92 	/* XXX pad */
     93 
     94 	return (alen);
     95 }
     96 
     97 void
     98 sctp_user_abort(sctp_t *sctp, mblk_t *data)
     99 {
    100 	mblk_t *mp;
    101 	int len, hdrlen;
    102 	char *cause;
    103 	sctp_faddr_t *fp = sctp->sctp_current;
    104 	ip_xmit_attr_t	*ixa = fp->ixa;
    105 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    106 
    107 	/*
    108 	 * Don't need notification if connection is not yet setup,
    109 	 * call sctp_clean_death() to reclaim resources.
    110 	 * Any pending connect call(s) will error out.
    111 	 */
    112 	if (sctp->sctp_state < SCTPS_COOKIE_WAIT) {
    113 		sctp_clean_death(sctp, ECONNABORTED);
    114 		return;
    115 	}
    116 
    117 	mp = sctp_make_mp(sctp, fp, 0);
    118 	if (mp == NULL) {
    119 		SCTP_KSTAT(sctps, sctp_send_user_abort_failed);
    120 		return;
    121 	}
    122 
    123 	/*
    124 	 * Create abort chunk.
    125 	 */
    126 	if (data) {
    127 		if (fp->isv4) {
    128 			hdrlen = sctp->sctp_hdr_len;
    129 		} else {
    130 			hdrlen = sctp->sctp_hdr6_len;
    131 		}
    132 		hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t);
    133 		cause = (char *)data->b_rptr;
    134 		len = data->b_wptr - data->b_rptr;
    135 
    136 		if (len + hdrlen > fp->sfa_pmss) {
    137 			len = fp->sfa_pmss - hdrlen;
    138 		}
    139 	} else {
    140 		cause = NULL;
    141 		len = 0;
    142 	}
    143 	/*
    144 	 * Since it is a user abort, we should have the sctp_t and hence
    145 	 * the correct verification tag.  So we should not set the T-bit
    146 	 * in the ABORT.
    147 	 */
    148 	if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0,
    149 	    B_FALSE)) < 0) {
    150 		freemsg(mp);
    151 		return;
    152 	}
    153 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
    154 	BUMP_LOCAL(sctp->sctp_opkts);
    155 	BUMP_LOCAL(sctp->sctp_obchunks);
    156 
    157 	sctp_set_iplen(sctp, mp, ixa);
    158 	ASSERT(ixa->ixa_ire != NULL);
    159 	ASSERT(ixa->ixa_cred != NULL);
    160 
    161 	(void) conn_ip_output(mp, ixa);
    162 
    163 	sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
    164 	sctp_clean_death(sctp, ECONNABORTED);
    165 }
    166 
    167 /*
    168  * If iserror == 0, sends an abort. If iserror != 0, sends an error.
    169  */
    170 void
    171 sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details,
    172     size_t len, mblk_t *inmp, int iserror, boolean_t tbit, ip_recv_attr_t *ira)
    173 {
    174 
    175 	mblk_t		*hmp;
    176 	uint32_t	ip_hdr_len;
    177 	ipha_t		*iniph;
    178 	ipha_t		*ahiph = NULL;
    179 	ip6_t		*inip6h;
    180 	ip6_t		*ahip6h = NULL;
    181 	sctp_hdr_t	*sh;
    182 	sctp_hdr_t	*insh;
    183 	size_t		ahlen;
    184 	uchar_t		*p;
    185 	ssize_t		alen;
    186 	int		isv4;
    187 	conn_t		*connp = sctp->sctp_connp;
    188 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    189 	ip_xmit_attr_t	*ixa;
    190 
    191 	isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
    192 	if (isv4) {
    193 		ahlen = sctp->sctp_hdr_len;
    194 	} else {
    195 		ahlen = sctp->sctp_hdr6_len;
    196 	}
    197 
    198 	/*
    199 	 * If this is a labeled system, then check to see if we're allowed to
    200 	 * send a response to this particular sender.  If not, then just drop.
    201 	 */
    202 	if (is_system_labeled() && !tsol_can_reply_error(inmp, ira))
    203 		return;
    204 
    205 	hmp = allocb(sctps->sctps_wroff_xtra + ahlen, BPRI_MED);
    206 	if (hmp == NULL) {
    207 		/* XXX no resources */
    208 		return;
    209 	}
    210 
    211 	/* copy in the IP / SCTP header */
    212 	p = hmp->b_rptr + sctps->sctps_wroff_xtra;
    213 	hmp->b_rptr = p;
    214 	hmp->b_wptr = p + ahlen;
    215 	if (isv4) {
    216 		bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len);
    217 		/*
    218 		 * Composite is likely incomplete at this point, so pull
    219 		 * info from the incoming IP / SCTP headers.
    220 		 */
    221 		ahiph = (ipha_t *)p;
    222 		iniph = (ipha_t *)inmp->b_rptr;
    223 		ip_hdr_len = IPH_HDR_LENGTH(inmp->b_rptr);
    224 
    225 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len);
    226 		ASSERT(OK_32PTR(sh));
    227 
    228 		insh = (sctp_hdr_t *)((uchar_t *)iniph + ip_hdr_len);
    229 		ASSERT(OK_32PTR(insh));
    230 
    231 		/* Copy in the peer's IP addr */
    232 		ahiph->ipha_dst = iniph->ipha_src;
    233 		ahiph->ipha_src = iniph->ipha_dst;
    234 	} else {
    235 		bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len);
    236 		ahip6h = (ip6_t *)p;
    237 		inip6h = (ip6_t *)inmp->b_rptr;
    238 		ip_hdr_len = ip_hdr_length_v6(inmp, inip6h);
    239 
    240 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len);
    241 		ASSERT(OK_32PTR(sh));
    242 
    243 		insh = (sctp_hdr_t *)((uchar_t *)inip6h + ip_hdr_len);
    244 		ASSERT(OK_32PTR(insh));
    245 
    246 		/* Copy in the peer's IP addr */
    247 		ahip6h->ip6_dst = inip6h->ip6_src;
    248 		ahip6h->ip6_src = inip6h->ip6_dst;
    249 	}
    250 
    251 	/* Fill in the holes in the SCTP common header */
    252 	sh->sh_sport = insh->sh_dport;
    253 	sh->sh_dport = insh->sh_sport;
    254 	sh->sh_verf = vtag;
    255 
    256 	/* Link in the abort chunk */
    257 	if ((alen = sctp_link_abort(hmp, serror, details, len, iserror, tbit))
    258 	    < 0) {
    259 		freemsg(hmp);
    260 		return;
    261 	}
    262 
    263 	/*
    264 	 * Base the transmission on any routing-related socket options
    265 	 * that have been set on the listener/connection.
    266 	 */
    267 	ixa = conn_get_ixa_exclusive(connp);
    268 	if (ixa == NULL) {
    269 		freemsg(hmp);
    270 		return;
    271 	}
    272 	ixa->ixa_flags &= ~IXAF_VERIFY_PMTU;
    273 
    274 	ixa->ixa_pktlen = ahlen + alen;
    275 	if (isv4) {
    276 		ixa->ixa_flags |= IXAF_IS_IPV4;
    277 		ahiph->ipha_length = htons(ixa->ixa_pktlen);
    278 		ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr_len;
    279 	} else {
    280 		ixa->ixa_flags &= ~IXAF_IS_IPV4;
    281 		ahip6h->ip6_plen = htons(ixa->ixa_pktlen - IPV6_HDR_LEN);
    282 		ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr6_len;
    283 	}
    284 
    285 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
    286 	BUMP_LOCAL(sctp->sctp_obchunks);
    287 
    288 	if (is_system_labeled() && ixa->ixa_tsl != NULL) {
    289 		ASSERT(ira->ira_tsl != NULL);
    290 
    291 		ixa->ixa_tsl = ira->ira_tsl;	/* A multi-level responder */
    292 	}
    293 
    294 	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
    295 		/*
    296 		 * Apply IPsec based on how IPsec was applied to
    297 		 * the packet that caused the abort.
    298 		 */
    299 		if (!ipsec_in_to_out(ira, ixa, hmp, ahiph, ahip6h)) {
    300 			ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip;
    301 
    302 			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
    303 			/* Note: mp already consumed and ip_drop_packet done */
    304 			ixa_refrele(ixa);
    305 			return;
    306 		}
    307 	} else {
    308 		ixa->ixa_flags |= IXAF_NO_IPSEC;
    309 	}
    310 
    311 	BUMP_LOCAL(sctp->sctp_opkts);
    312 	BUMP_LOCAL(sctp->sctp_obchunks);
    313 
    314 	(void) ip_output_simple(hmp, ixa);
    315 	ixa_refrele(ixa);
    316 }
    317 
    318 /*
    319  * OOTB version of the above.
    320  * If iserror == 0, sends an abort. If iserror != 0, sends an error.
    321  */
    322 void
    323 sctp_ootb_send_abort(uint32_t vtag, uint16_t serror, char *details,
    324     size_t len, const mblk_t *inmp, int iserror, boolean_t tbit,
    325     ip_recv_attr_t *ira, ip_stack_t *ipst)
    326 {
    327 	uint32_t	ip_hdr_len;
    328 	size_t		ahlen;
    329 	ipha_t		*ipha = NULL;
    330 	ip6_t		*ip6h = NULL;
    331 	sctp_hdr_t	*insctph;
    332 	int		i;
    333 	uint16_t	port;
    334 	ssize_t		alen;
    335 	int		isv4;
    336 	mblk_t		*mp;
    337 	netstack_t	*ns = ipst->ips_netstack;
    338 	sctp_stack_t	*sctps = ns->netstack_sctp;
    339 	ip_xmit_attr_t	ixas;
    340 
    341 	bzero(&ixas, sizeof (ixas));
    342 
    343 	isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
    344 	ip_hdr_len = ira->ira_ip_hdr_length;
    345 	ahlen = ip_hdr_len + sizeof (sctp_hdr_t);
    346 
    347 	/*
    348 	 * If this is a labeled system, then check to see if we're allowed to
    349 	 * send a response to this particular sender.  If not, then just drop.
    350 	 */
    351 	if (is_system_labeled() && !tsol_can_reply_error(inmp, ira))
    352 		return;
    353 
    354 	mp = allocb(ahlen + sctps->sctps_wroff_xtra, BPRI_MED);
    355 	if (mp == NULL) {
    356 		return;
    357 	}
    358 	mp->b_rptr += sctps->sctps_wroff_xtra;
    359 	mp->b_wptr = mp->b_rptr + ahlen;
    360 	bcopy(inmp->b_rptr, mp->b_rptr, ahlen);
    361 
    362 	/*
    363 	 * We follow the logic in tcp_xmit_early_reset() in that we skip
    364 	 * reversing source route (i.e. replace all IP options with EOL).
    365 	 */
    366 	if (isv4) {
    367 		ipaddr_t	v4addr;
    368 
    369 		ipha = (ipha_t *)mp->b_rptr;
    370 		for (i = IP_SIMPLE_HDR_LENGTH; i < (int)ip_hdr_len; i++)
    371 			mp->b_rptr[i] = IPOPT_EOL;
    372 		/* Swap addresses */
    373 		ipha->ipha_length = htons(ahlen);
    374 		v4addr = ipha->ipha_src;
    375 		ipha->ipha_src = ipha->ipha_dst;
    376 		ipha->ipha_dst = v4addr;
    377 		ipha->ipha_ident = 0;
    378 		ipha->ipha_ttl = (uchar_t)sctps->sctps_ipv4_ttl;
    379 
    380 		ixas.ixa_flags = IXAF_BASIC_SIMPLE_V4;
    381 	} else {
    382 		in6_addr_t	v6addr;
    383 
    384 		ip6h = (ip6_t *)mp->b_rptr;
    385 		/* Remove any extension headers assuming partial overlay */
    386 		if (ip_hdr_len > IPV6_HDR_LEN) {
    387 			uint8_t	*to;
    388 
    389 			to = mp->b_rptr + ip_hdr_len - IPV6_HDR_LEN;
    390 			ovbcopy(ip6h, to, IPV6_HDR_LEN);
    391 			mp->b_rptr += ip_hdr_len - IPV6_HDR_LEN;
    392 			ip_hdr_len = IPV6_HDR_LEN;
    393 			ip6h = (ip6_t *)mp->b_rptr;
    394 			ip6h->ip6_nxt = IPPROTO_SCTP;
    395 			ahlen = ip_hdr_len + sizeof (sctp_hdr_t);
    396 		}
    397 		ip6h->ip6_plen = htons(ahlen - IPV6_HDR_LEN);
    398 		v6addr = ip6h->ip6_src;
    399 		ip6h->ip6_src = ip6h->ip6_dst;
    400 		ip6h->ip6_dst = v6addr;
    401 		ip6h->ip6_hops = (uchar_t)sctps->sctps_ipv6_hoplimit;
    402 
    403 		ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6;
    404 		if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_dst)) {
    405 			ixas.ixa_flags |= IXAF_SCOPEID_SET;
    406 			ixas.ixa_scopeid = ira->ira_ruifindex;
    407 		}
    408 	}
    409 	insctph = (sctp_hdr_t *)(mp->b_rptr + ip_hdr_len);
    410 
    411 	/* Swap ports.  Verification tag is reused. */
    412 	port = insctph->sh_sport;
    413 	insctph->sh_sport = insctph->sh_dport;
    414 	insctph->sh_dport = port;
    415 	insctph->sh_verf = vtag;
    416 
    417 	/* Link in the abort chunk */
    418 	if ((alen = sctp_link_abort(mp, serror, details, len, iserror, tbit))
    419 	    < 0) {
    420 		freemsg(mp);
    421 		return;
    422 	}
    423 
    424 	ixas.ixa_pktlen = ahlen + alen;
    425 	ixas.ixa_ip_hdr_length = ip_hdr_len;
    426 
    427 	if (isv4) {
    428 		ipha->ipha_length = htons(ixas.ixa_pktlen);
    429 	} else {
    430 		ip6h->ip6_plen = htons(ixas.ixa_pktlen - IPV6_HDR_LEN);
    431 	}
    432 
    433 	ixas.ixa_protocol = IPPROTO_SCTP;
    434 	ixas.ixa_zoneid = ira->ira_zoneid;
    435 	ixas.ixa_ipst = ipst;
    436 	ixas.ixa_ifindex = 0;
    437 
    438 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
    439 
    440 	if (is_system_labeled()) {
    441 		ASSERT(ira->ira_tsl != NULL);
    442 
    443 		ixas.ixa_tsl = ira->ira_tsl;	/* A multi-level responder */
    444 	}
    445 
    446 	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
    447 		/*
    448 		 * Apply IPsec based on how IPsec was applied to
    449 		 * the packet that was out of the blue.
    450 		 */
    451 		if (!ipsec_in_to_out(ira, &ixas, mp, ipha, ip6h)) {
    452 			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
    453 			/* Note: mp already consumed and ip_drop_packet done */
    454 			return;
    455 		}
    456 	} else {
    457 		/*
    458 		 * This is in clear. The abort message we are building
    459 		 * here should go out in clear, independent of our policy.
    460 		 */
    461 		ixas.ixa_flags |= IXAF_NO_IPSEC;
    462 	}
    463 
    464 	(void) ip_output_simple(mp, &ixas);
    465 	ixa_cleanup(&ixas);
    466 }
    467 
    468 /*ARGSUSED*/
    469 mblk_t *
    470 sctp_make_err(sctp_t *sctp, uint16_t serror, void *details, size_t len)
    471 {
    472 
    473 	mblk_t *emp;
    474 	size_t elen;
    475 	sctp_chunk_hdr_t *ecp;
    476 	sctp_parm_hdr_t *eph;
    477 	int pad;
    478 
    479 	if ((pad = len % SCTP_ALIGN) != 0) {
    480 		pad = SCTP_ALIGN - pad;
    481 	}
    482 
    483 	elen = sizeof (*ecp) + sizeof (*eph) + len;
    484 	emp = allocb(elen + pad, BPRI_MED);
    485 	if (emp == NULL) {
    486 		return (NULL);
    487 	}
    488 
    489 	emp->b_wptr = emp->b_rptr + elen + pad;
    490 
    491 	/* Chunk header */
    492 	ecp = (sctp_chunk_hdr_t *)emp->b_rptr;
    493 	ecp->sch_id = CHUNK_ERROR;
    494 	ecp->sch_flags = 0;
    495 	ecp->sch_len = htons(elen);
    496 
    497 	eph = (sctp_parm_hdr_t *)(ecp + 1);
    498 	eph->sph_type = htons(serror);
    499 	eph->sph_len = htons(len + sizeof (*eph));
    500 
    501 	if (len > 0) {
    502 		bcopy(details, eph + 1, len);
    503 	}
    504 
    505 	if (pad != 0) {
    506 		bzero((uchar_t *)(eph + 1) + len, pad);
    507 	}
    508 
    509 	return (emp);
    510 }
    511 
    512 /*
    513  * Called from sctp_input_data() to add one error chunk to the error
    514  * chunks list.  The error chunks list will be processed at the end
    515  * of sctp_input_data() by calling sctp_process_err().
    516  */
    517 void
    518 sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len,
    519     sctp_faddr_t *dest)
    520 {
    521 	sctp_stack_t *sctps = sctp->sctp_sctps;
    522 	mblk_t *emp;
    523 	uint32_t emp_len;
    524 	uint32_t mss;
    525 	mblk_t *sendmp;
    526 	sctp_faddr_t *fp;
    527 
    528 	emp = sctp_make_err(sctp, serror, details, len);
    529 	if (emp == NULL)
    530 		return;
    531 	emp_len = MBLKL(emp);
    532 	if (sctp->sctp_err_chunks != NULL) {
    533 		fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks);
    534 	} else {
    535 		fp = dest;
    536 		SCTP_SET_CHUNK_DEST(emp, dest);
    537 	}
    538 	mss = fp->sfa_pmss;
    539 
    540 	/*
    541 	 * If the current output packet cannot include the new error chunk,
    542 	 * send out the current packet and then add the new error chunk
    543 	 * to the new output packet.
    544 	 */
    545 	if (sctp->sctp_err_len + emp_len > mss) {
    546 		if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
    547 			SCTP_KSTAT(sctps, sctp_send_err_failed);
    548 			/* Just free the latest error chunk. */
    549 			freeb(emp);
    550 			return;
    551 		}
    552 		sendmp->b_cont = sctp->sctp_err_chunks;
    553 		sctp_set_iplen(sctp, sendmp, fp->ixa);
    554 		(void) conn_ip_output(sendmp, fp->ixa);
    555 		BUMP_LOCAL(sctp->sctp_opkts);
    556 
    557 		sctp->sctp_err_chunks = emp;
    558 		sctp->sctp_err_len = emp_len;
    559 		SCTP_SET_CHUNK_DEST(emp, dest);
    560 	} else {
    561 		if (sctp->sctp_err_chunks != NULL)
    562 			linkb(sctp->sctp_err_chunks, emp);
    563 		else
    564 			sctp->sctp_err_chunks = emp;
    565 		sctp->sctp_err_len += emp_len;
    566 	}
    567 	/* Assume that we will send it out... */
    568 	BUMP_LOCAL(sctp->sctp_obchunks);
    569 }
    570 
    571 /*
    572  * Called from sctp_input_data() to send out error chunks created during
    573  * the processing of all the chunks in an incoming packet.
    574  */
    575 void
    576 sctp_process_err(sctp_t *sctp)
    577 {
    578 	sctp_stack_t *sctps = sctp->sctp_sctps;
    579 	mblk_t *errmp;
    580 	mblk_t *sendmp;
    581 	sctp_faddr_t *fp;
    582 
    583 	ASSERT(sctp->sctp_err_chunks != NULL);
    584 	errmp = sctp->sctp_err_chunks;
    585 	fp = SCTP_CHUNK_DEST(errmp);
    586 	if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
    587 		SCTP_KSTAT(sctps, sctp_send_err_failed);
    588 		freemsg(errmp);
    589 		goto done;
    590 	}
    591 	sendmp->b_cont = errmp;
    592 	sctp_set_iplen(sctp, sendmp, fp->ixa);
    593 	(void) conn_ip_output(sendmp, fp->ixa);
    594 	BUMP_LOCAL(sctp->sctp_opkts);
    595 done:
    596 	sctp->sctp_err_chunks = NULL;
    597 	sctp->sctp_err_len = 0;
    598 }
    599 
    600 /*
    601  * Returns 0 on non-fatal error, otherwise a system error on fatal
    602  * error.
    603  */
    604 int
    605 sctp_handle_error(sctp_t *sctp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ch,
    606     mblk_t *mp, ip_recv_attr_t *ira)
    607 {
    608 	sctp_parm_hdr_t *errh;
    609 	sctp_chunk_hdr_t *uch;
    610 
    611 	if (ch->sch_len == htons(sizeof (*ch))) {
    612 		/* no error cause given */
    613 		return (0);
    614 	}
    615 	errh = (sctp_parm_hdr_t *)(ch + 1);
    616 	sctp_error_event(sctp, ch);
    617 
    618 	switch (errh->sph_type) {
    619 	/*
    620 	 * Both BAD_SID and NO_USR_DATA errors
    621 	 * indicate a serious bug in our stack,
    622 	 * so complain and abort the association.
    623 	 */
    624 	case SCTP_ERR_BAD_SID:
    625 		cmn_err(CE_WARN, "BUG! send to invalid SID");
    626 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0,
    627 		    ira);
    628 		return (ECONNABORTED);
    629 	case SCTP_ERR_NO_USR_DATA:
    630 		cmn_err(CE_WARN, "BUG! no usr data");
    631 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0,
    632 		    ira);
    633 		return (ECONNABORTED);
    634 	case SCTP_ERR_UNREC_CHUNK:
    635 		/* Pull out the unrecognized chunk type */
    636 		if (ntohs(errh->sph_len) < (sizeof (*errh) + sizeof (*uch))) {
    637 			/* Not enough to process */
    638 			return (0);
    639 		}
    640 		uch = (sctp_chunk_hdr_t *)(errh + 1);
    641 		if (uch->sch_id == CHUNK_ASCONF) {
    642 			/* Turn on ASCONF sending */
    643 			sctp->sctp_understands_asconf = B_FALSE;
    644 			/*
    645 			 * Hand off to asconf to clear out the unacked
    646 			 * asconf chunk.
    647 			 */
    648 			if (ntohs(uch->sch_len) !=
    649 			    (ntohs(errh->sph_len) - sizeof (*errh))) {
    650 				/* malformed */
    651 				dprint(0, ("Malformed Unrec Chunk error\n"));
    652 				return (0);
    653 			}
    654 			sctp_asconf_free_cxmit(sctp, uch);
    655 			return (0);
    656 		}
    657 		/* Else drop it */
    658 		break;
    659 	default:
    660 		break;
    661 	}
    662 
    663 	return (0);
    664 }
    665