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