xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_error.c (revision 93a18d6d401e844455263f926578e9d2aa6b47ec)
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