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