17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2177c67f2fSkcpoon 227c478bd9Sstevel@tonic-gate /* 23f4b3ec61Sdh * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <sys/stream.h> 327c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 337c478bd9Sstevel@tonic-gate #include <sys/md5.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 367c478bd9Sstevel@tonic-gate #include <sys/random.h> 3745916cd2Sjpk #include <sys/tsol/tnet.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <netinet/in.h> 407c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <inet/common.h> 437c478bd9Sstevel@tonic-gate #include <inet/ip.h> 447c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 457c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 467c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 477c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 487c478bd9Sstevel@tonic-gate 491d8c4025Svi /* 501d8c4025Svi * Helper function for SunCluster (PSARC/2005/602) to get the original source 511d8c4025Svi * address from the COOKIE 521d8c4025Svi */ 531d8c4025Svi int cl_sctp_cookie_paddr(sctp_chunk_hdr_t *, in6_addr_t *); 541d8c4025Svi 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * From RFC 2104. This should probably go into libmd5 (and while 577c478bd9Sstevel@tonic-gate * we're at it, maybe we should make a libdigest so we can later 587c478bd9Sstevel@tonic-gate * add SHA1 and others, esp. since some weaknesses have been found 597c478bd9Sstevel@tonic-gate * with MD5). 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * text IN pointer to data stream 627c478bd9Sstevel@tonic-gate * text_len IN length of data stream 637c478bd9Sstevel@tonic-gate * key IN pointer to authentication key 647c478bd9Sstevel@tonic-gate * key_len IN length of authentication key 657c478bd9Sstevel@tonic-gate * digest OUT caller digest to be filled in 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate static void 687c478bd9Sstevel@tonic-gate hmac_md5(uchar_t *text, size_t text_len, uchar_t *key, size_t key_len, 697c478bd9Sstevel@tonic-gate uchar_t *digest) 707c478bd9Sstevel@tonic-gate { 717c478bd9Sstevel@tonic-gate MD5_CTX context; 727c478bd9Sstevel@tonic-gate uchar_t k_ipad[65]; /* inner padding - key XORd with ipad */ 737c478bd9Sstevel@tonic-gate uchar_t k_opad[65]; /* outer padding - key XORd with opad */ 747c478bd9Sstevel@tonic-gate uchar_t tk[16]; 757c478bd9Sstevel@tonic-gate int i; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* if key is longer than 64 bytes reset it to key=MD5(key) */ 787c478bd9Sstevel@tonic-gate if (key_len > 64) { 797c478bd9Sstevel@tonic-gate MD5_CTX tctx; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate MD5Init(&tctx); 827c478bd9Sstevel@tonic-gate MD5Update(&tctx, key, key_len); 837c478bd9Sstevel@tonic-gate MD5Final(tk, &tctx); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate key = tk; 867c478bd9Sstevel@tonic-gate key_len = 16; 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * the HMAC_MD5 transform looks like: 917c478bd9Sstevel@tonic-gate * 927c478bd9Sstevel@tonic-gate * MD5(K XOR opad, MD5(K XOR ipad, text)) 937c478bd9Sstevel@tonic-gate * 947c478bd9Sstevel@tonic-gate * where K is an n byte key 957c478bd9Sstevel@tonic-gate * ipad is the byte 0x36 repeated 64 times 967c478bd9Sstevel@tonic-gate * opad is the byte 0x5c repeated 64 times 977c478bd9Sstevel@tonic-gate * and text is the data being protected 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* start out by storing key in pads */ 1017c478bd9Sstevel@tonic-gate bzero(k_ipad, sizeof (k_ipad)); 1027c478bd9Sstevel@tonic-gate bzero(k_opad, sizeof (k_opad)); 1037c478bd9Sstevel@tonic-gate bcopy(key, k_ipad, key_len); 1047c478bd9Sstevel@tonic-gate bcopy(key, k_opad, key_len); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* XOR key with ipad and opad values */ 1077c478bd9Sstevel@tonic-gate for (i = 0; i < 64; i++) { 1087c478bd9Sstevel@tonic-gate k_ipad[i] ^= 0x36; 1097c478bd9Sstevel@tonic-gate k_opad[i] ^= 0x5c; 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * perform inner MD5 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate MD5Init(&context); /* init context for 1st */ 1157c478bd9Sstevel@tonic-gate /* pass */ 1167c478bd9Sstevel@tonic-gate MD5Update(&context, k_ipad, 64); /* start with inner pad */ 1177c478bd9Sstevel@tonic-gate MD5Update(&context, text, text_len); /* then text of datagram */ 1187c478bd9Sstevel@tonic-gate MD5Final(digest, &context); /* finish up 1st pass */ 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * perform outer MD5 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate MD5Init(&context); /* init context for 2nd */ 1237c478bd9Sstevel@tonic-gate /* pass */ 1247c478bd9Sstevel@tonic-gate MD5Update(&context, k_opad, 64); /* start with outer pad */ 1257c478bd9Sstevel@tonic-gate MD5Update(&context, digest, 16); /* then results of 1st */ 1267c478bd9Sstevel@tonic-gate /* hash */ 1277c478bd9Sstevel@tonic-gate MD5Final(digest, &context); /* finish up 2nd pass */ 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * If inmp is non-NULL, and we need to abort, it will use the IP/SCTP 1327c478bd9Sstevel@tonic-gate * info in initmp to send the abort. Otherwise, no abort will be sent. 1337c478bd9Sstevel@tonic-gate * If errmp is non-NULL, a chain of unrecognized parameters will 1347c478bd9Sstevel@tonic-gate * be created and returned via *errmp. 1357c478bd9Sstevel@tonic-gate * 1367c478bd9Sstevel@tonic-gate * Returns 1 if the parameters are OK (or there are no parameters), or 1377c478bd9Sstevel@tonic-gate * 0 if not. 1387c478bd9Sstevel@tonic-gate */ 1397c478bd9Sstevel@tonic-gate static int 1407c478bd9Sstevel@tonic-gate validate_init_params(sctp_t *sctp, sctp_chunk_hdr_t *ch, 1417c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init, mblk_t *inmp, sctp_parm_hdr_t **want_cookie, 1427c478bd9Sstevel@tonic-gate mblk_t **errmp, int *supp_af, uint_t *sctp_options) 1437c478bd9Sstevel@tonic-gate { 1447c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *cph; 1457c478bd9Sstevel@tonic-gate sctp_init_chunk_t *ic; 1467c478bd9Sstevel@tonic-gate ssize_t remaining; 1477c478bd9Sstevel@tonic-gate uint16_t serror = 0; 1487c478bd9Sstevel@tonic-gate char *details = NULL; 1497c478bd9Sstevel@tonic-gate size_t errlen = 0; 1507c478bd9Sstevel@tonic-gate boolean_t got_cookie = B_FALSE; 1517c478bd9Sstevel@tonic-gate uint16_t ptype; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate if (sctp_options != NULL) 1547c478bd9Sstevel@tonic-gate *sctp_options = 0; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* First validate stream parameters */ 1577c478bd9Sstevel@tonic-gate if (init->sic_instr == 0 || init->sic_outstr == 0) { 1587c478bd9Sstevel@tonic-gate serror = SCTP_ERR_BAD_MANDPARM; 1597c478bd9Sstevel@tonic-gate dprint(1, 1607c478bd9Sstevel@tonic-gate ("validate_init_params: bad sid, is=%d os=%d\n", 1617c478bd9Sstevel@tonic-gate htons(init->sic_instr), htons(init->sic_outstr))); 1627c478bd9Sstevel@tonic-gate goto abort; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate if (ntohl(init->sic_inittag) == 0) { 1657c478bd9Sstevel@tonic-gate serror = SCTP_ERR_BAD_MANDPARM; 1667c478bd9Sstevel@tonic-gate dprint(1, ("validate_init_params: inittag = 0\n")); 1677c478bd9Sstevel@tonic-gate goto abort; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate remaining = ntohs(ch->sch_len) - sizeof (*ch); 1717c478bd9Sstevel@tonic-gate ic = (sctp_init_chunk_t *)(ch + 1); 1727c478bd9Sstevel@tonic-gate remaining -= sizeof (*ic); 1737c478bd9Sstevel@tonic-gate if (remaining < sizeof (*cph)) { 1747c478bd9Sstevel@tonic-gate /* Nothing to validate */ 1757c478bd9Sstevel@tonic-gate if (want_cookie != NULL) 1767c478bd9Sstevel@tonic-gate goto cookie_abort; 1777c478bd9Sstevel@tonic-gate return (1); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate cph = (sctp_parm_hdr_t *)(ic + 1); 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate while (cph != NULL) { 1837c478bd9Sstevel@tonic-gate ptype = ntohs(cph->sph_type); 1847c478bd9Sstevel@tonic-gate switch (ptype) { 1857c478bd9Sstevel@tonic-gate case PARM_HBINFO: 1867c478bd9Sstevel@tonic-gate case PARM_UNRECOGNIZED: 1877c478bd9Sstevel@tonic-gate case PARM_ECN: 1887c478bd9Sstevel@tonic-gate /* just ignore them */ 1897c478bd9Sstevel@tonic-gate break; 1907c478bd9Sstevel@tonic-gate case PARM_FORWARD_TSN: 1917c478bd9Sstevel@tonic-gate if (sctp_options != NULL) 1927c478bd9Sstevel@tonic-gate *sctp_options |= SCTP_PRSCTP_OPTION; 1937c478bd9Sstevel@tonic-gate break; 1947c478bd9Sstevel@tonic-gate case PARM_COOKIE: 1957c478bd9Sstevel@tonic-gate got_cookie = B_TRUE; 1967c478bd9Sstevel@tonic-gate if (want_cookie != NULL) { 1977c478bd9Sstevel@tonic-gate *want_cookie = cph; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate break; 2007c478bd9Sstevel@tonic-gate case PARM_ADDR4: 201f551bb10Svi *supp_af |= PARM_SUPP_V4; 202f551bb10Svi break; 2037c478bd9Sstevel@tonic-gate case PARM_ADDR6: 204f551bb10Svi *supp_af |= PARM_SUPP_V6; 205f551bb10Svi break; 2067c478bd9Sstevel@tonic-gate case PARM_COOKIE_PRESERVE: 2077c478bd9Sstevel@tonic-gate case PARM_ADAPT_LAYER_IND: 2087c478bd9Sstevel@tonic-gate /* These are OK */ 2097c478bd9Sstevel@tonic-gate break; 2107c478bd9Sstevel@tonic-gate case PARM_ADDR_HOST_NAME: 2117c478bd9Sstevel@tonic-gate /* Don't support this; abort the association */ 2127c478bd9Sstevel@tonic-gate serror = SCTP_ERR_BAD_ADDR; 2137c478bd9Sstevel@tonic-gate details = (char *)cph; 2147c478bd9Sstevel@tonic-gate errlen = ntohs(cph->sph_len); 2157c478bd9Sstevel@tonic-gate dprint(1, ("sctp:validate_init_params: host addr\n")); 2167c478bd9Sstevel@tonic-gate goto abort; 2177c478bd9Sstevel@tonic-gate case PARM_SUPP_ADDRS: { 2187c478bd9Sstevel@tonic-gate /* Make sure we have a supported addr intersection */ 2197c478bd9Sstevel@tonic-gate uint16_t *p, addrtype; 2207c478bd9Sstevel@tonic-gate int plen; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate plen = ntohs(cph->sph_len); 2237c478bd9Sstevel@tonic-gate p = (uint16_t *)(cph + 1); 2247c478bd9Sstevel@tonic-gate while (plen > 0) { 2257c478bd9Sstevel@tonic-gate addrtype = ntohs(*p); 2267c478bd9Sstevel@tonic-gate switch (addrtype) { 2277c478bd9Sstevel@tonic-gate case PARM_ADDR6: 2287c478bd9Sstevel@tonic-gate *supp_af |= PARM_SUPP_V6; 2297c478bd9Sstevel@tonic-gate break; 2307c478bd9Sstevel@tonic-gate case PARM_ADDR4: 2317c478bd9Sstevel@tonic-gate *supp_af |= PARM_SUPP_V4; 2327c478bd9Sstevel@tonic-gate break; 2337c478bd9Sstevel@tonic-gate default: 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * Do nothing, silently ignore hostname 2367c478bd9Sstevel@tonic-gate * address. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate break; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate p++; 2417c478bd9Sstevel@tonic-gate plen -= sizeof (*p); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate break; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate default: 2467c478bd9Sstevel@tonic-gate /* Unrecognized param; check the high order bits */ 2477c478bd9Sstevel@tonic-gate if ((ptype & 0xc000) == 0xc000) { 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * report unrecognized param, and 2507c478bd9Sstevel@tonic-gate * keep processing 2517c478bd9Sstevel@tonic-gate */ 2527c478bd9Sstevel@tonic-gate if (errmp != NULL) { 2537c478bd9Sstevel@tonic-gate if (want_cookie != NULL) { 2547c478bd9Sstevel@tonic-gate *errmp = sctp_make_err(sctp, 2557c478bd9Sstevel@tonic-gate PARM_UNRECOGNIZED, 2567c478bd9Sstevel@tonic-gate (void *)cph, 2577c478bd9Sstevel@tonic-gate ntohs(cph->sph_len)); 2587c478bd9Sstevel@tonic-gate } else { 2597c478bd9Sstevel@tonic-gate sctp_add_unrec_parm(cph, errmp); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate break; 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate if (ptype & 0x4000) { 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * Stop processing and drop; report 2677c478bd9Sstevel@tonic-gate * unrecognized param 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate serror = SCTP_ERR_UNREC_PARM; 2707c478bd9Sstevel@tonic-gate details = (char *)cph; 2717c478bd9Sstevel@tonic-gate errlen = ntohs(cph->sph_len); 2727c478bd9Sstevel@tonic-gate goto abort; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate if (ptype & 0x8000) { 2757c478bd9Sstevel@tonic-gate /* skip and continue processing */ 2767c478bd9Sstevel@tonic-gate break; 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * 2 high bits are clear; stop processing and 2817c478bd9Sstevel@tonic-gate * drop packet 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate return (0); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate cph = sctp_next_parm(cph, &remaining); 2877c478bd9Sstevel@tonic-gate } 288f551bb10Svi /* 289f551bb10Svi * Some sanity checks. The following should not fail unless the 290f551bb10Svi * other side is broken. 291f551bb10Svi * 292f551bb10Svi * 1. If this is a V4 endpoint but V4 address is not 293f551bb10Svi * supported, abort. 294f551bb10Svi * 2. If this is a V6 only endpoint but V6 address is 295f551bb10Svi * not supported, abort. This assumes that a V6 296f551bb10Svi * endpoint can use both V4 and V6 addresses. 297f551bb10Svi * We only care about supp_af when processing INIT, i.e want_cookie 298f551bb10Svi * is NULL. 299f551bb10Svi */ 300f551bb10Svi if (want_cookie == NULL && 301f551bb10Svi ((sctp->sctp_family == AF_INET && !(*supp_af & PARM_SUPP_V4)) || 302f551bb10Svi (sctp->sctp_family == AF_INET6 && !(*supp_af & PARM_SUPP_V6) && 303f551bb10Svi sctp->sctp_connp->conn_ipv6_v6only))) { 304f551bb10Svi dprint(1, ("sctp:validate_init_params: supp addr\n")); 305f551bb10Svi serror = SCTP_ERR_BAD_ADDR; 306f551bb10Svi goto abort; 307f551bb10Svi } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (want_cookie != NULL && !got_cookie) { 3107c478bd9Sstevel@tonic-gate cookie_abort: 3117c478bd9Sstevel@tonic-gate dprint(1, ("validate_init_params: cookie absent\n")); 3127c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctp_init2vtag(ch), SCTP_ERR_MISSING_PARM, 3137c478bd9Sstevel@tonic-gate details, errlen, inmp, 0, B_FALSE); 3147c478bd9Sstevel@tonic-gate return (0); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* OK */ 3187c478bd9Sstevel@tonic-gate return (1); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate abort: 3217c478bd9Sstevel@tonic-gate if (want_cookie != NULL) 3227c478bd9Sstevel@tonic-gate return (0); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctp_init2vtag(ch), serror, details, 3257c478bd9Sstevel@tonic-gate errlen, inmp, 0, B_FALSE); 3267c478bd9Sstevel@tonic-gate return (0); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * Initialize params from the INIT and INIT-ACK when the assoc. is 3317c478bd9Sstevel@tonic-gate * established. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate boolean_t 3347c478bd9Sstevel@tonic-gate sctp_initialize_params(sctp_t *sctp, sctp_init_chunk_t *init, 3357c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack) 3367c478bd9Sstevel@tonic-gate { 3377c478bd9Sstevel@tonic-gate /* Get initial TSN */ 3387c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = ntohl(init->sic_inittsn); 3397c478bd9Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* Serial number is initialized to the same value as the TSN */ 3427c478bd9Sstevel@tonic-gate sctp->sctp_fcsn = sctp->sctp_lastacked; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * Get verification tags; no byteordering is necessary, since 3467c478bd9Sstevel@tonic-gate * verfication tags are never processed except for byte-by-byte 3477c478bd9Sstevel@tonic-gate * comparisons. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate sctp->sctp_fvtag = init->sic_inittag; 3507c478bd9Sstevel@tonic-gate sctp->sctp_sctph->sh_verf = init->sic_inittag; 3517c478bd9Sstevel@tonic-gate sctp->sctp_sctph6->sh_verf = init->sic_inittag; 3527c478bd9Sstevel@tonic-gate sctp->sctp_lvtag = iack->sic_inittag; 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* Get the peer's rwnd */ 3557c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = ntohl(init->sic_a_rwnd); 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* Allocate the in/out-stream counters */ 3587c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr = iack->sic_outstr; 3597c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = kmem_zalloc(sizeof (uint16_t) * 3607c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr, KM_NOSLEEP); 3617c478bd9Sstevel@tonic-gate if (sctp->sctp_ostrcntrs == NULL) 3627c478bd9Sstevel@tonic-gate return (B_FALSE); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate sctp->sctp_num_istr = iack->sic_instr; 3657c478bd9Sstevel@tonic-gate sctp->sctp_instr = kmem_zalloc(sizeof (*sctp->sctp_instr) * 3667c478bd9Sstevel@tonic-gate sctp->sctp_num_istr, KM_NOSLEEP); 3677c478bd9Sstevel@tonic-gate if (sctp->sctp_instr == NULL) { 3687c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_ostrcntrs, sizeof (uint16_t) * 3697c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr); 3707c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = NULL; 3717c478bd9Sstevel@tonic-gate return (B_FALSE); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate return (B_TRUE); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3761d8c4025Svi /* 3771d8c4025Svi * Copy the peer's original source address into addr. This relies on the 3781d8c4025Svi * following format (see sctp_send_initack() below): 3791d8c4025Svi * relative timestamp for the cookie (int64_t) + 3801d8c4025Svi * cookie lifetime (uint32_t) + 3811d8c4025Svi * local tie-tag (uint32_t) + peer tie-tag (uint32_t) + 3821d8c4025Svi * Peer's original src ... 3831d8c4025Svi */ 3841d8c4025Svi int 3851d8c4025Svi cl_sctp_cookie_paddr(sctp_chunk_hdr_t *ch, in6_addr_t *addr) 3861d8c4025Svi { 3871d8c4025Svi uchar_t *off; 3881d8c4025Svi 3891d8c4025Svi ASSERT(addr != NULL); 3901d8c4025Svi 3911d8c4025Svi if (ch->sch_id != CHUNK_COOKIE) 3921d8c4025Svi return (EINVAL); 3931d8c4025Svi 3941d8c4025Svi off = (uchar_t *)ch + sizeof (*ch) + sizeof (int64_t) + 3951d8c4025Svi sizeof (uint32_t) + sizeof (uint32_t) + sizeof (uint32_t); 3961d8c4025Svi 3971d8c4025Svi bcopy(off, addr, sizeof (*addr)); 3981d8c4025Svi 3991d8c4025Svi return (0); 4001d8c4025Svi } 4011d8c4025Svi 4027c478bd9Sstevel@tonic-gate #define SCTP_CALC_COOKIE_LEN(initcp) \ 4037c478bd9Sstevel@tonic-gate sizeof (int64_t) + /* timestamp */ \ 4047c478bd9Sstevel@tonic-gate sizeof (uint32_t) + /* cookie lifetime */ \ 4057c478bd9Sstevel@tonic-gate sizeof (sctp_init_chunk_t) + /* INIT ACK */ \ 4067c478bd9Sstevel@tonic-gate sizeof (in6_addr_t) + /* peer's original source */ \ 4077c478bd9Sstevel@tonic-gate ntohs((initcp)->sch_len) + /* peer's INIT */ \ 4087c478bd9Sstevel@tonic-gate sizeof (uint32_t) + /* local tie-tag */ \ 4097c478bd9Sstevel@tonic-gate sizeof (uint32_t) + /* peer tie-tag */ \ 4107c478bd9Sstevel@tonic-gate sizeof (sctp_parm_hdr_t) + /* param header */ \ 4117c478bd9Sstevel@tonic-gate 16 /* MD5 hash */ 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate void 414d7ab25acSkp sctp_send_initack(sctp_t *sctp, sctp_hdr_t *initsh, sctp_chunk_hdr_t *ch, 415d7ab25acSkp mblk_t *initmp) 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate ipha_t *initiph; 4187c478bd9Sstevel@tonic-gate ip6_t *initip6h; 4197c478bd9Sstevel@tonic-gate ipha_t *iackiph; 4207c478bd9Sstevel@tonic-gate ip6_t *iackip6h; 4217c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *iack_ch; 4227c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 4237c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init; 4247c478bd9Sstevel@tonic-gate sctp_hdr_t *iacksh; 4257c478bd9Sstevel@tonic-gate size_t cookielen; 4267c478bd9Sstevel@tonic-gate size_t iacklen; 4277c478bd9Sstevel@tonic-gate size_t ipsctplen; 4287c478bd9Sstevel@tonic-gate size_t errlen = 0; 4297c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *cookieph; 4307c478bd9Sstevel@tonic-gate mblk_t *iackmp; 4317c478bd9Sstevel@tonic-gate uint32_t itag; 4327c478bd9Sstevel@tonic-gate uint32_t itsn; 4337c478bd9Sstevel@tonic-gate int64_t *now; 4347c478bd9Sstevel@tonic-gate int64_t nowt; 4357c478bd9Sstevel@tonic-gate uint32_t *lifetime; 4367c478bd9Sstevel@tonic-gate char *p; 4377c478bd9Sstevel@tonic-gate boolean_t isv4; 438f551bb10Svi int supp_af = 0; 4397c478bd9Sstevel@tonic-gate uint_t sctp_options; 4407c478bd9Sstevel@tonic-gate uint32_t *ttag; 4417c478bd9Sstevel@tonic-gate int pad; 4427c478bd9Sstevel@tonic-gate mblk_t *errmp = NULL; 4437c478bd9Sstevel@tonic-gate boolean_t initcollision = B_FALSE; 444f551bb10Svi boolean_t linklocal = B_FALSE; 44545916cd2Sjpk cred_t *cr; 446d7ab25acSkp ts_label_t *initlabel; 447f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 4507c478bd9Sstevel@tonic-gate isv4 = (IPH_HDR_VERSION(initmp->b_rptr) == IPV4_VERSION); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate /* Extract the INIT chunk */ 4537c478bd9Sstevel@tonic-gate if (isv4) { 4547c478bd9Sstevel@tonic-gate initiph = (ipha_t *)initmp->b_rptr; 4557c478bd9Sstevel@tonic-gate ipsctplen = sctp->sctp_ip_hdr_len; 456f551bb10Svi supp_af |= PARM_SUPP_V4; 4577c478bd9Sstevel@tonic-gate } else { 4587c478bd9Sstevel@tonic-gate initip6h = (ip6_t *)initmp->b_rptr; 4597c478bd9Sstevel@tonic-gate ipsctplen = sctp->sctp_ip_hdr6_len; 460f551bb10Svi if (IN6_IS_ADDR_LINKLOCAL(&initip6h->ip6_src)) 461f551bb10Svi linklocal = B_TRUE; 462f551bb10Svi supp_af |= PARM_SUPP_V6; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(initsh)); 4657c478bd9Sstevel@tonic-gate init = (sctp_init_chunk_t *)((char *)(initsh + 1) + sizeof (*iack_ch)); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* Make sure we like the peer's parameters */ 4687c478bd9Sstevel@tonic-gate if (validate_init_params(sctp, ch, init, initmp, NULL, &errmp, 4697c478bd9Sstevel@tonic-gate &supp_af, &sctp_options) == 0) { 4707c478bd9Sstevel@tonic-gate return; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate if (errmp != NULL) 4737c478bd9Sstevel@tonic-gate errlen = msgdsize(errmp); 4747c478bd9Sstevel@tonic-gate if (sctp->sctp_family == AF_INET) { 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * Irregardless of the supported address in the INIT, v4 4777c478bd9Sstevel@tonic-gate * must be supported. 4787c478bd9Sstevel@tonic-gate */ 4797c478bd9Sstevel@tonic-gate supp_af = PARM_SUPP_V4; 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate if (sctp->sctp_state <= SCTPS_LISTEN) { 4827c478bd9Sstevel@tonic-gate /* normal, expected INIT: generate new vtag and itsn */ 4837c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)&itag, sizeof (itag)); 4847c478bd9Sstevel@tonic-gate if (itag == 0) 4857c478bd9Sstevel@tonic-gate itag = (uint32_t)gethrtime(); 4867c478bd9Sstevel@tonic-gate itsn = itag + 1; 4877c478bd9Sstevel@tonic-gate itag = htonl(itag); 4887c478bd9Sstevel@tonic-gate } else if (sctp->sctp_state == SCTPS_COOKIE_WAIT || 4897c478bd9Sstevel@tonic-gate sctp->sctp_state == SCTPS_COOKIE_ECHOED) { 4907c478bd9Sstevel@tonic-gate /* init collision; copy vtag and itsn from sctp */ 4917c478bd9Sstevel@tonic-gate itag = sctp->sctp_lvtag; 4927c478bd9Sstevel@tonic-gate itsn = sctp->sctp_ltsn; 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * In addition we need to send all the params that was sent 4957c478bd9Sstevel@tonic-gate * in our INIT chunk. Essentially, it is only the supported 4967c478bd9Sstevel@tonic-gate * address params that we need to add. 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate initcollision = B_TRUE; 499f551bb10Svi /* 500f551bb10Svi * When we sent the INIT, we should have set linklocal in 501f551bb10Svi * the sctp which should be good enough. 502f551bb10Svi */ 503f551bb10Svi if (linklocal) 504f551bb10Svi linklocal = B_FALSE; 5057c478bd9Sstevel@tonic-gate } else { 5067c478bd9Sstevel@tonic-gate /* peer restart; generate new vtag but keep everything else */ 5077c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)&itag, sizeof (itag)); 5087c478bd9Sstevel@tonic-gate if (itag == 0) 5097c478bd9Sstevel@tonic-gate itag = (uint32_t)gethrtime(); 5107c478bd9Sstevel@tonic-gate itag = htonl(itag); 5117c478bd9Sstevel@tonic-gate itsn = sctp->sctp_ltsn; 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Allocate a mblk for the INIT ACK, consisting of the link layer 5167c478bd9Sstevel@tonic-gate * header, the IP header, the SCTP common header, and INIT ACK chunk, 5177c478bd9Sstevel@tonic-gate * and finally the COOKIE parameter. 5187c478bd9Sstevel@tonic-gate */ 5197c478bd9Sstevel@tonic-gate cookielen = SCTP_CALC_COOKIE_LEN(ch); 5207c478bd9Sstevel@tonic-gate iacklen = sizeof (*iack_ch) + sizeof (*iack) + cookielen; 5217c478bd9Sstevel@tonic-gate if (sctp->sctp_send_adaption) 5227c478bd9Sstevel@tonic-gate iacklen += (sizeof (sctp_parm_hdr_t) + sizeof (uint32_t)); 5237c478bd9Sstevel@tonic-gate if (((sctp_options & SCTP_PRSCTP_OPTION) || initcollision) && 524f4b3ec61Sdh sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) { 5257c478bd9Sstevel@tonic-gate iacklen += sctp_options_param_len(sctp, SCTP_PRSCTP_OPTION); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate if (initcollision) 5287c478bd9Sstevel@tonic-gate iacklen += sctp_supaddr_param_len(sctp); 529f551bb10Svi if (!linklocal) 530*12f47623Skcpoon iacklen += sctp_addr_params(sctp, supp_af, NULL, B_FALSE); 5317c478bd9Sstevel@tonic-gate ipsctplen += sizeof (*iacksh) + iacklen; 5327c478bd9Sstevel@tonic-gate iacklen += errlen; 5337c478bd9Sstevel@tonic-gate if ((pad = ipsctplen % 4) != 0) { 5347c478bd9Sstevel@tonic-gate pad = 4 - pad; 5357c478bd9Sstevel@tonic-gate ipsctplen += pad; 5367c478bd9Sstevel@tonic-gate } 537d7ab25acSkp 538d7ab25acSkp /* 539d7ab25acSkp * If the listen socket is bound to a trusted extensions 540d7ab25acSkp * multi-label port, attach a copy of the listener's cred 541d7ab25acSkp * to the new INITACK mblk. Modify the cred to contain 542d7ab25acSkp * the security label of the received INIT packet. 543d7ab25acSkp * If not a multi-label port, attach the unmodified 544d7ab25acSkp * listener's cred directly. 545d7ab25acSkp * 546d7ab25acSkp * We expect Sun developed kernel modules to properly set 547d7ab25acSkp * cred labels for sctp connections. We can't be so sure this 548d7ab25acSkp * will be done correctly when 3rd party kernel modules 549d7ab25acSkp * directly use sctp. The initlabel panic guard logic was 550d7ab25acSkp * added to cover this possibility. 551d7ab25acSkp */ 552d7ab25acSkp if (sctp->sctp_connp->conn_mlp_type != mlptSingle) { 553d7ab25acSkp initlabel = MBLK_GETLABEL(initmp); 554d7ab25acSkp if (initlabel == NULL) { 555d7ab25acSkp sctp_send_abort(sctp, sctp_init2vtag(ch), 556d7ab25acSkp SCTP_ERR_UNKNOWN, NULL, 0, initmp, 0, B_FALSE); 557d7ab25acSkp return; 558d7ab25acSkp } 559d7ab25acSkp cr = copycred_from_bslabel(CONN_CRED(sctp->sctp_connp), 560d7ab25acSkp &initlabel->tsl_label, initlabel->tsl_doi, KM_NOSLEEP); 561d7ab25acSkp if (cr == NULL) { 562d7ab25acSkp sctp_send_abort(sctp, sctp_init2vtag(ch), 563d7ab25acSkp SCTP_ERR_NO_RESOURCES, NULL, 0, initmp, 0, B_FALSE); 564d7ab25acSkp return; 565d7ab25acSkp } 566f4b3ec61Sdh iackmp = allocb_cred(ipsctplen + sctps->sctps_wroff_xtra, cr); 567d7ab25acSkp crfree(cr); 568d7ab25acSkp } else { 569f4b3ec61Sdh iackmp = allocb_cred(ipsctplen + sctps->sctps_wroff_xtra, 570d7ab25acSkp CONN_CRED(sctp->sctp_connp)); 571d7ab25acSkp } 5727c478bd9Sstevel@tonic-gate if (iackmp == NULL) { 5737c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctp_init2vtag(ch), 5747c478bd9Sstevel@tonic-gate SCTP_ERR_NO_RESOURCES, NULL, 0, initmp, 0, B_FALSE); 5757c478bd9Sstevel@tonic-gate return; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* Copy in the [imcomplete] IP/SCTP composite header */ 579f4b3ec61Sdh p = (char *)(iackmp->b_rptr + sctps->sctps_wroff_xtra); 5807c478bd9Sstevel@tonic-gate iackmp->b_rptr = (uchar_t *)p; 5817c478bd9Sstevel@tonic-gate if (isv4) { 5827c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len); 5837c478bd9Sstevel@tonic-gate iackiph = (ipha_t *)p; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* Copy the peer's IP addr */ 5867c478bd9Sstevel@tonic-gate iackiph->ipha_dst = initiph->ipha_src; 5877c478bd9Sstevel@tonic-gate iackiph->ipha_src = initiph->ipha_dst; 5887c478bd9Sstevel@tonic-gate iackiph->ipha_length = htons(ipsctplen + errlen); 5897c478bd9Sstevel@tonic-gate iacksh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len); 5907c478bd9Sstevel@tonic-gate } else { 5917c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len); 5927c478bd9Sstevel@tonic-gate iackip6h = (ip6_t *)p; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate /* Copy the peer's IP addr */ 5957c478bd9Sstevel@tonic-gate iackip6h->ip6_dst = initip6h->ip6_src; 5967c478bd9Sstevel@tonic-gate iackip6h->ip6_src = initip6h->ip6_dst; 5977c478bd9Sstevel@tonic-gate iackip6h->ip6_plen = htons(ipsctplen - sizeof (*iackip6h) + 5987c478bd9Sstevel@tonic-gate errlen); 5997c478bd9Sstevel@tonic-gate iacksh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(iacksh)); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* Fill in the holes in the SCTP common header */ 6047c478bd9Sstevel@tonic-gate iacksh->sh_sport = initsh->sh_dport; 6057c478bd9Sstevel@tonic-gate iacksh->sh_dport = initsh->sh_sport; 6067c478bd9Sstevel@tonic-gate iacksh->sh_verf = init->sic_inittag; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* INIT ACK chunk header */ 6097c478bd9Sstevel@tonic-gate iack_ch = (sctp_chunk_hdr_t *)(iacksh + 1); 6107c478bd9Sstevel@tonic-gate iack_ch->sch_id = CHUNK_INIT_ACK; 6117c478bd9Sstevel@tonic-gate iack_ch->sch_flags = 0; 6127c478bd9Sstevel@tonic-gate iack_ch->sch_len = htons(iacklen); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* The INIT ACK itself */ 6157c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)(iack_ch + 1); 6167c478bd9Sstevel@tonic-gate iack->sic_inittag = itag; /* already in network byteorder */ 6177c478bd9Sstevel@tonic-gate iack->sic_inittsn = htonl(itsn); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate iack->sic_a_rwnd = htonl(sctp->sctp_rwnd); 6207c478bd9Sstevel@tonic-gate /* Advertise what we would want to have as stream #'s */ 6217c478bd9Sstevel@tonic-gate iack->sic_outstr = htons(MIN(sctp->sctp_num_ostr, 6227c478bd9Sstevel@tonic-gate ntohs(init->sic_instr))); 6237c478bd9Sstevel@tonic-gate iack->sic_instr = htons(sctp->sctp_num_istr); 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate p = (char *)(iack + 1); 6267c478bd9Sstevel@tonic-gate p += sctp_adaption_code_param(sctp, (uchar_t *)p); 6277c478bd9Sstevel@tonic-gate if (initcollision) 6287c478bd9Sstevel@tonic-gate p += sctp_supaddr_param(sctp, (uchar_t *)p); 629f551bb10Svi if (!linklocal) 630*12f47623Skcpoon p += sctp_addr_params(sctp, supp_af, (uchar_t *)p, B_FALSE); 6317c478bd9Sstevel@tonic-gate if (((sctp_options & SCTP_PRSCTP_OPTION) || initcollision) && 632f4b3ec61Sdh sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) { 6337c478bd9Sstevel@tonic-gate p += sctp_options_param(sctp, p, SCTP_PRSCTP_OPTION); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * Generate and lay in the COOKIE parameter. 6377c478bd9Sstevel@tonic-gate * 6381d8c4025Svi * Any change here that results in a change of location for 6391d8c4025Svi * the peer's orig source address must be propagated to the fn 6401d8c4025Svi * cl_sctp_cookie_paddr() above. 6411d8c4025Svi * 6427c478bd9Sstevel@tonic-gate * The cookie consists of: 6437c478bd9Sstevel@tonic-gate * 1. The relative timestamp for the cookie (lbolt64) 6447c478bd9Sstevel@tonic-gate * 2. The cookie lifetime (uint32_t) in tick 6457c478bd9Sstevel@tonic-gate * 3. The local tie-tag 6467c478bd9Sstevel@tonic-gate * 4. The peer tie-tag 6477c478bd9Sstevel@tonic-gate * 5. Peer's original src, used to confirm the validity of address. 6487c478bd9Sstevel@tonic-gate * 6. Our INIT ACK chunk, less any parameters 6497c478bd9Sstevel@tonic-gate * 7. The INIT chunk (may contain parameters) 6507c478bd9Sstevel@tonic-gate * 8. 128-bit MD5 signature. 6517c478bd9Sstevel@tonic-gate * 6527c478bd9Sstevel@tonic-gate * Since the timestamp values will only be evaluated locally, we 6537c478bd9Sstevel@tonic-gate * don't need to worry about byte-ordering them. 6547c478bd9Sstevel@tonic-gate */ 6557c478bd9Sstevel@tonic-gate cookieph = (sctp_parm_hdr_t *)p; 6567c478bd9Sstevel@tonic-gate cookieph->sph_type = htons(PARM_COOKIE); 6577c478bd9Sstevel@tonic-gate cookieph->sph_len = htons(cookielen); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* timestamp */ 6607c478bd9Sstevel@tonic-gate now = (int64_t *)(cookieph + 1); 6617c478bd9Sstevel@tonic-gate nowt = lbolt64; 6627c478bd9Sstevel@tonic-gate bcopy(&nowt, now, sizeof (*now)); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* cookie lifetime -- need configuration */ 6657c478bd9Sstevel@tonic-gate lifetime = (uint32_t *)(now + 1); 6667c478bd9Sstevel@tonic-gate *lifetime = sctp->sctp_cookie_lifetime; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* Set the tie-tags */ 6697c478bd9Sstevel@tonic-gate ttag = (uint32_t *)(lifetime + 1); 6707c478bd9Sstevel@tonic-gate if (sctp->sctp_state <= SCTPS_COOKIE_WAIT) { 6717c478bd9Sstevel@tonic-gate *ttag = 0; 6727c478bd9Sstevel@tonic-gate ttag++; 6737c478bd9Sstevel@tonic-gate *ttag = 0; 6747c478bd9Sstevel@tonic-gate ttag++; 6757c478bd9Sstevel@tonic-gate } else { 6767c478bd9Sstevel@tonic-gate /* local tie-tag (network byte-order) */ 6777c478bd9Sstevel@tonic-gate *ttag = sctp->sctp_lvtag; 6787c478bd9Sstevel@tonic-gate ttag++; 6797c478bd9Sstevel@tonic-gate /* peer tie-tag (network byte-order) */ 6807c478bd9Sstevel@tonic-gate *ttag = sctp->sctp_fvtag; 6817c478bd9Sstevel@tonic-gate ttag++; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate /* 6847c478bd9Sstevel@tonic-gate * Copy in peer's original source address so that we can confirm 6857c478bd9Sstevel@tonic-gate * the reachability later. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate p = (char *)ttag; 6887c478bd9Sstevel@tonic-gate if (isv4) { 6897c478bd9Sstevel@tonic-gate in6_addr_t peer_addr; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(iackiph->ipha_dst, &peer_addr); 6927c478bd9Sstevel@tonic-gate bcopy(&peer_addr, p, sizeof (in6_addr_t)); 6937c478bd9Sstevel@tonic-gate } else { 6947c478bd9Sstevel@tonic-gate bcopy(&iackip6h->ip6_dst, p, sizeof (in6_addr_t)); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate p += sizeof (in6_addr_t); 6977c478bd9Sstevel@tonic-gate /* Copy in our INIT ACK chunk */ 6987c478bd9Sstevel@tonic-gate bcopy(iack, p, sizeof (*iack)); 6997c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)p; 7007c478bd9Sstevel@tonic-gate /* Set the # of streams we'll end up using */ 7017c478bd9Sstevel@tonic-gate iack->sic_outstr = MIN(sctp->sctp_num_ostr, ntohs(init->sic_instr)); 7027c478bd9Sstevel@tonic-gate iack->sic_instr = MIN(sctp->sctp_num_istr, ntohs(init->sic_outstr)); 7037c478bd9Sstevel@tonic-gate p += sizeof (*iack); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* Copy in the peer's INIT chunk */ 7067c478bd9Sstevel@tonic-gate bcopy(ch, p, ntohs(ch->sch_len)); 7077c478bd9Sstevel@tonic-gate p += ntohs(ch->sch_len); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * Calculate the HMAC ICV into the digest slot in buf. 7117c478bd9Sstevel@tonic-gate * First, generate a new secret if the current secret is 7127c478bd9Sstevel@tonic-gate * older than the new secret lifetime parameter permits, 7137c478bd9Sstevel@tonic-gate * copying the current secret to sctp_old_secret. 7147c478bd9Sstevel@tonic-gate */ 715f4b3ec61Sdh if (sctps->sctps_new_secret_interval > 0 && 7167c478bd9Sstevel@tonic-gate (sctp->sctp_last_secret_update + 717f4b3ec61Sdh MSEC_TO_TICK(sctps->sctps_new_secret_interval)) <= nowt) { 7187c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_secret, sctp->sctp_old_secret, 7197c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN); 7207c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes(sctp->sctp_secret, 7217c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN); 7227c478bd9Sstevel@tonic-gate sctp->sctp_last_secret_update = nowt; 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate hmac_md5((uchar_t *)now, cookielen - sizeof (*cookieph) - 16, 7267c478bd9Sstevel@tonic-gate (uchar_t *)sctp->sctp_secret, SCTP_SECRET_LEN, (uchar_t *)p); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate iackmp->b_wptr = iackmp->b_rptr + ipsctplen; 7297c478bd9Sstevel@tonic-gate iackmp->b_cont = errmp; /* OK if NULL */ 7307c478bd9Sstevel@tonic-gate 731d7ab25acSkp if (is_system_labeled() && (cr = DB_CRED(iackmp)) != NULL && 73245916cd2Sjpk crgetlabel(cr) != NULL) { 73345916cd2Sjpk conn_t *connp = sctp->sctp_connp; 73445916cd2Sjpk int err, adjust; 73545916cd2Sjpk 73645916cd2Sjpk if (isv4) 73745916cd2Sjpk err = tsol_check_label(cr, &iackmp, &adjust, 738f4b3ec61Sdh connp->conn_mac_exempt, 739f4b3ec61Sdh sctps->sctps_netstack->netstack_ip); 74045916cd2Sjpk else 74145916cd2Sjpk err = tsol_check_label_v6(cr, &iackmp, &adjust, 742f4b3ec61Sdh connp->conn_mac_exempt, 743f4b3ec61Sdh sctps->sctps_netstack->netstack_ip); 74445916cd2Sjpk if (err != 0) { 74545916cd2Sjpk sctp_send_abort(sctp, sctp_init2vtag(ch), 74645916cd2Sjpk SCTP_ERR_AUTH_ERR, NULL, 0, initmp, 0, B_FALSE); 74745916cd2Sjpk freemsg(iackmp); 74845916cd2Sjpk return; 74945916cd2Sjpk } 75045916cd2Sjpk if (isv4) { 75145916cd2Sjpk iackiph = (ipha_t *)iackmp->b_rptr; 75245916cd2Sjpk adjust += ntohs(iackiph->ipha_length); 75345916cd2Sjpk iackiph->ipha_length = htons(adjust); 75445916cd2Sjpk } 75545916cd2Sjpk } 75645916cd2Sjpk 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * Stash the conn ptr info. for IP only as e don't have any 7597c478bd9Sstevel@tonic-gate * cached IRE. 7607c478bd9Sstevel@tonic-gate */ 7617c478bd9Sstevel@tonic-gate SCTP_STASH_IPINFO(iackmp, (ire_t *)NULL); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* XXX sctp == sctp_g_q, so using its obchunks is valid */ 7647c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_opkts); 7657c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate /* OK to call IP_PUT() here instead of sctp_add_sendq(). */ 7687c478bd9Sstevel@tonic-gate CONN_INC_REF(sctp->sctp_connp); 7697c478bd9Sstevel@tonic-gate iackmp->b_flag |= MSGHASREF; 7707c478bd9Sstevel@tonic-gate IP_PUT(iackmp, sctp->sctp_connp, isv4); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate void 7747c478bd9Sstevel@tonic-gate sctp_send_cookie_ack(sctp_t *sctp) 7757c478bd9Sstevel@tonic-gate { 7767c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *cach; 7777c478bd9Sstevel@tonic-gate mblk_t *camp; 778f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate camp = sctp_make_mp(sctp, NULL, sizeof (*cach)); 7817c478bd9Sstevel@tonic-gate if (camp == NULL) { 7827c478bd9Sstevel@tonic-gate /* XXX should abort, but don't have the inmp anymore */ 783f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_cookie_ack_failed); 7847c478bd9Sstevel@tonic-gate return; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate cach = (sctp_chunk_hdr_t *)camp->b_wptr; 7887c478bd9Sstevel@tonic-gate camp->b_wptr = (uchar_t *)(cach + 1); 7897c478bd9Sstevel@tonic-gate cach->sch_id = CHUNK_COOKIE_ACK; 7907c478bd9Sstevel@tonic-gate cach->sch_flags = 0; 7917c478bd9Sstevel@tonic-gate cach->sch_len = htons(sizeof (*cach)); 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, camp); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, camp); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate static int 8017c478bd9Sstevel@tonic-gate sctp_find_al_ind(sctp_parm_hdr_t *sph, ssize_t len, uint32_t *adaption_code) 8027c478bd9Sstevel@tonic-gate { 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate if (len < sizeof (*sph)) 8057c478bd9Sstevel@tonic-gate return (-1); 8067c478bd9Sstevel@tonic-gate while (sph != NULL) { 8077c478bd9Sstevel@tonic-gate if (sph->sph_type == htons(PARM_ADAPT_LAYER_IND) && 8087c478bd9Sstevel@tonic-gate ntohs(sph->sph_len) >= (sizeof (*sph) + 8097c478bd9Sstevel@tonic-gate sizeof (uint32_t))) { 8107c478bd9Sstevel@tonic-gate *adaption_code = *(uint32_t *)(sph + 1); 8117c478bd9Sstevel@tonic-gate return (0); 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate sph = sctp_next_parm(sph, &len); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate return (-1); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate void 8197c478bd9Sstevel@tonic-gate sctp_send_cookie_echo(sctp_t *sctp, sctp_chunk_hdr_t *iackch, mblk_t *iackmp) 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate mblk_t *cemp; 8227c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 8237c478bd9Sstevel@tonic-gate mblk_t *head; 8247c478bd9Sstevel@tonic-gate mblk_t *meta; 8257c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 8267c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *cech; 8277c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 8287c478bd9Sstevel@tonic-gate int32_t cansend; 8297c478bd9Sstevel@tonic-gate int32_t seglen; 8307c478bd9Sstevel@tonic-gate size_t ceclen; 8317c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *cph; 8327c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 8337c478bd9Sstevel@tonic-gate sctp_tf_t *tf; 834f551bb10Svi int pad = 0; 8357c478bd9Sstevel@tonic-gate int hdrlen; 8367c478bd9Sstevel@tonic-gate mblk_t *errmp = NULL; 8377c478bd9Sstevel@tonic-gate uint_t sctp_options; 8387c478bd9Sstevel@tonic-gate int error; 8397c478bd9Sstevel@tonic-gate uint16_t old_num_str; 840f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)(iackch + 1); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate cph = NULL; 8457c478bd9Sstevel@tonic-gate if (validate_init_params(sctp, iackch, iack, iackmp, &cph, &errmp, 8467c478bd9Sstevel@tonic-gate &pad, &sctp_options) == 0) { /* result in 'pad' ignored */ 847f4b3ec61Sdh BUMP_MIB(&sctps->sctps_mib, sctpAborted); 8487c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_CANT_STR_ASSOC, 0, NULL); 8497c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, ECONNABORTED); 8507c478bd9Sstevel@tonic-gate return; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate ASSERT(cph != NULL); 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_cookie_mp == NULL); 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* Got a cookie to echo back; allocate an mblk */ 8577c478bd9Sstevel@tonic-gate ceclen = sizeof (*cech) + ntohs(cph->sph_len) - sizeof (*cph); 8587c478bd9Sstevel@tonic-gate if ((pad = ceclen & (SCTP_ALIGN - 1)) != 0) 8597c478bd9Sstevel@tonic-gate pad = SCTP_ALIGN - pad; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate if (IPH_HDR_VERSION(iackmp->b_rptr) == IPV4_VERSION) 8627c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr_len; 8637c478bd9Sstevel@tonic-gate else 8647c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr6_len; 8657c478bd9Sstevel@tonic-gate 866f4b3ec61Sdh cemp = allocb(sctps->sctps_wroff_xtra + hdrlen + ceclen + pad, 867f4b3ec61Sdh BPRI_MED); 8687c478bd9Sstevel@tonic-gate if (cemp == NULL) { 8697c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 8707c478bd9Sstevel@tonic-gate sctp->sctp_current->rto); 8717c478bd9Sstevel@tonic-gate if (errmp != NULL) 8727c478bd9Sstevel@tonic-gate freeb(errmp); 8737c478bd9Sstevel@tonic-gate return; 8747c478bd9Sstevel@tonic-gate } 875f4b3ec61Sdh cemp->b_rptr += (sctps->sctps_wroff_xtra + hdrlen); 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* Process the INIT ACK */ 8787c478bd9Sstevel@tonic-gate sctp->sctp_sctph->sh_verf = iack->sic_inittag; 8797c478bd9Sstevel@tonic-gate sctp->sctp_sctph6->sh_verf = iack->sic_inittag; 8807c478bd9Sstevel@tonic-gate sctp->sctp_fvtag = iack->sic_inittag; 8817c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = ntohl(iack->sic_inittsn); 8827c478bd9Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 8837c478bd9Sstevel@tonic-gate sctp->sctp_fcsn = sctp->sctp_lastacked; 8847c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = ntohl(iack->sic_a_rwnd); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* 8877c478bd9Sstevel@tonic-gate * Populate sctp with addresses given in the INIT ACK or IP header. 8887c478bd9Sstevel@tonic-gate * Need to set the df bit in the current fp as it has been cleared 8897c478bd9Sstevel@tonic-gate * in sctp_connect(). 8907c478bd9Sstevel@tonic-gate */ 8917c478bd9Sstevel@tonic-gate sctp->sctp_current->df = B_TRUE; 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * Since IP uses this info during the fanout process, we need to hold 8947c478bd9Sstevel@tonic-gate * the lock for this hash line while performing this operation. 8957c478bd9Sstevel@tonic-gate */ 896f4b3ec61Sdh /* XXX sctp_conn_fanout + SCTP_CONN_HASH(sctps, sctp->sctp_ports); */ 8977c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_conn_tfp != NULL); 8987c478bd9Sstevel@tonic-gate tf = sctp->sctp_conn_tfp; 8997c478bd9Sstevel@tonic-gate /* sctp isn't a listener so only need to hold conn fanout lock */ 9007c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 9017c478bd9Sstevel@tonic-gate if (sctp_get_addrparams(sctp, NULL, iackmp, iackch, NULL) != 0) { 9027c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 9037c478bd9Sstevel@tonic-gate freeb(cemp); 9047c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 9057c478bd9Sstevel@tonic-gate sctp->sctp_current->rto); 9067c478bd9Sstevel@tonic-gate if (errmp != NULL) 9077c478bd9Sstevel@tonic-gate freeb(errmp); 9087c478bd9Sstevel@tonic-gate return; 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* 9157c478bd9Sstevel@tonic-gate * There could be a case when we get an INIT-ACK again, if the INIT 9167c478bd9Sstevel@tonic-gate * is re-transmitted, for e.g., which means we would have already 9177c478bd9Sstevel@tonic-gate * allocated this resource earlier (also for sctp_instr). In this 9187c478bd9Sstevel@tonic-gate * case we check and re-allocate, if necessary. 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate old_num_str = sctp->sctp_num_ostr; 9217c478bd9Sstevel@tonic-gate if (ntohs(iack->sic_instr) < sctp->sctp_num_ostr) 9227c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr = ntohs(iack->sic_instr); 9237c478bd9Sstevel@tonic-gate if (sctp->sctp_ostrcntrs == NULL) { 9247c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = kmem_zalloc(sizeof (uint16_t) * 9257c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr, KM_NOSLEEP); 9267c478bd9Sstevel@tonic-gate } else { 9277c478bd9Sstevel@tonic-gate ASSERT(old_num_str > 0); 9287c478bd9Sstevel@tonic-gate if (old_num_str != sctp->sctp_num_ostr) { 9297c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_ostrcntrs, sizeof (uint16_t) * 9307c478bd9Sstevel@tonic-gate old_num_str); 9317c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = kmem_zalloc(sizeof (uint16_t) * 9327c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr, KM_NOSLEEP); 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate if (sctp->sctp_ostrcntrs == NULL) { 9367c478bd9Sstevel@tonic-gate freeb(cemp); 9377c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 9387c478bd9Sstevel@tonic-gate if (errmp != NULL) 9397c478bd9Sstevel@tonic-gate freeb(errmp); 9407c478bd9Sstevel@tonic-gate return; 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate /* 9447c478bd9Sstevel@tonic-gate * Allocate the in stream tracking array. Comments for sctp_ostrcntrs 9457c478bd9Sstevel@tonic-gate * hold here too. 9467c478bd9Sstevel@tonic-gate */ 9477c478bd9Sstevel@tonic-gate old_num_str = sctp->sctp_num_istr; 9487c478bd9Sstevel@tonic-gate if (ntohs(iack->sic_outstr) < sctp->sctp_num_istr) 9497c478bd9Sstevel@tonic-gate sctp->sctp_num_istr = ntohs(iack->sic_outstr); 9507c478bd9Sstevel@tonic-gate if (sctp->sctp_instr == NULL) { 9517c478bd9Sstevel@tonic-gate sctp->sctp_instr = kmem_zalloc(sizeof (*sctp->sctp_instr) * 9527c478bd9Sstevel@tonic-gate sctp->sctp_num_istr, KM_NOSLEEP); 9537c478bd9Sstevel@tonic-gate } else { 9547c478bd9Sstevel@tonic-gate ASSERT(old_num_str > 0); 9557c478bd9Sstevel@tonic-gate if (old_num_str != sctp->sctp_num_istr) { 9567c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_instr, 9577c478bd9Sstevel@tonic-gate sizeof (*sctp->sctp_instr) * old_num_str); 9587c478bd9Sstevel@tonic-gate sctp->sctp_instr = kmem_zalloc( 9597c478bd9Sstevel@tonic-gate sizeof (*sctp->sctp_instr) * sctp->sctp_num_istr, 9607c478bd9Sstevel@tonic-gate KM_NOSLEEP); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate if (sctp->sctp_instr == NULL) { 9647c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_ostrcntrs, 9657c478bd9Sstevel@tonic-gate sizeof (uint16_t) * sctp->sctp_num_ostr); 9667c478bd9Sstevel@tonic-gate freeb(cemp); 9677c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 9687c478bd9Sstevel@tonic-gate if (errmp != NULL) 9697c478bd9Sstevel@tonic-gate freeb(errmp); 9707c478bd9Sstevel@tonic-gate return; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate if (!(sctp_options & SCTP_PRSCTP_OPTION) && sctp->sctp_prsctp_aware) 9747c478bd9Sstevel@tonic-gate sctp->sctp_prsctp_aware = B_FALSE; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate if (sctp_find_al_ind((sctp_parm_hdr_t *)(iack + 1), 9777c478bd9Sstevel@tonic-gate ntohs(iackch->sch_len) - (sizeof (*iackch) + sizeof (*iack)), 9787c478bd9Sstevel@tonic-gate &sctp->sctp_rx_adaption_code) == 0) { 9797c478bd9Sstevel@tonic-gate sctp->sctp_recv_adaption = 1; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate cech = (sctp_chunk_hdr_t *)cemp->b_rptr; 9837c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(cech)); 9847c478bd9Sstevel@tonic-gate cech->sch_id = CHUNK_COOKIE; 9857c478bd9Sstevel@tonic-gate cech->sch_flags = 0; 9867c478bd9Sstevel@tonic-gate cech->sch_len = htons(ceclen); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate /* Copy the cookie (less the parm hdr) to the chunk */ 9897c478bd9Sstevel@tonic-gate bcopy(cph + 1, cech + 1, ceclen - sizeof (*cph)); 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate cemp->b_wptr = cemp->b_rptr + ceclen; 9927c478bd9Sstevel@tonic-gate 993df19b344Svi if (sctp->sctp_unsent > 0) { 9947c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *smh; 9957c478bd9Sstevel@tonic-gate mblk_t *prev = NULL; 9967c478bd9Sstevel@tonic-gate uint32_t unsent = 0; 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_unsent; 9997c478bd9Sstevel@tonic-gate do { 10007c478bd9Sstevel@tonic-gate smh = (sctp_msg_hdr_t *)mp->b_rptr; 10017c478bd9Sstevel@tonic-gate if (smh->smh_sid >= sctp->sctp_num_ostr) { 10027c478bd9Sstevel@tonic-gate unsent += smh->smh_msglen; 10037c478bd9Sstevel@tonic-gate if (prev != NULL) 10047c478bd9Sstevel@tonic-gate prev->b_next = mp->b_next; 10057c478bd9Sstevel@tonic-gate else 10067c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mp->b_next; 10077c478bd9Sstevel@tonic-gate mp->b_next = NULL; 10087c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, mp, SCTP_ERR_BAD_SID, 10097c478bd9Sstevel@tonic-gate B_FALSE); 10107c478bd9Sstevel@tonic-gate if (prev != NULL) 10117c478bd9Sstevel@tonic-gate mp = prev->b_next; 10127c478bd9Sstevel@tonic-gate else 10137c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_unsent; 10147c478bd9Sstevel@tonic-gate } else { 10157c478bd9Sstevel@tonic-gate prev = mp; 10167c478bd9Sstevel@tonic-gate mp = mp->b_next; 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate } while (mp != NULL); 10197c478bd9Sstevel@tonic-gate if (unsent > 0) { 10207c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 10217c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 10247c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 10257c478bd9Sstevel@tonic-gate * This is not necessary, but doesn't harm, we 10267c478bd9Sstevel@tonic-gate * just use unsent instead of sent-unack'ed + 10277c478bd9Sstevel@tonic-gate * unsent, since there won't be any sent-unack'ed 10287c478bd9Sstevel@tonic-gate * here. 10297c478bd9Sstevel@tonic-gate */ 10307c478bd9Sstevel@tonic-gate if (!SCTP_IS_DETACHED(sctp)) { 10317c478bd9Sstevel@tonic-gate sctp->sctp_ulp_xmitted(sctp->sctp_ulpd, 10327c478bd9Sstevel@tonic-gate sctp->sctp_unsent); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) 10367c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate ceclen += pad; 10397c478bd9Sstevel@tonic-gate cansend = MIN(sctp->sctp_unsent, sctp->sctp_frwnd); 10407c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, NULL, &error, ceclen, 10417c478bd9Sstevel@tonic-gate cansend, NULL); 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * The error cannot be anything else since we could have an non-zero 10447c478bd9Sstevel@tonic-gate * error only if sctp_get_msg_to_send() tries to send a Forward 10457c478bd9Sstevel@tonic-gate * TSN which will not happen here. 10467c478bd9Sstevel@tonic-gate */ 10477c478bd9Sstevel@tonic-gate ASSERT(error == 0); 10487c478bd9Sstevel@tonic-gate if (meta == NULL) 10497c478bd9Sstevel@tonic-gate goto sendcookie; 10507c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 10517c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 10527c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 10537c478bd9Sstevel@tonic-gate if ((ceclen + seglen) > fp->sfa_pmss || 10547c478bd9Sstevel@tonic-gate (seglen - sizeof (*sdc)) > cansend) { 10557c478bd9Sstevel@tonic-gate goto sendcookie; 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate /* OK, if this fails */ 10587c478bd9Sstevel@tonic-gate cemp->b_cont = dupmsg(mp); 10597c478bd9Sstevel@tonic-gate sendcookie: 1060df19b344Svi head = sctp_add_proto_hdr(sctp, fp, cemp, 0, NULL); 1061df19b344Svi if (head == NULL) { 1062df19b344Svi freemsg(cemp); 1063df19b344Svi SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 1064df19b344Svi if (errmp != NULL) 1065df19b344Svi freeb(errmp); 1066f4b3ec61Sdh SCTP_KSTAT(sctps, sctp_send_cookie_failed); 1067df19b344Svi return; 1068df19b344Svi } 10697c478bd9Sstevel@tonic-gate /* 10707c478bd9Sstevel@tonic-gate * Even if cookie-echo exceeds MTU for one of the hops, it'll 10717c478bd9Sstevel@tonic-gate * have a chance of getting there. 10727c478bd9Sstevel@tonic-gate */ 10737c478bd9Sstevel@tonic-gate if (fp->isv4) { 10747c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 10757c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate sctp->sctp_cookie_mp = dupmsg(head); 10807c478bd9Sstevel@tonic-gate /* Don't bundle, we will just resend init if this cookie is lost. */ 10817c478bd9Sstevel@tonic-gate if (sctp->sctp_cookie_mp == NULL) { 10827c478bd9Sstevel@tonic-gate if (cemp->b_cont != NULL) { 10837c478bd9Sstevel@tonic-gate freemsg(cemp->b_cont); 10847c478bd9Sstevel@tonic-gate cemp->b_cont = NULL; 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate } else if (cemp->b_cont != NULL) { 10877c478bd9Sstevel@tonic-gate ASSERT(mp != NULL && mp == meta->b_cont); 10887c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(cemp->b_cont); 10897c478bd9Sstevel@tonic-gate cemp->b_wptr += pad; 10907c478bd9Sstevel@tonic-gate seglen -= sizeof (*sdc); 10917c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, seglen, meta); 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate if (errmp != NULL) 10947c478bd9Sstevel@tonic-gate linkb(head, errmp); 10957c478bd9Sstevel@tonic-gate sctp->sctp_state = SCTPS_COOKIE_ECHOED; 10967c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->rto); 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate sctp_set_iplen(sctp, head); 10997c478bd9Sstevel@tonic-gate sctp_add_sendq(sctp, head); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate int 11037c478bd9Sstevel@tonic-gate sctp_process_cookie(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *cmp, 11047c478bd9Sstevel@tonic-gate sctp_init_chunk_t **iackpp, sctp_hdr_t *insctph, int *recv_adaption, 11057c478bd9Sstevel@tonic-gate in6_addr_t *peer_addr) 11067c478bd9Sstevel@tonic-gate { 11077c478bd9Sstevel@tonic-gate int32_t clen; 11087c478bd9Sstevel@tonic-gate size_t initplen; 11097c478bd9Sstevel@tonic-gate uchar_t *p; 11107c478bd9Sstevel@tonic-gate uchar_t *given_hash; 11117c478bd9Sstevel@tonic-gate uchar_t needed_hash[16]; 11127c478bd9Sstevel@tonic-gate int64_t ts; 11137c478bd9Sstevel@tonic-gate int64_t diff; 11147c478bd9Sstevel@tonic-gate uint32_t *lt; 11157c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 11167c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *initch; 11177c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init; 11187c478bd9Sstevel@tonic-gate uint32_t *lttag; 11197c478bd9Sstevel@tonic-gate uint32_t *fttag; 11207c478bd9Sstevel@tonic-gate uint32_t ports; 1121f4b3ec61Sdh sctp_stack_t *sctps = sctp->sctp_sctps; 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 11247c478bd9Sstevel@tonic-gate /* Verify the ICV */ 11257c478bd9Sstevel@tonic-gate clen = ntohs(ch->sch_len) - sizeof (*ch) - 16; 11267c478bd9Sstevel@tonic-gate if (clen < 0) { 11277c478bd9Sstevel@tonic-gate dprint(1, ("invalid cookie chunk length %d\n", 11287c478bd9Sstevel@tonic-gate ntohs(ch->sch_len))); 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate return (-1); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate p = (uchar_t *)(ch + 1); 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate hmac_md5(p, clen, (uchar_t *)sctp->sctp_secret, SCTP_SECRET_LEN, 11357c478bd9Sstevel@tonic-gate needed_hash); 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate /* The given hash follows the cookie data */ 11387c478bd9Sstevel@tonic-gate given_hash = p + clen; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate if (bcmp(given_hash, needed_hash, 16) != 0) { 11417c478bd9Sstevel@tonic-gate /* The secret may have changed; try the old secret */ 11427c478bd9Sstevel@tonic-gate hmac_md5(p, clen, (uchar_t *)sctp->sctp_old_secret, 11437c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN, needed_hash); 11447c478bd9Sstevel@tonic-gate if (bcmp(given_hash, needed_hash, 16) != 0) { 11457c478bd9Sstevel@tonic-gate return (-1); 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate /* Timestamp is int64_t, and we only guarantee 32-bit alignment */ 11507c478bd9Sstevel@tonic-gate bcopy(p, &ts, sizeof (ts)); 1151*12f47623Skcpoon /* Cookie life time, uint32_t */ 11527c478bd9Sstevel@tonic-gate lt = (uint32_t *)(p + sizeof (ts)); 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate /* 11557c478bd9Sstevel@tonic-gate * To quote PRC, "this is our baby", so let's continue. 11567c478bd9Sstevel@tonic-gate * We need to pull out the encapsulated INIT ACK and 11577c478bd9Sstevel@tonic-gate * INIT chunks. Note that we don't process these until 11587c478bd9Sstevel@tonic-gate * we have verified the timestamp, but we need them before 11597c478bd9Sstevel@tonic-gate * processing the timestamp since if the time check fails, 11607c478bd9Sstevel@tonic-gate * we need to get the verification tag from the INIT in order 11617c478bd9Sstevel@tonic-gate * to send a stale cookie error. 11627c478bd9Sstevel@tonic-gate */ 11637c478bd9Sstevel@tonic-gate lttag = (uint32_t *)(lt + 1); 11647c478bd9Sstevel@tonic-gate fttag = lttag + 1; 11657c478bd9Sstevel@tonic-gate if (peer_addr != NULL) 11667c478bd9Sstevel@tonic-gate bcopy(fttag + 1, peer_addr, sizeof (in6_addr_t)); 11677c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)((char *)(fttag + 1) + sizeof (in6_addr_t)); 11687c478bd9Sstevel@tonic-gate initch = (sctp_chunk_hdr_t *)(iack + 1); 11697c478bd9Sstevel@tonic-gate init = (sctp_init_chunk_t *)(initch + 1); 11707c478bd9Sstevel@tonic-gate initplen = ntohs(initch->sch_len) - (sizeof (*init) + sizeof (*initch)); 11717c478bd9Sstevel@tonic-gate *iackpp = iack; 11727c478bd9Sstevel@tonic-gate *recv_adaption = 0; 11737c478bd9Sstevel@tonic-gate 1174*12f47623Skcpoon /* 1175*12f47623Skcpoon * Check the staleness of the Cookie, specified in 3.3.10.3 of 1176*12f47623Skcpoon * RFC 2960. 1177*12f47623Skcpoon * 1178*12f47623Skcpoon * The mesaure of staleness is the difference, in microseconds, 1179*12f47623Skcpoon * between the current time and the time the State Cookie expires. 1180*12f47623Skcpoon * So it is lbolt64 - (ts + *lt). If it is positive, it means 1181*12f47623Skcpoon * that the Cookie has expired. 1182*12f47623Skcpoon */ 1183*12f47623Skcpoon diff = lbolt64 - (ts + *lt); 1184*12f47623Skcpoon if (diff > 0 && (init->sic_inittag != sctp->sctp_fvtag || 11857c478bd9Sstevel@tonic-gate iack->sic_inittag != sctp->sctp_lvtag)) { 11867c478bd9Sstevel@tonic-gate uint32_t staleness; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate staleness = TICK_TO_USEC(diff); 11897c478bd9Sstevel@tonic-gate staleness = htonl(staleness); 11907c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, init->sic_inittag, SCTP_ERR_STALE_COOKIE, 11917c478bd9Sstevel@tonic-gate (char *)&staleness, sizeof (staleness), cmp, 1, B_FALSE); 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate dprint(1, ("stale cookie %d\n", staleness)); 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate return (-1); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* Check for attack by adding addresses to a restart */ 11997c478bd9Sstevel@tonic-gate bcopy(insctph, &ports, sizeof (ports)); 1200f4b3ec61Sdh if (sctp_secure_restart_check(cmp, initch, ports, KM_NOSLEEP, 1201f4b3ec61Sdh sctps) != 1) { 12027c478bd9Sstevel@tonic-gate return (-1); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* Look for adaptation code if there any parms in the INIT chunk */ 12067c478bd9Sstevel@tonic-gate if ((initplen >= sizeof (sctp_parm_hdr_t)) && 12077c478bd9Sstevel@tonic-gate (sctp_find_al_ind((sctp_parm_hdr_t *)(init + 1), initplen, 12087c478bd9Sstevel@tonic-gate &sctp->sctp_rx_adaption_code) == 0)) { 12097c478bd9Sstevel@tonic-gate *recv_adaption = 1; 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate /* Examine tie-tags */ 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_COOKIE_WAIT) { 12157c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED && 12167c478bd9Sstevel@tonic-gate init->sic_inittag == sctp->sctp_fvtag && 12177c478bd9Sstevel@tonic-gate iack->sic_inittag == sctp->sctp_lvtag && 12187c478bd9Sstevel@tonic-gate *fttag == 0 && *lttag == 0) { 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate dprint(1, ("duplicate cookie from %x:%x:%x:%x (%d)\n", 12217c478bd9Sstevel@tonic-gate SCTP_PRINTADDR(sctp->sctp_current->faddr), 12227c478bd9Sstevel@tonic-gate (int)(sctp->sctp_fport))); 12237c478bd9Sstevel@tonic-gate return (-1); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if (init->sic_inittag != sctp->sctp_fvtag && 12277c478bd9Sstevel@tonic-gate iack->sic_inittag != sctp->sctp_lvtag && 12287c478bd9Sstevel@tonic-gate *fttag == sctp->sctp_fvtag && 12297c478bd9Sstevel@tonic-gate *lttag == sctp->sctp_lvtag) { 12307c478bd9Sstevel@tonic-gate int i; 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate /* Section 5.2.4 case A: restart */ 12337c478bd9Sstevel@tonic-gate sctp->sctp_fvtag = init->sic_inittag; 12347c478bd9Sstevel@tonic-gate sctp->sctp_lvtag = iack->sic_inittag; 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate sctp->sctp_sctph->sh_verf = init->sic_inittag; 12377c478bd9Sstevel@tonic-gate sctp->sctp_sctph6->sh_verf = init->sic_inittag; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = ntohl(init->sic_inittsn); 12407c478bd9Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 12417c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = ntohl(init->sic_a_rwnd); 12427c478bd9Sstevel@tonic-gate sctp->sctp_fcsn = sctp->sctp_lastacked; 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (sctp->sctp_state < SCTPS_ESTABLISHED) { 12457c478bd9Sstevel@tonic-gate sctp->sctp_state = SCTPS_ESTABLISHED; 12467c478bd9Sstevel@tonic-gate sctp->sctp_assoc_start_time = (uint32_t)lbolt; 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate dprint(1, ("sctp peer %x:%x:%x:%x (%d) restarted\n", 12507c478bd9Sstevel@tonic-gate SCTP_PRINTADDR(sctp->sctp_current->faddr), 12517c478bd9Sstevel@tonic-gate (int)(sctp->sctp_fport))); 12527c478bd9Sstevel@tonic-gate /* reset parameters */ 12537c478bd9Sstevel@tonic-gate sctp_congest_reset(sctp); 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate /* reset stream bookkeeping */ 12567c478bd9Sstevel@tonic-gate sctp_instream_cleanup(sctp, B_FALSE); 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate sctp->sctp_istr_nmsgs = 0; 12597c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued = 0; 12607c478bd9Sstevel@tonic-gate for (i = 0; i < sctp->sctp_num_ostr; i++) { 12617c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs[i] = 0; 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate /* XXX flush xmit_list? */ 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate return (0); 12667c478bd9Sstevel@tonic-gate } else if (init->sic_inittag != sctp->sctp_fvtag && 12677c478bd9Sstevel@tonic-gate iack->sic_inittag == sctp->sctp_lvtag) { 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate /* Section 5.2.4 case B: INIT collision */ 12707c478bd9Sstevel@tonic-gate if (sctp->sctp_state < SCTPS_ESTABLISHED) { 12717c478bd9Sstevel@tonic-gate if (!sctp_initialize_params(sctp, init, iack)) 12727c478bd9Sstevel@tonic-gate return (-1); /* Drop? */ 12737c478bd9Sstevel@tonic-gate sctp->sctp_state = SCTPS_ESTABLISHED; 12747c478bd9Sstevel@tonic-gate sctp->sctp_assoc_start_time = (uint32_t)lbolt; 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate dprint(1, ("init collision with %x:%x:%x:%x (%d)\n", 12787c478bd9Sstevel@tonic-gate SCTP_PRINTADDR(sctp->sctp_current->faddr), 12797c478bd9Sstevel@tonic-gate (int)(sctp->sctp_fport))); 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate return (0); 12827c478bd9Sstevel@tonic-gate } else if (iack->sic_inittag != sctp->sctp_lvtag && 12837c478bd9Sstevel@tonic-gate init->sic_inittag == sctp->sctp_fvtag && 12847c478bd9Sstevel@tonic-gate *fttag == 0 && *lttag == 0) { 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate /* Section 5.2.4 case C: late COOKIE */ 12877c478bd9Sstevel@tonic-gate dprint(1, ("late cookie from %x:%x:%x:%x (%d)\n", 12887c478bd9Sstevel@tonic-gate SCTP_PRINTADDR(sctp->sctp_current->faddr), 12897c478bd9Sstevel@tonic-gate (int)(sctp->sctp_fport))); 12907c478bd9Sstevel@tonic-gate return (-1); 12917c478bd9Sstevel@tonic-gate } else if (init->sic_inittag == sctp->sctp_fvtag && 12927c478bd9Sstevel@tonic-gate iack->sic_inittag == sctp->sctp_lvtag) { 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * Section 5.2.4 case D: COOKIE ECHO retransmit 12967c478bd9Sstevel@tonic-gate * Don't check cookie lifetime 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate dprint(1, ("cookie tags match from %x:%x:%x:%x (%d)\n", 12997c478bd9Sstevel@tonic-gate SCTP_PRINTADDR(sctp->sctp_current->faddr), 13007c478bd9Sstevel@tonic-gate (int)(sctp->sctp_fport))); 13017c478bd9Sstevel@tonic-gate if (sctp->sctp_state < SCTPS_ESTABLISHED) { 13027c478bd9Sstevel@tonic-gate if (!sctp_initialize_params(sctp, init, iack)) 13037c478bd9Sstevel@tonic-gate return (-1); /* Drop? */ 13047c478bd9Sstevel@tonic-gate sctp->sctp_state = SCTPS_ESTABLISHED; 13057c478bd9Sstevel@tonic-gate sctp->sctp_assoc_start_time = (uint32_t)lbolt; 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate return (0); 13087c478bd9Sstevel@tonic-gate } else { 13097c478bd9Sstevel@tonic-gate /* unrecognized case -- silently drop it */ 13107c478bd9Sstevel@tonic-gate return (-1); 13117c478bd9Sstevel@tonic-gate } 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate return (0); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate /* 13187c478bd9Sstevel@tonic-gate * Similar to ip_fanout_sctp, except that the src addr(s) are drawn 13197c478bd9Sstevel@tonic-gate * from address parameters in an INIT ACK's address list. This 13207c478bd9Sstevel@tonic-gate * function is used when an INIT ACK is received but IP's fanout 13217c478bd9Sstevel@tonic-gate * function could not find a sctp via the normal lookup routine. 13227c478bd9Sstevel@tonic-gate * This can happen when a host sends an INIT ACK from a different 13237c478bd9Sstevel@tonic-gate * address than the INIT was sent to. 13247c478bd9Sstevel@tonic-gate * 13257c478bd9Sstevel@tonic-gate * Returns the sctp_t if found, or NULL if not found. 13267c478bd9Sstevel@tonic-gate */ 13277c478bd9Sstevel@tonic-gate sctp_t * 13287c478bd9Sstevel@tonic-gate sctp_addrlist2sctp(mblk_t *mp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ich, 1329e35d2278Svi zoneid_t zoneid, sctp_stack_t *sctps) 13307c478bd9Sstevel@tonic-gate { 13317c478bd9Sstevel@tonic-gate int isv4; 13327c478bd9Sstevel@tonic-gate ipha_t *iph; 13337c478bd9Sstevel@tonic-gate ip6_t *ip6h; 13347c478bd9Sstevel@tonic-gate in6_addr_t dst; 13357c478bd9Sstevel@tonic-gate in6_addr_t src; 13367c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *ph; 13377c478bd9Sstevel@tonic-gate ssize_t remaining; 13387c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 13397c478bd9Sstevel@tonic-gate uint32_t ports; 13407c478bd9Sstevel@tonic-gate sctp_t *sctp = NULL; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate ASSERT(ich->sch_id == CHUNK_INIT_ACK); 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate isv4 = (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION); 13457c478bd9Sstevel@tonic-gate if (isv4) { 13467c478bd9Sstevel@tonic-gate iph = (ipha_t *)mp->b_rptr; 13477c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(iph->ipha_dst, &dst); 13487c478bd9Sstevel@tonic-gate } else { 13497c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 13507c478bd9Sstevel@tonic-gate dst = ip6h->ip6_dst; 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate ports = *(uint32_t *)sctph; 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate dprint(1, ("sctp_addrlist2sctp: ports=%u, dst = %x:%x:%x:%x\n", 13567c478bd9Sstevel@tonic-gate ports, SCTP_PRINTADDR(dst))); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate /* pull out any address parameters */ 13597c478bd9Sstevel@tonic-gate remaining = ntohs(ich->sch_len) - sizeof (*ich) - sizeof (*iack); 13607c478bd9Sstevel@tonic-gate if (remaining < sizeof (*ph)) { 13617c478bd9Sstevel@tonic-gate return (NULL); 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)(ich + 1); 13657c478bd9Sstevel@tonic-gate ph = (sctp_parm_hdr_t *)(iack + 1); 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate while (ph != NULL) { 13687c478bd9Sstevel@tonic-gate /* 13697c478bd9Sstevel@tonic-gate * params have been put in host byteorder by 13707c478bd9Sstevel@tonic-gate * sctp_check_input() 13717c478bd9Sstevel@tonic-gate */ 13727c478bd9Sstevel@tonic-gate if (ph->sph_type == PARM_ADDR4) { 13737c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED((struct in_addr *)(ph + 1), 13747c478bd9Sstevel@tonic-gate &src); 13757c478bd9Sstevel@tonic-gate 1376e35d2278Svi sctp = sctp_conn_match(&src, &dst, ports, zoneid, 1377e35d2278Svi sctps); 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate dprint(1, 13807c478bd9Sstevel@tonic-gate ("sctp_addrlist2sctp: src=%x:%x:%x:%x, sctp=%p\n", 138145916cd2Sjpk SCTP_PRINTADDR(src), (void *)sctp)); 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate if (sctp != NULL) { 13857c478bd9Sstevel@tonic-gate return (sctp); 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate } else if (ph->sph_type == PARM_ADDR6) { 13887c478bd9Sstevel@tonic-gate src = *(in6_addr_t *)(ph + 1); 1389e35d2278Svi sctp = sctp_conn_match(&src, &dst, ports, zoneid, 1390e35d2278Svi sctps); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate dprint(1, 13937c478bd9Sstevel@tonic-gate ("sctp_addrlist2sctp: src=%x:%x:%x:%x, sctp=%p\n", 139445916cd2Sjpk SCTP_PRINTADDR(src), (void *)sctp)); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate if (sctp != NULL) { 13977c478bd9Sstevel@tonic-gate return (sctp); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate ph = sctp_next_parm(ph, &remaining); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate return (NULL); 14057c478bd9Sstevel@tonic-gate } 1406