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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/systm.h> 29 #include <sys/stream.h> 30 #include <sys/cmn_err.h> 31 #include <sys/ddi.h> 32 #include <sys/strsubr.h> 33 #include <sys/tsol/tnet.h> 34 35 #include <netinet/in.h> 36 #include <netinet/ip6.h> 37 38 #include <inet/ipsec_impl.h> 39 #include <inet/common.h> 40 #include <inet/ip.h> 41 #include <inet/ip6.h> 42 #include <inet/ipsec_impl.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) 99 { 100 mblk_t *mp; 101 int len, hdrlen; 102 char *cause; 103 sctp_faddr_t *fp = sctp->sctp_current; 104 ip_xmit_attr_t *ixa = fp->ixa; 105 sctp_stack_t *sctps = sctp->sctp_sctps; 106 107 /* 108 * Don't need notification if connection is not yet setup, 109 * call sctp_clean_death() to reclaim resources. 110 * Any pending connect call(s) will error out. 111 */ 112 if (sctp->sctp_state < SCTPS_COOKIE_WAIT) { 113 sctp_clean_death(sctp, ECONNABORTED); 114 return; 115 } 116 117 mp = sctp_make_mp(sctp, fp, 0); 118 if (mp == NULL) { 119 SCTP_KSTAT(sctps, sctp_send_user_abort_failed); 120 return; 121 } 122 123 /* 124 * Create abort chunk. 125 */ 126 if (data) { 127 if (fp->isv4) { 128 hdrlen = sctp->sctp_hdr_len; 129 } else { 130 hdrlen = sctp->sctp_hdr6_len; 131 } 132 hdrlen += sizeof (sctp_chunk_hdr_t) + sizeof (sctp_parm_hdr_t); 133 cause = (char *)data->b_rptr; 134 len = data->b_wptr - data->b_rptr; 135 136 if (len + hdrlen > fp->sfa_pmss) { 137 len = fp->sfa_pmss - hdrlen; 138 } 139 } else { 140 cause = NULL; 141 len = 0; 142 } 143 /* 144 * Since it is a user abort, we should have the sctp_t and hence 145 * the correct verification tag. So we should not set the T-bit 146 * in the ABORT. 147 */ 148 if ((len = sctp_link_abort(mp, SCTP_ERR_USER_ABORT, cause, len, 0, 149 B_FALSE)) < 0) { 150 freemsg(mp); 151 return; 152 } 153 BUMP_MIB(&sctps->sctps_mib, sctpAborted); 154 BUMP_LOCAL(sctp->sctp_opkts); 155 BUMP_LOCAL(sctp->sctp_obchunks); 156 157 sctp_set_iplen(sctp, mp, ixa); 158 ASSERT(ixa->ixa_ire != NULL); 159 ASSERT(ixa->ixa_cred != NULL); 160 161 (void) conn_ip_output(mp, ixa); 162 163 sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL); 164 sctp_clean_death(sctp, ECONNABORTED); 165 } 166 167 /* 168 * If iserror == 0, sends an abort. If iserror != 0, sends an error. 169 */ 170 void 171 sctp_send_abort(sctp_t *sctp, uint32_t vtag, uint16_t serror, char *details, 172 size_t len, mblk_t *inmp, int iserror, boolean_t tbit, ip_recv_attr_t *ira) 173 { 174 175 mblk_t *hmp; 176 uint32_t ip_hdr_len; 177 ipha_t *iniph; 178 ipha_t *ahiph = NULL; 179 ip6_t *inip6h; 180 ip6_t *ahip6h = NULL; 181 sctp_hdr_t *sh; 182 sctp_hdr_t *insh; 183 size_t ahlen; 184 uchar_t *p; 185 ssize_t alen; 186 int isv4; 187 conn_t *connp = sctp->sctp_connp; 188 sctp_stack_t *sctps = sctp->sctp_sctps; 189 ip_xmit_attr_t *ixa; 190 191 isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION); 192 if (isv4) { 193 ahlen = sctp->sctp_hdr_len; 194 } else { 195 ahlen = sctp->sctp_hdr6_len; 196 } 197 198 /* 199 * If this is a labeled system, then check to see if we're allowed to 200 * send a response to this particular sender. If not, then just drop. 201 */ 202 if (is_system_labeled() && !tsol_can_reply_error(inmp, ira)) 203 return; 204 205 hmp = allocb(sctps->sctps_wroff_xtra + ahlen, BPRI_MED); 206 if (hmp == NULL) { 207 /* XXX no resources */ 208 return; 209 } 210 211 /* copy in the IP / SCTP header */ 212 p = hmp->b_rptr + sctps->sctps_wroff_xtra; 213 hmp->b_rptr = p; 214 hmp->b_wptr = p + ahlen; 215 if (isv4) { 216 bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len); 217 /* 218 * Composite is likely incomplete at this point, so pull 219 * info from the incoming IP / SCTP headers. 220 */ 221 ahiph = (ipha_t *)p; 222 iniph = (ipha_t *)inmp->b_rptr; 223 ip_hdr_len = IPH_HDR_LENGTH(inmp->b_rptr); 224 225 sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len); 226 ASSERT(OK_32PTR(sh)); 227 228 insh = (sctp_hdr_t *)((uchar_t *)iniph + ip_hdr_len); 229 ASSERT(OK_32PTR(insh)); 230 231 /* Copy in the peer's IP addr */ 232 ahiph->ipha_dst = iniph->ipha_src; 233 ahiph->ipha_src = iniph->ipha_dst; 234 } else { 235 bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len); 236 ahip6h = (ip6_t *)p; 237 inip6h = (ip6_t *)inmp->b_rptr; 238 ip_hdr_len = ip_hdr_length_v6(inmp, inip6h); 239 240 sh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len); 241 ASSERT(OK_32PTR(sh)); 242 243 insh = (sctp_hdr_t *)((uchar_t *)inip6h + ip_hdr_len); 244 ASSERT(OK_32PTR(insh)); 245 246 /* Copy in the peer's IP addr */ 247 ahip6h->ip6_dst = inip6h->ip6_src; 248 ahip6h->ip6_src = inip6h->ip6_dst; 249 } 250 251 /* Fill in the holes in the SCTP common header */ 252 sh->sh_sport = insh->sh_dport; 253 sh->sh_dport = insh->sh_sport; 254 sh->sh_verf = vtag; 255 256 /* Link in the abort chunk */ 257 if ((alen = sctp_link_abort(hmp, serror, details, len, iserror, tbit)) 258 < 0) { 259 freemsg(hmp); 260 return; 261 } 262 263 /* 264 * Base the transmission on any routing-related socket options 265 * that have been set on the listener/connection. 266 */ 267 ixa = conn_get_ixa_exclusive(connp); 268 if (ixa == NULL) { 269 freemsg(hmp); 270 return; 271 } 272 ixa->ixa_flags &= ~IXAF_VERIFY_PMTU; 273 274 ixa->ixa_pktlen = ahlen + alen; 275 if (isv4) { 276 ixa->ixa_flags |= IXAF_IS_IPV4; 277 ahiph->ipha_length = htons(ixa->ixa_pktlen); 278 ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr_len; 279 } else { 280 ixa->ixa_flags &= ~IXAF_IS_IPV4; 281 ahip6h->ip6_plen = htons(ixa->ixa_pktlen - IPV6_HDR_LEN); 282 ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr6_len; 283 } 284 285 BUMP_MIB(&sctps->sctps_mib, sctpAborted); 286 BUMP_LOCAL(sctp->sctp_obchunks); 287 288 if (is_system_labeled() && ixa->ixa_tsl != NULL) { 289 ASSERT(ira->ira_tsl != NULL); 290 291 ixa->ixa_tsl = ira->ira_tsl; /* A multi-level responder */ 292 } 293 294 if (ira->ira_flags & IRAF_IPSEC_SECURE) { 295 /* 296 * Apply IPsec based on how IPsec was applied to 297 * the packet that caused the abort. 298 */ 299 if (!ipsec_in_to_out(ira, ixa, hmp, ahiph, ahip6h)) { 300 ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip; 301 302 BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards); 303 /* Note: mp already consumed and ip_drop_packet done */ 304 ixa_refrele(ixa); 305 return; 306 } 307 } else { 308 ixa->ixa_flags |= IXAF_NO_IPSEC; 309 } 310 311 BUMP_LOCAL(sctp->sctp_opkts); 312 BUMP_LOCAL(sctp->sctp_obchunks); 313 314 (void) ip_output_simple(hmp, ixa); 315 ixa_refrele(ixa); 316 } 317 318 /* 319 * OOTB version of the above. 320 * If iserror == 0, sends an abort. If iserror != 0, sends an error. 321 */ 322 void 323 sctp_ootb_send_abort(uint32_t vtag, uint16_t serror, char *details, 324 size_t len, const mblk_t *inmp, int iserror, boolean_t tbit, 325 ip_recv_attr_t *ira, ip_stack_t *ipst) 326 { 327 uint32_t ip_hdr_len; 328 size_t ahlen; 329 ipha_t *ipha = NULL; 330 ip6_t *ip6h = NULL; 331 sctp_hdr_t *insctph; 332 int i; 333 uint16_t port; 334 ssize_t alen; 335 int isv4; 336 mblk_t *mp; 337 netstack_t *ns = ipst->ips_netstack; 338 sctp_stack_t *sctps = ns->netstack_sctp; 339 ip_xmit_attr_t ixas; 340 341 bzero(&ixas, sizeof (ixas)); 342 343 isv4 = (IPH_HDR_VERSION(inmp->b_rptr) == IPV4_VERSION); 344 ip_hdr_len = ira->ira_ip_hdr_length; 345 ahlen = ip_hdr_len + sizeof (sctp_hdr_t); 346 347 /* 348 * If this is a labeled system, then check to see if we're allowed to 349 * send a response to this particular sender. If not, then just drop. 350 */ 351 if (is_system_labeled() && !tsol_can_reply_error(inmp, ira)) 352 return; 353 354 mp = allocb(ahlen + sctps->sctps_wroff_xtra, BPRI_MED); 355 if (mp == NULL) { 356 return; 357 } 358 mp->b_rptr += sctps->sctps_wroff_xtra; 359 mp->b_wptr = mp->b_rptr + ahlen; 360 bcopy(inmp->b_rptr, mp->b_rptr, ahlen); 361 362 /* 363 * We follow the logic in tcp_xmit_early_reset() in that we skip 364 * reversing source route (i.e. replace all IP options with EOL). 365 */ 366 if (isv4) { 367 ipaddr_t v4addr; 368 369 ipha = (ipha_t *)mp->b_rptr; 370 for (i = IP_SIMPLE_HDR_LENGTH; i < (int)ip_hdr_len; i++) 371 mp->b_rptr[i] = IPOPT_EOL; 372 /* Swap addresses */ 373 ipha->ipha_length = htons(ahlen); 374 v4addr = ipha->ipha_src; 375 ipha->ipha_src = ipha->ipha_dst; 376 ipha->ipha_dst = v4addr; 377 ipha->ipha_ident = 0; 378 ipha->ipha_ttl = (uchar_t)sctps->sctps_ipv4_ttl; 379 380 ixas.ixa_flags = IXAF_BASIC_SIMPLE_V4; 381 } else { 382 in6_addr_t v6addr; 383 384 ip6h = (ip6_t *)mp->b_rptr; 385 /* Remove any extension headers assuming partial overlay */ 386 if (ip_hdr_len > IPV6_HDR_LEN) { 387 uint8_t *to; 388 389 to = mp->b_rptr + ip_hdr_len - IPV6_HDR_LEN; 390 ovbcopy(ip6h, to, IPV6_HDR_LEN); 391 mp->b_rptr += ip_hdr_len - IPV6_HDR_LEN; 392 ip_hdr_len = IPV6_HDR_LEN; 393 ip6h = (ip6_t *)mp->b_rptr; 394 ip6h->ip6_nxt = IPPROTO_SCTP; 395 ahlen = ip_hdr_len + sizeof (sctp_hdr_t); 396 } 397 ip6h->ip6_plen = htons(ahlen - IPV6_HDR_LEN); 398 v6addr = ip6h->ip6_src; 399 ip6h->ip6_src = ip6h->ip6_dst; 400 ip6h->ip6_dst = v6addr; 401 ip6h->ip6_hops = (uchar_t)sctps->sctps_ipv6_hoplimit; 402 403 ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6; 404 if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_dst)) { 405 ixas.ixa_flags |= IXAF_SCOPEID_SET; 406 ixas.ixa_scopeid = ira->ira_ruifindex; 407 } 408 } 409 insctph = (sctp_hdr_t *)(mp->b_rptr + ip_hdr_len); 410 411 /* Swap ports. Verification tag is reused. */ 412 port = insctph->sh_sport; 413 insctph->sh_sport = insctph->sh_dport; 414 insctph->sh_dport = port; 415 insctph->sh_verf = vtag; 416 417 /* Link in the abort chunk */ 418 if ((alen = sctp_link_abort(mp, serror, details, len, iserror, tbit)) 419 < 0) { 420 freemsg(mp); 421 return; 422 } 423 424 ixas.ixa_pktlen = ahlen + alen; 425 ixas.ixa_ip_hdr_length = ip_hdr_len; 426 427 if (isv4) { 428 ipha->ipha_length = htons(ixas.ixa_pktlen); 429 } else { 430 ip6h->ip6_plen = htons(ixas.ixa_pktlen - IPV6_HDR_LEN); 431 } 432 433 ixas.ixa_protocol = IPPROTO_SCTP; 434 ixas.ixa_zoneid = ira->ira_zoneid; 435 ixas.ixa_ipst = ipst; 436 ixas.ixa_ifindex = 0; 437 438 BUMP_MIB(&sctps->sctps_mib, sctpAborted); 439 440 if (is_system_labeled()) { 441 ASSERT(ira->ira_tsl != NULL); 442 443 ixas.ixa_tsl = ira->ira_tsl; /* A multi-level responder */ 444 } 445 446 if (ira->ira_flags & IRAF_IPSEC_SECURE) { 447 /* 448 * Apply IPsec based on how IPsec was applied to 449 * the packet that was out of the blue. 450 */ 451 if (!ipsec_in_to_out(ira, &ixas, mp, ipha, ip6h)) { 452 BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards); 453 /* Note: mp already consumed and ip_drop_packet done */ 454 return; 455 } 456 } else { 457 /* 458 * This is in clear. The abort message we are building 459 * here should go out in clear, independent of our policy. 460 */ 461 ixas.ixa_flags |= IXAF_NO_IPSEC; 462 } 463 464 (void) ip_output_simple(mp, &ixas); 465 ixa_cleanup(&ixas); 466 } 467 468 /*ARGSUSED*/ 469 mblk_t * 470 sctp_make_err(sctp_t *sctp, uint16_t serror, void *details, size_t len) 471 { 472 473 mblk_t *emp; 474 size_t elen; 475 sctp_chunk_hdr_t *ecp; 476 sctp_parm_hdr_t *eph; 477 int pad; 478 479 if ((pad = len % SCTP_ALIGN) != 0) { 480 pad = SCTP_ALIGN - pad; 481 } 482 483 elen = sizeof (*ecp) + sizeof (*eph) + len; 484 emp = allocb(elen + pad, BPRI_MED); 485 if (emp == NULL) { 486 return (NULL); 487 } 488 489 emp->b_wptr = emp->b_rptr + elen + pad; 490 491 /* Chunk header */ 492 ecp = (sctp_chunk_hdr_t *)emp->b_rptr; 493 ecp->sch_id = CHUNK_ERROR; 494 ecp->sch_flags = 0; 495 ecp->sch_len = htons(elen); 496 497 eph = (sctp_parm_hdr_t *)(ecp + 1); 498 eph->sph_type = htons(serror); 499 eph->sph_len = htons(len + sizeof (*eph)); 500 501 if (len > 0) { 502 bcopy(details, eph + 1, len); 503 } 504 505 if (pad != 0) { 506 bzero((uchar_t *)(eph + 1) + len, pad); 507 } 508 509 return (emp); 510 } 511 512 /* 513 * Called from sctp_input_data() to add one error chunk to the error 514 * chunks list. The error chunks list will be processed at the end 515 * of sctp_input_data() by calling sctp_process_err(). 516 */ 517 void 518 sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len, 519 sctp_faddr_t *dest) 520 { 521 sctp_stack_t *sctps = sctp->sctp_sctps; 522 mblk_t *emp; 523 uint32_t emp_len; 524 uint32_t mss; 525 mblk_t *sendmp; 526 sctp_faddr_t *fp; 527 528 emp = sctp_make_err(sctp, serror, details, len); 529 if (emp == NULL) 530 return; 531 emp_len = MBLKL(emp); 532 if (sctp->sctp_err_chunks != NULL) { 533 fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks); 534 } else { 535 fp = dest; 536 SCTP_SET_CHUNK_DEST(emp, dest); 537 } 538 mss = fp->sfa_pmss; 539 540 /* 541 * If the current output packet cannot include the new error chunk, 542 * send out the current packet and then add the new error chunk 543 * to the new output packet. 544 */ 545 if (sctp->sctp_err_len + emp_len > mss) { 546 if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) { 547 SCTP_KSTAT(sctps, sctp_send_err_failed); 548 /* Just free the latest error chunk. */ 549 freeb(emp); 550 return; 551 } 552 sendmp->b_cont = sctp->sctp_err_chunks; 553 sctp_set_iplen(sctp, sendmp, fp->ixa); 554 (void) conn_ip_output(sendmp, fp->ixa); 555 BUMP_LOCAL(sctp->sctp_opkts); 556 557 sctp->sctp_err_chunks = emp; 558 sctp->sctp_err_len = emp_len; 559 SCTP_SET_CHUNK_DEST(emp, dest); 560 } else { 561 if (sctp->sctp_err_chunks != NULL) 562 linkb(sctp->sctp_err_chunks, emp); 563 else 564 sctp->sctp_err_chunks = emp; 565 sctp->sctp_err_len += emp_len; 566 } 567 /* Assume that we will send it out... */ 568 BUMP_LOCAL(sctp->sctp_obchunks); 569 } 570 571 /* 572 * Called from sctp_input_data() to send out error chunks created during 573 * the processing of all the chunks in an incoming packet. 574 */ 575 void 576 sctp_process_err(sctp_t *sctp) 577 { 578 sctp_stack_t *sctps = sctp->sctp_sctps; 579 mblk_t *errmp; 580 mblk_t *sendmp; 581 sctp_faddr_t *fp; 582 583 ASSERT(sctp->sctp_err_chunks != NULL); 584 errmp = sctp->sctp_err_chunks; 585 fp = SCTP_CHUNK_DEST(errmp); 586 if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) { 587 SCTP_KSTAT(sctps, sctp_send_err_failed); 588 freemsg(errmp); 589 goto done; 590 } 591 sendmp->b_cont = errmp; 592 sctp_set_iplen(sctp, sendmp, fp->ixa); 593 (void) conn_ip_output(sendmp, fp->ixa); 594 BUMP_LOCAL(sctp->sctp_opkts); 595 done: 596 sctp->sctp_err_chunks = NULL; 597 sctp->sctp_err_len = 0; 598 } 599 600 /* 601 * Returns 0 on non-fatal error, otherwise a system error on fatal 602 * error. 603 */ 604 int 605 sctp_handle_error(sctp_t *sctp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ch, 606 mblk_t *mp, ip_recv_attr_t *ira) 607 { 608 sctp_parm_hdr_t *errh; 609 sctp_chunk_hdr_t *uch; 610 611 if (ch->sch_len == htons(sizeof (*ch))) { 612 /* no error cause given */ 613 return (0); 614 } 615 errh = (sctp_parm_hdr_t *)(ch + 1); 616 sctp_error_event(sctp, ch, B_FALSE); 617 618 switch (errh->sph_type) { 619 /* 620 * Both BAD_SID and NO_USR_DATA errors 621 * indicate a serious bug in our stack, 622 * so complain and abort the association. 623 */ 624 case SCTP_ERR_BAD_SID: 625 cmn_err(CE_WARN, "BUG! send to invalid SID"); 626 sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0, 627 ira); 628 return (ECONNABORTED); 629 case SCTP_ERR_NO_USR_DATA: 630 cmn_err(CE_WARN, "BUG! no usr data"); 631 sctp_send_abort(sctp, sctph->sh_verf, 0, NULL, 0, mp, 0, 0, 632 ira); 633 return (ECONNABORTED); 634 case SCTP_ERR_UNREC_CHUNK: 635 /* Pull out the unrecognized chunk type */ 636 if (ntohs(errh->sph_len) < (sizeof (*errh) + sizeof (*uch))) { 637 /* Not enough to process */ 638 return (0); 639 } 640 uch = (sctp_chunk_hdr_t *)(errh + 1); 641 if (uch->sch_id == CHUNK_ASCONF) { 642 /* Turn on ASCONF sending */ 643 sctp->sctp_understands_asconf = B_FALSE; 644 /* 645 * Hand off to asconf to clear out the unacked 646 * asconf chunk. 647 */ 648 if (ntohs(uch->sch_len) != 649 (ntohs(errh->sph_len) - sizeof (*errh))) { 650 /* malformed */ 651 dprint(0, ("Malformed Unrec Chunk error\n")); 652 return (0); 653 } 654 sctp_asconf_free_cxmit(sctp, uch); 655 return (0); 656 } 657 /* Else drop it */ 658 break; 659 default: 660 break; 661 } 662 663 return (0); 664 } 665