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