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