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 = NULL; 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