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 2008 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 #include <sys/tsol/tnet.h>
36 
37 #include <netinet/in.h>
38 #include <netinet/ip6.h>
39 
40 #include <inet/common.h>
41 #include <inet/ip.h>
42 #include <inet/ip6.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, boolean_t tbit)
99 {
100 	mblk_t *mp;
101 	int len, hdrlen;
102 	char *cause;
103 	sctp_faddr_t *fp = sctp->sctp_current;
104 	sctp_stack_t	*sctps = sctp->sctp_sctps;
105 
106 	mp = sctp_make_mp(sctp, fp, 0);
107 	if (mp == NULL) {
108 		SCTP_KSTAT(sctps, sctp_send_user_abort_failed);
109 		return;
110 	}
111 
112 	/*
113 	 * Create abort chunk.
114 	 */
115 	if (data) {
116 		if (fp->isv4) {
117 			hdrlen = sctp->sctp_hdr_len;
118 		} else {
119 			hdrlen = sctp->sctp_hdr6_len;
120 		}
121 		hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t);
122 		cause = (char *)data->b_rptr;
123 		len = data->b_wptr - data->b_rptr;
124 
125 		if (len + hdrlen > fp->sfa_pmss) {
126 			len = fp->sfa_pmss - hdrlen;
127 		}
128 	} else {
129 		cause = NULL;
130 		len = 0;
131 	}
132 	if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0,
133 	    tbit)) < 0) {
134 		freemsg(mp);
135 		return;
136 	}
137 	sctp_set_iplen(sctp, mp);
138 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
139 	BUMP_LOCAL(sctp->sctp_opkts);
140 	BUMP_LOCAL(sctp->sctp_obchunks);
141 
142 	CONN_INC_REF(sctp->sctp_connp);
143 	mp->b_flag |= MSGHASREF;
144 	IP_PUT(mp, sctp->sctp_connp, fp->isv4);
145 }
146 
147 /*
148  * If iserror == 0, sends an abort. If iserror != 0, sends an error.
149  */
150 void
151 sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details,
152     size_t len, mblk_t *inmp, int iserror, boolean_t tbit)
153 {
154 
155 	mblk_t		*hmp;
156 	uint32_t	ip_hdr_len;
157 	ipha_t		*iniph;
158 	ipha_t		*ahiph;
159 	ip6_t		*inip6h;
160 	ip6_t		*ahip6h;
161 	sctp_hdr_t	*sh;
162 	sctp_hdr_t	*insh;
163 	size_t		ahlen;
164 	uchar_t		*p;
165 	ssize_t		alen;
166 	int		isv4;
167 	ire_t		*ire;
168 	irb_t		*irb;
169 	ts_label_t	*tsl;
170 	conn_t		*connp;
171 	cred_t		*cr = NULL;
172 	sctp_stack_t	*sctps = sctp->sctp_sctps;
173 	ip_stack_t	*ipst;
174 
175 	isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION);
176 	if (isv4) {
177 		ahlen = sctp->sctp_hdr_len;
178 	} else {
179 		ahlen = sctp->sctp_hdr6_len;
180 	}
181 
182 	/*
183 	 * If this is a labeled system, then check to see if we're allowed to
184 	 * send a response to this particular sender.  If not, then just drop.
185 	 */
186 	if (is_system_labeled() && !tsol_can_reply_error(inmp))
187 		return;
188 
189 	hmp = allocb_cred(sctps->sctps_wroff_xtra + ahlen,
190 	    CONN_CRED(sctp->sctp_connp));
191 	if (hmp == NULL) {
192 		/* XXX no resources */
193 		return;
194 	}
195 
196 	/* copy in the IP / SCTP header */
197 	p = hmp->b_rptr + sctps->sctps_wroff_xtra;
198 	hmp->b_rptr = p;
199 	hmp->b_wptr = p + ahlen;
200 	if (isv4) {
201 		bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len);
202 		/*
203 		 * Composite is likely incomplete at this point, so pull
204 		 * info from the incoming IP / SCTP headers.
205 		 */
206 		ahiph = (ipha_t *)p;
207 		iniph = (ipha_t *)inmp->b_rptr;
208 		ip_hdr_len = IPH_HDR_LENGTH(inmp->b_rptr);
209 
210 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len);
211 		ASSERT(OK_32PTR(sh));
212 
213 		insh = (sctp_hdr_t *)((uchar_t *)iniph + ip_hdr_len);
214 		ASSERT(OK_32PTR(insh));
215 
216 		/* Copy in the peer's IP addr */
217 		ahiph->ipha_dst = iniph->ipha_src;
218 		ahiph->ipha_src = iniph->ipha_dst;
219 	} else {
220 		bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len);
221 		ahip6h = (ip6_t *)p;
222 		inip6h = (ip6_t *)inmp->b_rptr;
223 		ip_hdr_len = sizeof (ip6_t);
224 
225 		sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len);
226 		ASSERT(OK_32PTR(sh));
227 
228 		insh = (sctp_hdr_t *)((uchar_t *)inip6h + ip_hdr_len);
229 		ASSERT(OK_32PTR(insh));
230 
231 		/* Copy in the peer's IP addr */
232 		ahip6h->ip6_dst = inip6h->ip6_src;
233 		ahip6h->ip6_src = inip6h->ip6_dst;
234 	}
235 
236 	/* Fill in the holes in the SCTP common header */
237 	sh->sh_sport = insh->sh_dport;
238 	sh->sh_dport = insh->sh_sport;
239 	sh->sh_verf = vtag;
240 
241 	/* Link in the abort chunk */
242 	if ((alen = sctp_link_abort(hmp, serror, details, len, iserror, tbit))
243 	    < 0) {
244 		freemsg(hmp);
245 		return;
246 	}
247 
248 	if (isv4) {
249 		ahiph->ipha_length = htons(ahlen + alen);
250 	} else {
251 		ahip6h->ip6_plen = htons(alen + sizeof (*sh));
252 	}
253 
254 	BUMP_MIB(&sctps->sctps_mib, sctpAborted);
255 	BUMP_LOCAL(sctp->sctp_obchunks);
256 
257 	ipst = sctps->sctps_netstack->netstack_ip;
258 	connp = sctp->sctp_connp;
259 	if (is_system_labeled() && (cr = DB_CRED(inmp)) != NULL &&
260 	    crgetlabel(cr) != NULL) {
261 		int err;
262 		boolean_t exempt = connp->conn_mac_exempt;
263 
264 		if (isv4)
265 			err = tsol_check_label(cr, &hmp, exempt, ipst);
266 		else
267 			err = tsol_check_label_v6(cr, &hmp, exempt, ipst);
268 		if (err != 0) {
269 			freemsg(hmp);
270 			return;
271 		}
272 	}
273 
274 	/* Stash the conn ptr info. for IP */
275 	SCTP_STASH_IPINFO(hmp, NULL);
276 
277 	CONN_INC_REF(connp);
278 	hmp->b_flag |= MSGHASREF;
279 	IP_PUT(hmp, connp, sctp->sctp_current == NULL ? B_TRUE :
280 	    sctp->sctp_current->isv4);
281 	/*
282 	 * Let's just mark the IRE for this destination as temporary
283 	 * to prevent any DoS attack.
284 	 */
285 	tsl = cr == NULL ? NULL : crgetlabel(cr);
286 	if (isv4) {
287 		ire = ire_cache_lookup(iniph->ipha_src, sctp->sctp_zoneid, tsl,
288 		    ipst);
289 	} else {
290 		ire = ire_cache_lookup_v6(&inip6h->ip6_src, sctp->sctp_zoneid,
291 		    tsl, ipst);
292 	}
293 	/*
294 	 * In the normal case the ire would be non-null, however it could be
295 	 * null, say, if IP needs to resolve the gateway for this address. We
296 	 * only care about IRE_CACHE.
297 	 */
298 	if (ire == NULL)
299 		return;
300 	if (ire->ire_type != IRE_CACHE) {
301 		ire_refrele(ire);
302 		return;
303 	}
304 	irb = ire->ire_bucket;
305 	/* ire_lock is not needed, as ire_marks is protected by irb_lock */
306 	rw_enter(&irb->irb_lock, RW_WRITER);
307 	/*
308 	 * Only increment the temporary IRE count if the original
309 	 * IRE is not already marked temporary.
310 	 */
311 	if (!(ire->ire_marks & IRE_MARK_TEMPORARY)) {
312 		irb->irb_tmp_ire_cnt++;
313 		ire->ire_marks |= IRE_MARK_TEMPORARY;
314 	}
315 	rw_exit(&irb->irb_lock);
316 	ire_refrele(ire);
317 }
318 
319 /*ARGSUSED*/
320 mblk_t *
321 sctp_make_err(sctp_t *sctp, uint16_t serror, void *details, size_t len)
322 {
323 
324 	mblk_t *emp;
325 	size_t elen;
326 	sctp_chunk_hdr_t *ecp;
327 	sctp_parm_hdr_t *eph;
328 	int pad;
329 
330 	if ((pad = len % SCTP_ALIGN) != 0) {
331 		pad = SCTP_ALIGN - pad;
332 	}
333 
334 	elen = sizeof (*ecp) + sizeof (*eph) + len;
335 	emp = allocb(elen + pad, BPRI_MED);
336 	if (emp == NULL) {
337 		return (NULL);
338 	}
339 
340 	emp->b_wptr = emp->b_rptr + elen + pad;
341 
342 	/* Chunk header */
343 	ecp = (sctp_chunk_hdr_t *)emp->b_rptr;
344 	ecp->sch_id = CHUNK_ERROR;
345 	ecp->sch_flags = 0;
346 	ecp->sch_len = htons(elen);
347 
348 	eph = (sctp_parm_hdr_t *)(ecp + 1);
349 	eph->sph_type = htons(serror);
350 	eph->sph_len = htons(len + sizeof (*eph));
351 
352 	if (len > 0) {
353 		bcopy(details, eph + 1, len);
354 	}
355 
356 	if (pad != 0) {
357 		bzero((uchar_t *)(eph + 1) + len, pad);
358 	}
359 
360 	return (emp);
361 }
362 
363 /*
364  * Called from sctp_input_data() to add one error chunk to the error
365  * chunks list.  The error chunks list will be processed at the end
366  * of sctp_input_data() by calling sctp_process_err().
367  */
368 void
369 sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len,
370     sctp_faddr_t *dest)
371 {
372 	sctp_stack_t *sctps = sctp->sctp_sctps;
373 	mblk_t *emp;
374 	uint32_t emp_len;
375 	uint32_t mss;
376 	mblk_t *sendmp;
377 	sctp_faddr_t *fp;
378 
379 	emp = sctp_make_err(sctp, serror, details, len);
380 	if (emp == NULL)
381 		return;
382 	emp_len = MBLKL(emp);
383 	if (sctp->sctp_err_chunks != NULL) {
384 		fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks);
385 	} else {
386 		fp = dest;
387 		SCTP_SET_CHUNK_DEST(emp, dest);
388 	}
389 	mss = fp->sfa_pmss;
390 
391 	/*
392 	 * If the current output packet cannot include the new error chunk,
393 	 * send out the current packet and then add the new error chunk
394 	 * to the new output packet.
395 	 */
396 	if (sctp->sctp_err_len + emp_len > mss) {
397 		if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) {
398 			SCTP_KSTAT(sctps, sctp_send_err_failed);
399 			/* Just free the latest error chunk. */
400 			freeb(emp);
401 			return;
402 		}
403 		sendmp->b_cont = sctp->sctp_err_chunks;
404 		sctp_set_iplen(sctp, sendmp);
405 		sctp_add_sendq(sctp, sendmp);
406 
407 		sctp->sctp_err_chunks = emp;
408 		sctp->sctp_err_len = emp_len;
409 		SCTP_SET_CHUNK_DEST(emp, dest);
410 	} else {
411 		if (sctp->sctp_err_chunks != NULL)
412 			linkb(sctp->sctp_err_chunks, emp);
413 		else
414 			sctp->sctp_err_chunks = emp;
415 		sctp->sctp_err_len += emp_len;
416 	}
417 	/* Assume that we will send it out... */
418 	BUMP_LOCAL(sctp->sctp_obchunks);
419 }
420 
421 /*
422  * Called from sctp_input_data() to send out error chunks created during
423  * the processing of all the chunks in an incoming packet.
424  */
425 void
426 sctp_process_err(sctp_t *sctp)
427 {
428 	sctp_stack_t *sctps = sctp->sctp_sctps;
429 	mblk_t *errmp;
430 	mblk_t *sendmp;
431 
432 	ASSERT(sctp->sctp_err_chunks != NULL);
433 	errmp = sctp->sctp_err_chunks;
434 	if ((sendmp = sctp_make_mp(sctp, SCTP_CHUNK_DEST(errmp), 0)) == NULL) {
435 		SCTP_KSTAT(sctps, sctp_send_err_failed);
436 		freemsg(errmp);
437 		goto done;
438 	}
439 	sendmp->b_cont = errmp;
440 	sctp_set_iplen(sctp, sendmp);
441 	sctp_add_sendq(sctp, sendmp);
442 done:
443 	sctp->sctp_err_chunks = NULL;
444 	sctp->sctp_err_len = 0;
445 }
446 
447 /*
448  * Returns 0 on non-fatal error, otherwise a system error on fatal
449  * error.
450  */
451 int
452 sctp_handle_error(sctp_t *sctp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ch,
453     mblk_t *mp)
454 {
455 	sctp_parm_hdr_t *errh;
456 	sctp_chunk_hdr_t *uch;
457 
458 	if (ch->sch_len == htons(sizeof (*ch))) {
459 		/* no error cause given */
460 		return (0);
461 	}
462 	errh = (sctp_parm_hdr_t *)(ch + 1);
463 	sctp_error_event(sctp, ch);
464 
465 	switch (errh->sph_type) {
466 	/*
467 	 * Both BAD_SID and NO_USR_DATA errors
468 	 * indicate a serious bug in our stack,
469 	 * so complain and abort the association.
470 	 */
471 	case SCTP_ERR_BAD_SID:
472 		cmn_err(CE_WARN, "BUG! send to invalid SID");
473 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
474 		return (ECONNABORTED);
475 	case SCTP_ERR_NO_USR_DATA:
476 		cmn_err(CE_WARN, "BUG! no usr data");
477 		sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0);
478 		return (ECONNABORTED);
479 	case SCTP_ERR_UNREC_CHUNK:
480 		/* Pull out the unrecognized chunk type */
481 		if (ntohs(errh->sph_len) < (sizeof (*errh) + sizeof (*uch))) {
482 			/* Not enough to process */
483 			return (0);
484 		}
485 		uch = (sctp_chunk_hdr_t *)(errh + 1);
486 		if (uch->sch_id == CHUNK_ASCONF) {
487 			/* Turn on ASCONF sending */
488 			sctp->sctp_understands_asconf = B_FALSE;
489 			/*
490 			 * Hand off to asconf to clear out the unacked
491 			 * asconf chunk.
492 			 */
493 			if (ntohs(uch->sch_len) !=
494 			    (ntohs(errh->sph_len) - sizeof (*errh))) {
495 				/* malformed */
496 				dprint(0, ("Malformed Unrec Chunk error\n"));
497 				return (0);
498 			}
499 			sctp_asconf_free_cxmit(sctp, uch);
500 			return (0);
501 		}
502 		/* Else drop it */
503 		break;
504 	default:
505 		break;
506 	}
507 
508 	return (0);
509 }
510