xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_error.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/stream.h>
32 #include <sys/cmn_err.h>
33 #include <sys/ddi.h>
34 #include <sys/strsubr.h>
35 
36 #include <netinet/in.h>
37 #include <netinet/ip6.h>
38 
39 #include <inet/common.h>
40 #include <inet/ip.h>
41 #include <inet/ip6.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
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
97 sctp_user_abort(sctp_t *sctp, mblk_t *data, boolean_t tbit)
98 {
99 	mblk_t *mp;
100 	int len, hdrlen;
101 	char *cause;
102 	sctp_faddr_t *fp = sctp->sctp_current;
103 
104 	mp = sctp_make_mp(sctp, fp, 0);
105 	if (mp == NULL)
106 		return;
107 	/*
108 	 * Create abort chunk.
109 	 */
110 	if (data) {
111 		if (fp->isv4) {
112 			hdrlen = sctp->sctp_hdr_len;
113 		} else {
114 			hdrlen = sctp->sctp_hdr6_len;
115 		}
116 		hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t);
117 		cause = (char *)data->b_rptr;
118 		len = data->b_wptr - data->b_rptr;
119 
120 		if (len + hdrlen > fp->sfa_pmss) {
121 			len = fp->sfa_pmss - hdrlen;
122 		}
123 	} else {
124 		cause = NULL;
125 		len = 0;
126 	}
127 	if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0,
128 		tbit)) < 0) {
129 		freemsg(mp);
130 		return;
131 	}
132 	sctp_set_iplen(sctp, mp);
133 	BUMP_MIB(&sctp_mib, sctpAborted);
134 	BUMP_LOCAL(sctp->sctp_opkts);
135 	BUMP_LOCAL(sctp->sctp_obchunks);
136 
137 	CONN_INC_REF(sctp->sctp_connp);
138 	mp->b_flag |= MSGHASREF;
139 	IP_PUT(mp, sctp->sctp_connp, fp->isv4);
140 }
141 
142 /*
143  * If iserror == 0, sends an abort. If iserror != 0, sends an error.
144  */
145 void
146 sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details,
147     size_t len, mblk_t *inmp, int iserror, boolean_t tbit)
148 {
149 
150 	mblk_t		*hmp;
151 	uint32_t	ip_hdr_len;
152 	ipha_t		*iniph;
153 	ipha_t		*ahiph;
154 	ip6_t		*inip6h;
155 	ip6_t		*ahip6h;
156 	sctp_hdr_t	*sh;
157 	sctp_hdr_t	*insh;
158 	size_t		ahlen;
159 	uchar_t		*p;
160 	ssize_t		alen;
161 	int		isv4;
162 	ire_t		*ire;
163 	irb_t		*irb;
164 
165 	isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
166 	if (isv4) {
167 		ahlen = sctp->sctp_hdr_len;
168 	} else {
169 		ahlen = sctp->sctp_hdr6_len;
170 	}
171 
172 	hmp = allocb(sctp_wroff_xtra + ahlen, BPRI_MED);
173 	if (hmp == NULL) {
174 		/* XXX no resources */
175 		return;
176 	}
177 
178 	/* copy in the IP / SCTP header */
179 	p = hmp->b_rptr + sctp_wroff_xtra;
180 	hmp->b_rptr = p;
181 	hmp->b_wptr = p + ahlen;
182 	if (isv4) {
183 		bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len);
184 		/*
185 		 * Composite is likely incomplete at this point, so pull
186 		 * info from the incoming IP / SCTP headers.
187 		 */
188 		ahiph = (ipha_t *)p;
189 		iniph = (ipha_t *)inmp->b_rptr;
190 		ip_hdr_len = IPH_HDR_LENGTH(inmp->b_rptr);
191 
192 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len);
193 		ASSERT(OK_32PTR(sh));
194 
195 		insh = (sctp_hdr_t *)((uchar_t *)iniph + ip_hdr_len);
196 		ASSERT(OK_32PTR(insh));
197 
198 		/* Copy in the peer's IP addr */
199 		ahiph->ipha_dst = iniph->ipha_src;
200 		ahiph->ipha_src = iniph->ipha_dst;
201 	} else {
202 		bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len);
203 		ahip6h = (ip6_t *)p;
204 		inip6h = (ip6_t *)inmp->b_rptr;
205 		ip_hdr_len = sizeof (ip6_t);
206 
207 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len);
208 		ASSERT(OK_32PTR(sh));
209 
210 		insh = (sctp_hdr_t *)((uchar_t *)inip6h + ip_hdr_len);
211 		ASSERT(OK_32PTR(insh));
212 
213 		/* Copy in the peer's IP addr */
214 		ahip6h->ip6_dst = inip6h->ip6_src;
215 		ahip6h->ip6_src = inip6h->ip6_dst;
216 	}
217 
218 	/* Fill in the holes in the SCTP common header */
219 	sh->sh_sport = insh->sh_dport;
220 	sh->sh_dport = insh->sh_sport;
221 	sh->sh_verf = vtag;
222 
223 	/* Link in the abort chunk */
224 	if ((alen = sctp_link_abort(hmp, serror, details, len, iserror, tbit))
225 	    < 0) {
226 		freemsg(hmp);
227 		return;
228 	}
229 
230 	if (isv4) {
231 		ahiph->ipha_length = htons(ahlen + alen);
232 	} else {
233 		ahip6h->ip6_plen = htons(alen + sizeof (*sh));
234 	}
235 
236 	/* Stash the conn ptr info. for IP */
237 	SCTP_STASH_IPINFO(hmp, (ire_t *)NULL);
238 
239 	BUMP_MIB(&sctp_mib, sctpAborted);
240 	BUMP_LOCAL(sctp->sctp_obchunks);
241 
242 	CONN_INC_REF(sctp->sctp_connp);
243 	hmp->b_flag |= MSGHASREF;
244 	IP_PUT(hmp, sctp->sctp_connp, sctp->sctp_current == NULL ? B_TRUE :
245 	    sctp->sctp_current->isv4);
246 	/*
247 	 * Let's just mark the IRE for this destination as temporary
248 	 * to prevent any DoS attack.
249 	 */
250 	if (isv4)
251 		ire = ire_cache_lookup(iniph->ipha_src, sctp->sctp_zoneid);
252 	else
253 		ire = ire_cache_lookup_v6(&inip6h->ip6_src, sctp->sctp_zoneid);
254 	/*
255 	 * In the normal case the ire would be non-null, however it could be
256 	 * null, say, if IP needs to resolve the gateway for this address. We
257 	 * only care about IRE_CACHE.
258 	 */
259 	if (ire == NULL)
260 		return;
261 	if (ire->ire_type != IRE_CACHE) {
262 		ire_refrele(ire);
263 		return;
264 	}
265 	irb = ire->ire_bucket;
266 	/* ire_lock is not needed, as ire_marks is protected by irb_lock */
267 	rw_enter(&irb->irb_lock, RW_WRITER);
268 	/*
269 	 * Only increment the temporary IRE count if the original
270 	 * IRE is not already marked temporary.
271 	 */
272 	if (!(ire->ire_marks & IRE_MARK_TEMPORARY)) {
273 		irb->irb_tmp_ire_cnt++;
274 		ire->ire_marks |= IRE_MARK_TEMPORARY;
275 	}
276 	rw_exit(&irb->irb_lock);
277 	ire_refrele(ire);
278 }
279 
280 /*ARGSUSED*/
281 mblk_t *
282 sctp_make_err(sctp_t *sctp, uint16_t serror, void *details, size_t len)
283 {
284 
285 	mblk_t *emp;
286 	size_t elen;
287 	sctp_chunk_hdr_t *ecp;
288 	sctp_parm_hdr_t *eph;
289 	int pad;
290 
291 	if ((pad = len % 4) != 0) {
292 		pad = 4 - pad;
293 	}
294 
295 	elen = sizeof (*ecp) + sizeof (*eph) + len;
296 	emp = allocb(elen + pad, BPRI_MED);
297 	if (emp == NULL) {
298 		return (NULL);
299 	}
300 
301 	emp->b_wptr = emp->b_rptr + elen + pad;
302 
303 	/* Chunk header */
304 	ecp = (sctp_chunk_hdr_t *)emp->b_rptr;
305 	ecp->sch_id = CHUNK_ERROR;
306 	ecp->sch_flags = 0;
307 	ecp->sch_len = htons(elen);
308 
309 	eph = (sctp_parm_hdr_t *)(ecp + 1);
310 	eph->sph_type = htons(serror);
311 	eph->sph_len = htons(len + sizeof (*eph));
312 
313 	if (len > 0) {
314 		bcopy(details, eph + 1, len);
315 	}
316 
317 	if (pad != 0) {
318 		bzero((uchar_t *)(eph + 1) + len, pad);
319 	}
320 
321 	return (emp);
322 }
323 
324 void
325 sctp_send_err(sctp_t *sctp, mblk_t *emp, sctp_faddr_t *dest)
326 {
327 	mblk_t	*sendmp;
328 
329 	sendmp = sctp_make_sack(sctp, dest, NULL);
330 	if (sendmp != NULL) {
331 		linkb(sendmp, emp);
332 	} else {
333 		sendmp = sctp_make_mp(sctp, dest, 0);
334 		if (sendmp == NULL) {
335 			freemsg(emp);
336 			return;
337 		}
338 		sendmp->b_cont = emp;
339 	}
340 	BUMP_LOCAL(sctp->sctp_obchunks);
341 
342 	sctp_set_iplen(sctp, sendmp);
343 	sctp_add_sendq(sctp, sendmp);
344 }
345 
346 /*
347  * Returns 0 on non-fatal error, otherwise a system error on fatal
348  * error.
349  */
350 int
351 sctp_handle_error(sctp_t *sctp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ch,
352     mblk_t *mp)
353 {
354 	sctp_parm_hdr_t *errh;
355 	sctp_chunk_hdr_t *uch;
356 
357 	if (ch->sch_len == htons(sizeof (*ch))) {
358 		/* no error cause given */
359 		return (0);
360 	}
361 	errh = (sctp_parm_hdr_t *)(ch + 1);
362 	sctp_error_event(sctp, ch);
363 
364 	switch (errh->sph_type) {
365 	/*
366 	 * Both BAD_SID and NO_USR_DATA errors
367 	 * indicate a serious bug in our stack,
368 	 * so complain and abort the association.
369 	 */
370 	case SCTP_ERR_BAD_SID:
371 		cmn_err(CE_WARN, "BUG! send to invalid SID");
372 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
373 		return (ECONNABORTED);
374 	case SCTP_ERR_NO_USR_DATA:
375 		cmn_err(CE_WARN, "BUG! no usr data");
376 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
377 		return (ECONNABORTED);
378 	case SCTP_ERR_UNREC_CHUNK:
379 		/* Pull out the unrecognized chunk type */
380 		if (ntohs(errh->sph_len) < (sizeof (*errh) + sizeof (*uch))) {
381 			/* Not enough to process */
382 			return (0);
383 		}
384 		uch = (sctp_chunk_hdr_t *)(errh + 1);
385 		if (uch->sch_id == CHUNK_ASCONF) {
386 			/* Turn on ASCONF sending */
387 			sctp->sctp_understands_asconf = B_FALSE;
388 			/*
389 			 * Hand off to asconf to clear out the unacked
390 			 * asconf chunk.
391 			 */
392 			if (ntohs(uch->sch_len) !=
393 			    (ntohs(errh->sph_len) - sizeof (*errh))) {
394 				/* malformed */
395 				dprint(0, ("Malformed Unrec Chunk error\n"));
396 				return (0);
397 			}
398 			sctp_asconf_unrec_chunk(sctp, uch);
399 			return (0);
400 		}
401 		/* Else drop it */
402 		break;
403 	default:
404 		break;
405 	}
406 
407 	return (0);
408 }
409