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