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