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 /* 235dd46ab5SKacheong Poon * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/systm.h> 287c478bd9Sstevel@tonic-gate #include <sys/stream.h> 297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 307c478bd9Sstevel@tonic-gate #include <sys/md5.h> 317c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 327c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 337c478bd9Sstevel@tonic-gate #include <sys/random.h> 3445916cd2Sjpk #include <sys/tsol/tnet.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <netinet/in.h> 377c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <inet/common.h> 407c478bd9Sstevel@tonic-gate #include <inet/ip.h> 417c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 42bd670b35SErik Nordmark #include <inet/ipsec_impl.h> 437c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 447c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 457c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* 481d8c4025Svi117747 * Helper function for SunCluster (PSARC/2005/602) to get the original source 491d8c4025Svi117747 * address from the COOKIE 501d8c4025Svi117747 */ 511d8c4025Svi117747 int cl_sctp_cookie_paddr(sctp_chunk_hdr_t *, in6_addr_t *); 521d8c4025Svi117747 531d8c4025Svi117747 /* 547c478bd9Sstevel@tonic-gate * From RFC 2104. This should probably go into libmd5 (and while 557c478bd9Sstevel@tonic-gate * we're at it, maybe we should make a libdigest so we can later 567c478bd9Sstevel@tonic-gate * add SHA1 and others, esp. since some weaknesses have been found 577c478bd9Sstevel@tonic-gate * with MD5). 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * text IN pointer to data stream 607c478bd9Sstevel@tonic-gate * text_len IN length of data stream 617c478bd9Sstevel@tonic-gate * key IN pointer to authentication key 627c478bd9Sstevel@tonic-gate * key_len IN length of authentication key 637c478bd9Sstevel@tonic-gate * digest OUT caller digest to be filled in 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate static void 667c478bd9Sstevel@tonic-gate hmac_md5(uchar_t *text, size_t text_len, uchar_t *key, size_t key_len, 677c478bd9Sstevel@tonic-gate uchar_t *digest) 687c478bd9Sstevel@tonic-gate { 697c478bd9Sstevel@tonic-gate MD5_CTX context; 707c478bd9Sstevel@tonic-gate uchar_t k_ipad[65]; /* inner padding - key XORd with ipad */ 717c478bd9Sstevel@tonic-gate uchar_t k_opad[65]; /* outer padding - key XORd with opad */ 727c478bd9Sstevel@tonic-gate uchar_t tk[16]; 737c478bd9Sstevel@tonic-gate int i; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* if key is longer than 64 bytes reset it to key=MD5(key) */ 767c478bd9Sstevel@tonic-gate if (key_len > 64) { 777c478bd9Sstevel@tonic-gate MD5_CTX tctx; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate MD5Init(&tctx); 807c478bd9Sstevel@tonic-gate MD5Update(&tctx, key, key_len); 817c478bd9Sstevel@tonic-gate MD5Final(tk, &tctx); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate key = tk; 847c478bd9Sstevel@tonic-gate key_len = 16; 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * the HMAC_MD5 transform looks like: 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * MD5(K XOR opad, MD5(K XOR ipad, text)) 917c478bd9Sstevel@tonic-gate * 927c478bd9Sstevel@tonic-gate * where K is an n byte key 937c478bd9Sstevel@tonic-gate * ipad is the byte 0x36 repeated 64 times 947c478bd9Sstevel@tonic-gate * opad is the byte 0x5c repeated 64 times 957c478bd9Sstevel@tonic-gate * and text is the data being protected 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* start out by storing key in pads */ 997c478bd9Sstevel@tonic-gate bzero(k_ipad, sizeof (k_ipad)); 1007c478bd9Sstevel@tonic-gate bzero(k_opad, sizeof (k_opad)); 1017c478bd9Sstevel@tonic-gate bcopy(key, k_ipad, key_len); 1027c478bd9Sstevel@tonic-gate bcopy(key, k_opad, key_len); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* XOR key with ipad and opad values */ 1057c478bd9Sstevel@tonic-gate for (i = 0; i < 64; i++) { 1067c478bd9Sstevel@tonic-gate k_ipad[i] ^= 0x36; 1077c478bd9Sstevel@tonic-gate k_opad[i] ^= 0x5c; 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * perform inner MD5 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate MD5Init(&context); /* init context for 1st */ 1137c478bd9Sstevel@tonic-gate /* pass */ 1147c478bd9Sstevel@tonic-gate MD5Update(&context, k_ipad, 64); /* start with inner pad */ 1157c478bd9Sstevel@tonic-gate MD5Update(&context, text, text_len); /* then text of datagram */ 1167c478bd9Sstevel@tonic-gate MD5Final(digest, &context); /* finish up 1st pass */ 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * perform outer MD5 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate MD5Init(&context); /* init context for 2nd */ 1217c478bd9Sstevel@tonic-gate /* pass */ 1227c478bd9Sstevel@tonic-gate MD5Update(&context, k_opad, 64); /* start with outer pad */ 1237c478bd9Sstevel@tonic-gate MD5Update(&context, digest, 16); /* then results of 1st */ 1247c478bd9Sstevel@tonic-gate /* hash */ 1257c478bd9Sstevel@tonic-gate MD5Final(digest, &context); /* finish up 2nd pass */ 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * If inmp is non-NULL, and we need to abort, it will use the IP/SCTP 1307c478bd9Sstevel@tonic-gate * info in initmp to send the abort. Otherwise, no abort will be sent. 1317c478bd9Sstevel@tonic-gate * 132c513743fSGeorge Shepherd * When called from stcp_send_initack() while processing parameters 13377ebe684SGeorge Shepherd * from a received INIT_CHUNK want_cookie will be NULL. 13477ebe684SGeorge Shepherd * 13577ebe684SGeorge Shepherd * When called from sctp_send_cookie_echo() while processing an INIT_ACK, 13677ebe684SGeorge Shepherd * want_cookie contains a pointer to a pointer of type *sctp_parm_hdr_t. 13777ebe684SGeorge Shepherd * However, this last pointer will be NULL until the cookie is processed 13877ebe684SGeorge Shepherd * at which time it will be set to point to a sctp_parm_hdr_t that contains 13977ebe684SGeorge Shepherd * the cookie info. 14077ebe684SGeorge Shepherd * 14177ebe684SGeorge Shepherd * Note: an INIT_ACK is expected to contain a cookie. 14277ebe684SGeorge Shepherd * 143c513743fSGeorge Shepherd * When processing an INIT_ACK, an ERROR chunk and chain of one or more 144c513743fSGeorge Shepherd * error CAUSE blocks will be created if unrecognized parameters marked by 145c513743fSGeorge Shepherd * the sender as reportable are found. 146c513743fSGeorge Shepherd * 147c513743fSGeorge Shepherd * When processing an INIT chunk, a chain of one or more error CAUSE blocks 148c513743fSGeorge Shepherd * will be created if unrecognized parameters marked by the sender as 149c513743fSGeorge Shepherd * reportable are found. These are appended directly to the INIT_ACK chunk. 150c513743fSGeorge Shepherd * 151c513743fSGeorge Shepherd * In both cases the error chain is visible to the caller via *errmp. 152c513743fSGeorge Shepherd * 15377ebe684SGeorge Shepherd * Returns 1 if the parameters are OK (or if there are no optional 15477ebe684SGeorge Shepherd * parameters), returns 0 otherwise. 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate static int 1577c478bd9Sstevel@tonic-gate validate_init_params(sctp_t *sctp, sctp_chunk_hdr_t *ch, 1587c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init, mblk_t *inmp, sctp_parm_hdr_t **want_cookie, 159bd670b35SErik Nordmark mblk_t **errmp, int *supp_af, uint_t *sctp_options, ip_recv_attr_t *ira) 1607c478bd9Sstevel@tonic-gate { 1617c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *cph; 1627c478bd9Sstevel@tonic-gate sctp_init_chunk_t *ic; 1637c478bd9Sstevel@tonic-gate ssize_t remaining; 1647c478bd9Sstevel@tonic-gate uint16_t serror = 0; 1657c478bd9Sstevel@tonic-gate char *details = NULL; 1667c478bd9Sstevel@tonic-gate size_t errlen = 0; 1677c478bd9Sstevel@tonic-gate boolean_t got_cookie = B_FALSE; 16877ebe684SGeorge Shepherd boolean_t got_errchunk = B_FALSE; 1697c478bd9Sstevel@tonic-gate uint16_t ptype; 17047b33325SGeorge Shepherd sctp_mpc_t mpc; 171bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 17247b33325SGeorge Shepherd 1737c478bd9Sstevel@tonic-gate 17477ebe684SGeorge Shepherd ASSERT(errmp != NULL); 17577ebe684SGeorge Shepherd 1767c478bd9Sstevel@tonic-gate if (sctp_options != NULL) 1777c478bd9Sstevel@tonic-gate *sctp_options = 0; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* First validate stream parameters */ 1807c478bd9Sstevel@tonic-gate if (init->sic_instr == 0 || init->sic_outstr == 0) { 1817c478bd9Sstevel@tonic-gate serror = SCTP_ERR_BAD_MANDPARM; 182222c5bceSkp158701 dprint(1, ("validate_init_params: bad sid, is=%d os=%d\n", 1837c478bd9Sstevel@tonic-gate htons(init->sic_instr), htons(init->sic_outstr))); 1847c478bd9Sstevel@tonic-gate goto abort; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate if (ntohl(init->sic_inittag) == 0) { 1877c478bd9Sstevel@tonic-gate serror = SCTP_ERR_BAD_MANDPARM; 1887c478bd9Sstevel@tonic-gate dprint(1, ("validate_init_params: inittag = 0\n")); 1897c478bd9Sstevel@tonic-gate goto abort; 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate remaining = ntohs(ch->sch_len) - sizeof (*ch); 1937c478bd9Sstevel@tonic-gate ic = (sctp_init_chunk_t *)(ch + 1); 1947c478bd9Sstevel@tonic-gate remaining -= sizeof (*ic); 1957c478bd9Sstevel@tonic-gate if (remaining < sizeof (*cph)) { 19677ebe684SGeorge Shepherd /* 19777ebe684SGeorge Shepherd * When processing a received INIT_ACK, a cookie is 19877ebe684SGeorge Shepherd * expected, if missing there is nothing to validate. 19977ebe684SGeorge Shepherd */ 2007c478bd9Sstevel@tonic-gate if (want_cookie != NULL) 2017c478bd9Sstevel@tonic-gate goto cookie_abort; 2027c478bd9Sstevel@tonic-gate return (1); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate cph = (sctp_parm_hdr_t *)(ic + 1); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate while (cph != NULL) { 2087c478bd9Sstevel@tonic-gate ptype = ntohs(cph->sph_type); 2097c478bd9Sstevel@tonic-gate switch (ptype) { 2107c478bd9Sstevel@tonic-gate case PARM_HBINFO: 2117c478bd9Sstevel@tonic-gate case PARM_UNRECOGNIZED: 2127c478bd9Sstevel@tonic-gate case PARM_ECN: 2137c478bd9Sstevel@tonic-gate /* just ignore them */ 2147c478bd9Sstevel@tonic-gate break; 2157c478bd9Sstevel@tonic-gate case PARM_FORWARD_TSN: 2167c478bd9Sstevel@tonic-gate if (sctp_options != NULL) 2177c478bd9Sstevel@tonic-gate *sctp_options |= SCTP_PRSCTP_OPTION; 2187c478bd9Sstevel@tonic-gate break; 2197c478bd9Sstevel@tonic-gate case PARM_COOKIE: 2207c478bd9Sstevel@tonic-gate got_cookie = B_TRUE; 22177ebe684SGeorge Shepherd /* 22277ebe684SGeorge Shepherd * Processing a received INIT_ACK, we have a cookie 22377ebe684SGeorge Shepherd * and a valid pointer in our caller to attach it to. 22477ebe684SGeorge Shepherd */ 2257c478bd9Sstevel@tonic-gate if (want_cookie != NULL) { 2267c478bd9Sstevel@tonic-gate *want_cookie = cph; 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate break; 2297c478bd9Sstevel@tonic-gate case PARM_ADDR4: 230f551bb10Svi117747 *supp_af |= PARM_SUPP_V4; 231f551bb10Svi117747 break; 2327c478bd9Sstevel@tonic-gate case PARM_ADDR6: 233f551bb10Svi117747 *supp_af |= PARM_SUPP_V6; 234f551bb10Svi117747 break; 2357c478bd9Sstevel@tonic-gate case PARM_COOKIE_PRESERVE: 2367c478bd9Sstevel@tonic-gate case PARM_ADAPT_LAYER_IND: 2377c478bd9Sstevel@tonic-gate /* These are OK */ 2387c478bd9Sstevel@tonic-gate break; 2397c478bd9Sstevel@tonic-gate case PARM_ADDR_HOST_NAME: 2407c478bd9Sstevel@tonic-gate /* Don't support this; abort the association */ 2417c478bd9Sstevel@tonic-gate serror = SCTP_ERR_BAD_ADDR; 2427c478bd9Sstevel@tonic-gate details = (char *)cph; 2437c478bd9Sstevel@tonic-gate errlen = ntohs(cph->sph_len); 2447c478bd9Sstevel@tonic-gate dprint(1, ("sctp:validate_init_params: host addr\n")); 2457c478bd9Sstevel@tonic-gate goto abort; 2467c478bd9Sstevel@tonic-gate case PARM_SUPP_ADDRS: { 2477c478bd9Sstevel@tonic-gate /* Make sure we have a supported addr intersection */ 2487c478bd9Sstevel@tonic-gate uint16_t *p, addrtype; 2497c478bd9Sstevel@tonic-gate int plen; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate plen = ntohs(cph->sph_len); 2527c478bd9Sstevel@tonic-gate p = (uint16_t *)(cph + 1); 2537c478bd9Sstevel@tonic-gate while (plen > 0) { 2547c478bd9Sstevel@tonic-gate addrtype = ntohs(*p); 2557c478bd9Sstevel@tonic-gate switch (addrtype) { 2567c478bd9Sstevel@tonic-gate case PARM_ADDR6: 2577c478bd9Sstevel@tonic-gate *supp_af |= PARM_SUPP_V6; 2587c478bd9Sstevel@tonic-gate break; 2597c478bd9Sstevel@tonic-gate case PARM_ADDR4: 2607c478bd9Sstevel@tonic-gate *supp_af |= PARM_SUPP_V4; 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate default: 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * Do nothing, silently ignore hostname 2657c478bd9Sstevel@tonic-gate * address. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate break; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate p++; 2707c478bd9Sstevel@tonic-gate plen -= sizeof (*p); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate break; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate default: 2757c478bd9Sstevel@tonic-gate /* 27677ebe684SGeorge Shepherd * Handle any unrecognized params, the two high order 27777ebe684SGeorge Shepherd * bits of ptype define how the remote wants them 27877ebe684SGeorge Shepherd * handled. 27977ebe684SGeorge Shepherd * Top bit: 28077ebe684SGeorge Shepherd * 1. Continue processing other params in the chunk 28177ebe684SGeorge Shepherd * 0. Stop processing params after this one. 28277ebe684SGeorge Shepherd * 2nd bit: 28377ebe684SGeorge Shepherd * 1. Must report this unrecognized param to remote 28477ebe684SGeorge Shepherd * 0. Obey the top bit silently. 2857c478bd9Sstevel@tonic-gate */ 28677ebe684SGeorge Shepherd if (ptype & SCTP_REPORT_THIS_PARAM) { 287c513743fSGeorge Shepherd if (!got_errchunk && want_cookie != NULL) { 28877ebe684SGeorge Shepherd /* 2895e8aaf77SGeorge Shepherd * The incoming pointer want_cookie is 2905e8aaf77SGeorge Shepherd * NULL so processing an INIT_ACK. 2915e8aaf77SGeorge Shepherd * This is the first reportable param, 2925e8aaf77SGeorge Shepherd * create an ERROR chunk and populate 2935e8aaf77SGeorge Shepherd * it with a CAUSE block for this parm. 29477ebe684SGeorge Shepherd */ 2957c478bd9Sstevel@tonic-gate *errmp = sctp_make_err(sctp, 2967c478bd9Sstevel@tonic-gate PARM_UNRECOGNIZED, 2977c478bd9Sstevel@tonic-gate (void *)cph, 2987c478bd9Sstevel@tonic-gate ntohs(cph->sph_len)); 29977ebe684SGeorge Shepherd got_errchunk = B_TRUE; 3007c478bd9Sstevel@tonic-gate } else { 30177ebe684SGeorge Shepherd /* 3025e8aaf77SGeorge Shepherd * If processing an INIT_ACK, we already 3035e8aaf77SGeorge Shepherd * have an ERROR chunk, just add a new 3045e8aaf77SGeorge Shepherd * CAUSE block and update ERROR chunk 3055e8aaf77SGeorge Shepherd * length. 3065e8aaf77SGeorge Shepherd * If processing an INIT chunk add a new 3075e8aaf77SGeorge Shepherd * CAUSE block to the INIT_ACK, in this 3085e8aaf77SGeorge Shepherd * case there is no ERROR chunk thus 3095e8aaf77SGeorge Shepherd * got_errchunk will be B_FALSE. Chunk 3105e8aaf77SGeorge Shepherd * length is computed by our caller. 31177ebe684SGeorge Shepherd */ 312c513743fSGeorge Shepherd sctp_add_unrec_parm(cph, errmp, 313c513743fSGeorge Shepherd got_errchunk); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate } 31677ebe684SGeorge Shepherd if (ptype & SCTP_CONT_PROC_PARAMS) { 3177c478bd9Sstevel@tonic-gate /* 31877ebe684SGeorge Shepherd * Continue processing params after this 31977ebe684SGeorge Shepherd * parameter. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate break; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate /* 32577ebe684SGeorge Shepherd * Stop processing params, report any reportable 32677ebe684SGeorge Shepherd * unrecognized params found so far. 3277c478bd9Sstevel@tonic-gate */ 32877ebe684SGeorge Shepherd goto done; 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate cph = sctp_next_parm(cph, &remaining); 3327c478bd9Sstevel@tonic-gate } 33377ebe684SGeorge Shepherd done: 334f551bb10Svi117747 /* 335f551bb10Svi117747 * Some sanity checks. The following should not fail unless the 336f551bb10Svi117747 * other side is broken. 337f551bb10Svi117747 * 338f551bb10Svi117747 * 1. If this is a V4 endpoint but V4 address is not 339f551bb10Svi117747 * supported, abort. 340f551bb10Svi117747 * 2. If this is a V6 only endpoint but V6 address is 341f551bb10Svi117747 * not supported, abort. This assumes that a V6 342f551bb10Svi117747 * endpoint can use both V4 and V6 addresses. 343f551bb10Svi117747 * We only care about supp_af when processing INIT, i.e want_cookie 344f551bb10Svi117747 * is NULL. 345f551bb10Svi117747 */ 346f551bb10Svi117747 if (want_cookie == NULL && 347bd670b35SErik Nordmark ((connp->conn_family == AF_INET && !(*supp_af & PARM_SUPP_V4)) || 348bd670b35SErik Nordmark (connp->conn_family == AF_INET6 && !(*supp_af & PARM_SUPP_V6) && 349f551bb10Svi117747 sctp->sctp_connp->conn_ipv6_v6only))) { 350f551bb10Svi117747 dprint(1, ("sctp:validate_init_params: supp addr\n")); 351f551bb10Svi117747 serror = SCTP_ERR_BAD_ADDR; 352f551bb10Svi117747 goto abort; 353f551bb10Svi117747 } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate if (want_cookie != NULL && !got_cookie) { 3567c478bd9Sstevel@tonic-gate cookie_abort: 35747b33325SGeorge Shepherd /* Will populate the CAUSE block in the ABORT chunk. */ 35847b33325SGeorge Shepherd mpc.mpc_num = htons(1); 35947b33325SGeorge Shepherd mpc.mpc_param = htons(PARM_COOKIE); 36047b33325SGeorge Shepherd mpc.mpc_pad = 0; 36147b33325SGeorge Shepherd 3627c478bd9Sstevel@tonic-gate dprint(1, ("validate_init_params: cookie absent\n")); 3637c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctp_init2vtag(ch), SCTP_ERR_MISSING_PARM, 364bd670b35SErik Nordmark (char *)&mpc, sizeof (sctp_mpc_t), inmp, 0, B_FALSE, ira); 3657c478bd9Sstevel@tonic-gate return (0); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* OK */ 3697c478bd9Sstevel@tonic-gate return (1); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate abort: 3727c478bd9Sstevel@tonic-gate if (want_cookie != NULL) 3737c478bd9Sstevel@tonic-gate return (0); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctp_init2vtag(ch), serror, details, 376bd670b35SErik Nordmark errlen, inmp, 0, B_FALSE, ira); 3777c478bd9Sstevel@tonic-gate return (0); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* 3817c478bd9Sstevel@tonic-gate * Initialize params from the INIT and INIT-ACK when the assoc. is 3827c478bd9Sstevel@tonic-gate * established. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate boolean_t 3857c478bd9Sstevel@tonic-gate sctp_initialize_params(sctp_t *sctp, sctp_init_chunk_t *init, 3867c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack) 3877c478bd9Sstevel@tonic-gate { 3887c478bd9Sstevel@tonic-gate /* Get initial TSN */ 3897c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = ntohl(init->sic_inittsn); 3907c478bd9Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* Serial number is initialized to the same value as the TSN */ 3937c478bd9Sstevel@tonic-gate sctp->sctp_fcsn = sctp->sctp_lastacked; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * Get verification tags; no byteordering is necessary, since 3977c478bd9Sstevel@tonic-gate * verfication tags are never processed except for byte-by-byte 3987c478bd9Sstevel@tonic-gate * comparisons. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate sctp->sctp_fvtag = init->sic_inittag; 4017c478bd9Sstevel@tonic-gate sctp->sctp_sctph->sh_verf = init->sic_inittag; 4027c478bd9Sstevel@tonic-gate sctp->sctp_sctph6->sh_verf = init->sic_inittag; 4037c478bd9Sstevel@tonic-gate sctp->sctp_lvtag = iack->sic_inittag; 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate /* Get the peer's rwnd */ 4067c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = ntohl(init->sic_a_rwnd); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* Allocate the in/out-stream counters */ 4097c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr = iack->sic_outstr; 4107c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = kmem_zalloc(sizeof (uint16_t) * 4117c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr, KM_NOSLEEP); 4127c478bd9Sstevel@tonic-gate if (sctp->sctp_ostrcntrs == NULL) 4137c478bd9Sstevel@tonic-gate return (B_FALSE); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate sctp->sctp_num_istr = iack->sic_instr; 4167c478bd9Sstevel@tonic-gate sctp->sctp_instr = kmem_zalloc(sizeof (*sctp->sctp_instr) * 4177c478bd9Sstevel@tonic-gate sctp->sctp_num_istr, KM_NOSLEEP); 4187c478bd9Sstevel@tonic-gate if (sctp->sctp_instr == NULL) { 4197c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_ostrcntrs, sizeof (uint16_t) * 4207c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr); 4217c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = NULL; 4227c478bd9Sstevel@tonic-gate return (B_FALSE); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate return (B_TRUE); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4271d8c4025Svi117747 /* 4281d8c4025Svi117747 * Copy the peer's original source address into addr. This relies on the 4291d8c4025Svi117747 * following format (see sctp_send_initack() below): 4301d8c4025Svi117747 * relative timestamp for the cookie (int64_t) + 4311d8c4025Svi117747 * cookie lifetime (uint32_t) + 4321d8c4025Svi117747 * local tie-tag (uint32_t) + peer tie-tag (uint32_t) + 4331d8c4025Svi117747 * Peer's original src ... 4341d8c4025Svi117747 */ 4351d8c4025Svi117747 int 4361d8c4025Svi117747 cl_sctp_cookie_paddr(sctp_chunk_hdr_t *ch, in6_addr_t *addr) 4371d8c4025Svi117747 { 4381d8c4025Svi117747 uchar_t *off; 4391d8c4025Svi117747 4401d8c4025Svi117747 ASSERT(addr != NULL); 4411d8c4025Svi117747 4421d8c4025Svi117747 if (ch->sch_id != CHUNK_COOKIE) 4431d8c4025Svi117747 return (EINVAL); 4441d8c4025Svi117747 4451d8c4025Svi117747 off = (uchar_t *)ch + sizeof (*ch) + sizeof (int64_t) + 4461d8c4025Svi117747 sizeof (uint32_t) + sizeof (uint32_t) + sizeof (uint32_t); 4471d8c4025Svi117747 4481d8c4025Svi117747 bcopy(off, addr, sizeof (*addr)); 4491d8c4025Svi117747 4501d8c4025Svi117747 return (0); 4511d8c4025Svi117747 } 4521d8c4025Svi117747 4537c478bd9Sstevel@tonic-gate #define SCTP_CALC_COOKIE_LEN(initcp) \ 4547c478bd9Sstevel@tonic-gate sizeof (int64_t) + /* timestamp */ \ 4557c478bd9Sstevel@tonic-gate sizeof (uint32_t) + /* cookie lifetime */ \ 4567c478bd9Sstevel@tonic-gate sizeof (sctp_init_chunk_t) + /* INIT ACK */ \ 4577c478bd9Sstevel@tonic-gate sizeof (in6_addr_t) + /* peer's original source */ \ 4587c478bd9Sstevel@tonic-gate ntohs((initcp)->sch_len) + /* peer's INIT */ \ 4597c478bd9Sstevel@tonic-gate sizeof (uint32_t) + /* local tie-tag */ \ 4607c478bd9Sstevel@tonic-gate sizeof (uint32_t) + /* peer tie-tag */ \ 4617c478bd9Sstevel@tonic-gate sizeof (sctp_parm_hdr_t) + /* param header */ \ 4627c478bd9Sstevel@tonic-gate 16 /* MD5 hash */ 4637c478bd9Sstevel@tonic-gate 464bd670b35SErik Nordmark /* 465bd670b35SErik Nordmark * Note that sctp is the listener, hence we shouldn't modify it. 466bd670b35SErik Nordmark */ 4677c478bd9Sstevel@tonic-gate void 468d7ab25acSkp158701 sctp_send_initack(sctp_t *sctp, sctp_hdr_t *initsh, sctp_chunk_hdr_t *ch, 469bd670b35SErik Nordmark mblk_t *initmp, ip_recv_attr_t *ira) 4707c478bd9Sstevel@tonic-gate { 4717c478bd9Sstevel@tonic-gate ipha_t *initiph; 4727c478bd9Sstevel@tonic-gate ip6_t *initip6h; 473bd670b35SErik Nordmark ipha_t *iackiph = NULL; 474bd670b35SErik Nordmark ip6_t *iackip6h = NULL; 4757c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *iack_ch; 4767c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 4777c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init; 4787c478bd9Sstevel@tonic-gate sctp_hdr_t *iacksh; 4797c478bd9Sstevel@tonic-gate size_t cookielen; 4807c478bd9Sstevel@tonic-gate size_t iacklen; 4817c478bd9Sstevel@tonic-gate size_t ipsctplen; 4827c478bd9Sstevel@tonic-gate size_t errlen = 0; 4837c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *cookieph; 4847c478bd9Sstevel@tonic-gate mblk_t *iackmp; 4857c478bd9Sstevel@tonic-gate uint32_t itag; 4867c478bd9Sstevel@tonic-gate uint32_t itsn; 4877c478bd9Sstevel@tonic-gate int64_t *now; 4887c478bd9Sstevel@tonic-gate int64_t nowt; 4897c478bd9Sstevel@tonic-gate uint32_t *lifetime; 4907c478bd9Sstevel@tonic-gate char *p; 4917c478bd9Sstevel@tonic-gate boolean_t isv4; 492f551bb10Svi117747 int supp_af = 0; 4937c478bd9Sstevel@tonic-gate uint_t sctp_options; 4947c478bd9Sstevel@tonic-gate uint32_t *ttag; 4957c478bd9Sstevel@tonic-gate int pad; 4967c478bd9Sstevel@tonic-gate mblk_t *errmp = NULL; 4977c478bd9Sstevel@tonic-gate boolean_t initcollision = B_FALSE; 498f551bb10Svi117747 boolean_t linklocal = B_FALSE; 499f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 500bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 501bd670b35SErik Nordmark int err; 502bd670b35SErik Nordmark ip_xmit_attr_t *ixa = NULL; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 5057c478bd9Sstevel@tonic-gate isv4 = (IPH_HDR_VERSION(initmp->b_rptr) == IPV4_VERSION); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate /* Extract the INIT chunk */ 5087c478bd9Sstevel@tonic-gate if (isv4) { 5097c478bd9Sstevel@tonic-gate initiph = (ipha_t *)initmp->b_rptr; 5107c478bd9Sstevel@tonic-gate ipsctplen = sctp->sctp_ip_hdr_len; 511f551bb10Svi117747 supp_af |= PARM_SUPP_V4; 5127c478bd9Sstevel@tonic-gate } else { 5137c478bd9Sstevel@tonic-gate initip6h = (ip6_t *)initmp->b_rptr; 5147c478bd9Sstevel@tonic-gate ipsctplen = sctp->sctp_ip_hdr6_len; 515bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&initip6h->ip6_src) || 516bd670b35SErik Nordmark IN6_IS_ADDR_LINKLOCAL(&initip6h->ip6_dst)) 517f551bb10Svi117747 linklocal = B_TRUE; 518f551bb10Svi117747 supp_af |= PARM_SUPP_V6; 519bd670b35SErik Nordmark if (!sctp->sctp_connp->conn_ipv6_v6only) 520bd670b35SErik Nordmark supp_af |= PARM_SUPP_V4; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(initsh)); 5237c478bd9Sstevel@tonic-gate init = (sctp_init_chunk_t *)((char *)(initsh + 1) + sizeof (*iack_ch)); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* Make sure we like the peer's parameters */ 5267c478bd9Sstevel@tonic-gate if (validate_init_params(sctp, ch, init, initmp, NULL, &errmp, 527bd670b35SErik Nordmark &supp_af, &sctp_options, ira) == 0) { 5287c478bd9Sstevel@tonic-gate return; 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate if (errmp != NULL) 5317c478bd9Sstevel@tonic-gate errlen = msgdsize(errmp); 532bd670b35SErik Nordmark if (connp->conn_family == AF_INET) { 5337c478bd9Sstevel@tonic-gate /* 5345e8aaf77SGeorge Shepherd * Regardless of the supported address in the INIT, v4 5357c478bd9Sstevel@tonic-gate * must be supported. 5367c478bd9Sstevel@tonic-gate */ 5377c478bd9Sstevel@tonic-gate supp_af = PARM_SUPP_V4; 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate if (sctp->sctp_state <= SCTPS_LISTEN) { 5407c478bd9Sstevel@tonic-gate /* normal, expected INIT: generate new vtag and itsn */ 5417c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)&itag, sizeof (itag)); 5427c478bd9Sstevel@tonic-gate if (itag == 0) 5437c478bd9Sstevel@tonic-gate itag = (uint32_t)gethrtime(); 5447c478bd9Sstevel@tonic-gate itsn = itag + 1; 5457c478bd9Sstevel@tonic-gate itag = htonl(itag); 5467c478bd9Sstevel@tonic-gate } else if (sctp->sctp_state == SCTPS_COOKIE_WAIT || 5477c478bd9Sstevel@tonic-gate sctp->sctp_state == SCTPS_COOKIE_ECHOED) { 5487c478bd9Sstevel@tonic-gate /* init collision; copy vtag and itsn from sctp */ 5497c478bd9Sstevel@tonic-gate itag = sctp->sctp_lvtag; 5507c478bd9Sstevel@tonic-gate itsn = sctp->sctp_ltsn; 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * In addition we need to send all the params that was sent 5537c478bd9Sstevel@tonic-gate * in our INIT chunk. Essentially, it is only the supported 5547c478bd9Sstevel@tonic-gate * address params that we need to add. 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate initcollision = B_TRUE; 557f551bb10Svi117747 /* 558f551bb10Svi117747 * When we sent the INIT, we should have set linklocal in 559f551bb10Svi117747 * the sctp which should be good enough. 560f551bb10Svi117747 */ 561f551bb10Svi117747 if (linklocal) 562f551bb10Svi117747 linklocal = B_FALSE; 5637c478bd9Sstevel@tonic-gate } else { 5647c478bd9Sstevel@tonic-gate /* peer restart; generate new vtag but keep everything else */ 5657c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)&itag, sizeof (itag)); 5667c478bd9Sstevel@tonic-gate if (itag == 0) 5677c478bd9Sstevel@tonic-gate itag = (uint32_t)gethrtime(); 5687c478bd9Sstevel@tonic-gate itag = htonl(itag); 5697c478bd9Sstevel@tonic-gate itsn = sctp->sctp_ltsn; 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate /* 5737c478bd9Sstevel@tonic-gate * Allocate a mblk for the INIT ACK, consisting of the link layer 5747c478bd9Sstevel@tonic-gate * header, the IP header, the SCTP common header, and INIT ACK chunk, 5757c478bd9Sstevel@tonic-gate * and finally the COOKIE parameter. 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate cookielen = SCTP_CALC_COOKIE_LEN(ch); 5787c478bd9Sstevel@tonic-gate iacklen = sizeof (*iack_ch) + sizeof (*iack) + cookielen; 579558fbd03Skcpoon if (sctp->sctp_send_adaptation) 5807c478bd9Sstevel@tonic-gate iacklen += (sizeof (sctp_parm_hdr_t) + sizeof (uint32_t)); 5817c478bd9Sstevel@tonic-gate if (((sctp_options & SCTP_PRSCTP_OPTION) || initcollision) && 582f4b3ec61Sdh155122 sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) { 5837c478bd9Sstevel@tonic-gate iacklen += sctp_options_param_len(sctp, SCTP_PRSCTP_OPTION); 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate if (initcollision) 5867c478bd9Sstevel@tonic-gate iacklen += sctp_supaddr_param_len(sctp); 587f551bb10Svi117747 if (!linklocal) 58812f47623Skcpoon iacklen += sctp_addr_params(sctp, supp_af, NULL, B_FALSE); 5897c478bd9Sstevel@tonic-gate ipsctplen += sizeof (*iacksh) + iacklen; 5907c478bd9Sstevel@tonic-gate iacklen += errlen; 5915e8aaf77SGeorge Shepherd /* 5925e8aaf77SGeorge Shepherd * Padding is applied after the cookie which is the end of chunk 5935e8aaf77SGeorge Shepherd * unless CAUSE blocks are appended when the pad must also be 5945e8aaf77SGeorge Shepherd * accounted for in iacklen. 5955e8aaf77SGeorge Shepherd */ 5965e8aaf77SGeorge Shepherd if ((pad = ipsctplen % SCTP_ALIGN) != 0) { 5975e8aaf77SGeorge Shepherd pad = SCTP_ALIGN - pad; 5987c478bd9Sstevel@tonic-gate ipsctplen += pad; 5995e8aaf77SGeorge Shepherd if (errmp != NULL) 6005e8aaf77SGeorge Shepherd iacklen += pad; 6017c478bd9Sstevel@tonic-gate } 602d7ab25acSkp158701 603d7ab25acSkp158701 /* 604bd670b35SErik Nordmark * Base the transmission on any routing-related socket options 605bd670b35SErik Nordmark * that have been set on the listener. 606bd670b35SErik Nordmark */ 607bd670b35SErik Nordmark ixa = conn_get_ixa_exclusive(connp); 608bd670b35SErik Nordmark if (ixa == NULL) { 609bd670b35SErik Nordmark sctp_send_abort(sctp, sctp_init2vtag(ch), 610bd670b35SErik Nordmark SCTP_ERR_NO_RESOURCES, NULL, 0, initmp, 0, B_FALSE, ira); 611bd670b35SErik Nordmark return; 612bd670b35SErik Nordmark } 613bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_VERIFY_PMTU; 614bd670b35SErik Nordmark 615bd670b35SErik Nordmark if (isv4) 616bd670b35SErik Nordmark ixa->ixa_flags |= IXAF_IS_IPV4; 617bd670b35SErik Nordmark else 618bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_IS_IPV4; 619bd670b35SErik Nordmark 620bd670b35SErik Nordmark /* 621bd670b35SErik Nordmark * If the listen socket is bound to a trusted extensions multi-label 622bd670b35SErik Nordmark * port, a MAC-Exempt connection with an unlabeled node, we use the 623d7ab25acSkp158701 * the security label of the received INIT packet. 624d7ab25acSkp158701 * If not a multi-label port, attach the unmodified 625bd670b35SErik Nordmark * listener's label directly. 626d7ab25acSkp158701 * 627d7ab25acSkp158701 * We expect Sun developed kernel modules to properly set 628d7ab25acSkp158701 * cred labels for sctp connections. We can't be so sure this 629d7ab25acSkp158701 * will be done correctly when 3rd party kernel modules 630bd670b35SErik Nordmark * directly use sctp. We check for a NULL ira_tsl to cover this 631bd670b35SErik Nordmark * possibility. 632d7ab25acSkp158701 */ 633bd670b35SErik Nordmark if (is_system_labeled()) { 634bd670b35SErik Nordmark /* Discard any old label */ 635bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 636bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 637bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 638bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_TSL; 639bd670b35SErik Nordmark ixa->ixa_tsl = NULL; 640bd670b35SErik Nordmark } 641bd670b35SErik Nordmark 642bd670b35SErik Nordmark if (connp->conn_mlp_type != mlptSingle || 643bd670b35SErik Nordmark connp->conn_mac_mode != CONN_MAC_DEFAULT) { 644bd670b35SErik Nordmark if (ira->ira_tsl == NULL) { 645d7ab25acSkp158701 sctp_send_abort(sctp, sctp_init2vtag(ch), 646bd670b35SErik Nordmark SCTP_ERR_UNKNOWN, NULL, 0, initmp, 0, 647bd670b35SErik Nordmark B_FALSE, ira); 648bd670b35SErik Nordmark ixa_refrele(ixa); 649d7ab25acSkp158701 return; 650d7ab25acSkp158701 } 651bd670b35SErik Nordmark label_hold(ira->ira_tsl); 652bd670b35SErik Nordmark ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl); 653d7ab25acSkp158701 } else { 654bd670b35SErik Nordmark ixa->ixa_tsl = crgetlabel(connp->conn_cred); 655d7ab25acSkp158701 } 656bd670b35SErik Nordmark } 657bd670b35SErik Nordmark 658bd670b35SErik Nordmark iackmp = allocb(ipsctplen + sctps->sctps_wroff_xtra, BPRI_MED); 6597c478bd9Sstevel@tonic-gate if (iackmp == NULL) { 6607c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, sctp_init2vtag(ch), 661bd670b35SErik Nordmark SCTP_ERR_NO_RESOURCES, NULL, 0, initmp, 0, B_FALSE, ira); 662bd670b35SErik Nordmark ixa_refrele(ixa); 6637c478bd9Sstevel@tonic-gate return; 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate /* Copy in the [imcomplete] IP/SCTP composite header */ 667f4b3ec61Sdh155122 p = (char *)(iackmp->b_rptr + sctps->sctps_wroff_xtra); 6687c478bd9Sstevel@tonic-gate iackmp->b_rptr = (uchar_t *)p; 6697c478bd9Sstevel@tonic-gate if (isv4) { 6707c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_iphc, p, sctp->sctp_hdr_len); 6717c478bd9Sstevel@tonic-gate iackiph = (ipha_t *)p; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* Copy the peer's IP addr */ 6747c478bd9Sstevel@tonic-gate iackiph->ipha_dst = initiph->ipha_src; 6757c478bd9Sstevel@tonic-gate iackiph->ipha_src = initiph->ipha_dst; 6767c478bd9Sstevel@tonic-gate iackiph->ipha_length = htons(ipsctplen + errlen); 6777c478bd9Sstevel@tonic-gate iacksh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr_len); 678bd670b35SErik Nordmark ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr_len; 6797c478bd9Sstevel@tonic-gate } else { 6807c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_iphc6, p, sctp->sctp_hdr6_len); 6817c478bd9Sstevel@tonic-gate iackip6h = (ip6_t *)p; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* Copy the peer's IP addr */ 6847c478bd9Sstevel@tonic-gate iackip6h->ip6_dst = initip6h->ip6_src; 6857c478bd9Sstevel@tonic-gate iackip6h->ip6_src = initip6h->ip6_dst; 686bd670b35SErik Nordmark iackip6h->ip6_plen = htons(ipsctplen + errlen - IPV6_HDR_LEN); 6877c478bd9Sstevel@tonic-gate iacksh = (sctp_hdr_t *)(p + sctp->sctp_ip_hdr6_len); 688bd670b35SErik Nordmark ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr6_len; 6897c478bd9Sstevel@tonic-gate } 690bd670b35SErik Nordmark ixa->ixa_pktlen = ipsctplen + errlen; 691bd670b35SErik Nordmark 6927c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(iacksh)); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate /* Fill in the holes in the SCTP common header */ 6957c478bd9Sstevel@tonic-gate iacksh->sh_sport = initsh->sh_dport; 6967c478bd9Sstevel@tonic-gate iacksh->sh_dport = initsh->sh_sport; 6977c478bd9Sstevel@tonic-gate iacksh->sh_verf = init->sic_inittag; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* INIT ACK chunk header */ 7007c478bd9Sstevel@tonic-gate iack_ch = (sctp_chunk_hdr_t *)(iacksh + 1); 7017c478bd9Sstevel@tonic-gate iack_ch->sch_id = CHUNK_INIT_ACK; 7027c478bd9Sstevel@tonic-gate iack_ch->sch_flags = 0; 7037c478bd9Sstevel@tonic-gate iack_ch->sch_len = htons(iacklen); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* The INIT ACK itself */ 7067c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)(iack_ch + 1); 7077c478bd9Sstevel@tonic-gate iack->sic_inittag = itag; /* already in network byteorder */ 7087c478bd9Sstevel@tonic-gate iack->sic_inittsn = htonl(itsn); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate iack->sic_a_rwnd = htonl(sctp->sctp_rwnd); 7117c478bd9Sstevel@tonic-gate /* Advertise what we would want to have as stream #'s */ 7127c478bd9Sstevel@tonic-gate iack->sic_outstr = htons(MIN(sctp->sctp_num_ostr, 7137c478bd9Sstevel@tonic-gate ntohs(init->sic_instr))); 7147c478bd9Sstevel@tonic-gate iack->sic_instr = htons(sctp->sctp_num_istr); 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate p = (char *)(iack + 1); 717558fbd03Skcpoon p += sctp_adaptation_code_param(sctp, (uchar_t *)p); 7187c478bd9Sstevel@tonic-gate if (initcollision) 7197c478bd9Sstevel@tonic-gate p += sctp_supaddr_param(sctp, (uchar_t *)p); 720f551bb10Svi117747 if (!linklocal) 72112f47623Skcpoon p += sctp_addr_params(sctp, supp_af, (uchar_t *)p, B_FALSE); 7227c478bd9Sstevel@tonic-gate if (((sctp_options & SCTP_PRSCTP_OPTION) || initcollision) && 723f4b3ec61Sdh155122 sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) { 7247c478bd9Sstevel@tonic-gate p += sctp_options_param(sctp, p, SCTP_PRSCTP_OPTION); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate /* 7277c478bd9Sstevel@tonic-gate * Generate and lay in the COOKIE parameter. 7287c478bd9Sstevel@tonic-gate * 7291d8c4025Svi117747 * Any change here that results in a change of location for 7301d8c4025Svi117747 * the peer's orig source address must be propagated to the fn 7311d8c4025Svi117747 * cl_sctp_cookie_paddr() above. 7321d8c4025Svi117747 * 7337c478bd9Sstevel@tonic-gate * The cookie consists of: 7347c478bd9Sstevel@tonic-gate * 1. The relative timestamp for the cookie (lbolt64) 7357c478bd9Sstevel@tonic-gate * 2. The cookie lifetime (uint32_t) in tick 7367c478bd9Sstevel@tonic-gate * 3. The local tie-tag 7377c478bd9Sstevel@tonic-gate * 4. The peer tie-tag 7387c478bd9Sstevel@tonic-gate * 5. Peer's original src, used to confirm the validity of address. 7397c478bd9Sstevel@tonic-gate * 6. Our INIT ACK chunk, less any parameters 7407c478bd9Sstevel@tonic-gate * 7. The INIT chunk (may contain parameters) 7417c478bd9Sstevel@tonic-gate * 8. 128-bit MD5 signature. 7427c478bd9Sstevel@tonic-gate * 7437c478bd9Sstevel@tonic-gate * Since the timestamp values will only be evaluated locally, we 7447c478bd9Sstevel@tonic-gate * don't need to worry about byte-ordering them. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate cookieph = (sctp_parm_hdr_t *)p; 7477c478bd9Sstevel@tonic-gate cookieph->sph_type = htons(PARM_COOKIE); 7487c478bd9Sstevel@tonic-gate cookieph->sph_len = htons(cookielen); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* timestamp */ 7517c478bd9Sstevel@tonic-gate now = (int64_t *)(cookieph + 1); 7525dd46ab5SKacheong Poon nowt = LBOLT_FASTPATH64; 7537c478bd9Sstevel@tonic-gate bcopy(&nowt, now, sizeof (*now)); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* cookie lifetime -- need configuration */ 7567c478bd9Sstevel@tonic-gate lifetime = (uint32_t *)(now + 1); 7577c478bd9Sstevel@tonic-gate *lifetime = sctp->sctp_cookie_lifetime; 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate /* Set the tie-tags */ 7607c478bd9Sstevel@tonic-gate ttag = (uint32_t *)(lifetime + 1); 7617c478bd9Sstevel@tonic-gate if (sctp->sctp_state <= SCTPS_COOKIE_WAIT) { 7627c478bd9Sstevel@tonic-gate *ttag = 0; 7637c478bd9Sstevel@tonic-gate ttag++; 7647c478bd9Sstevel@tonic-gate *ttag = 0; 7657c478bd9Sstevel@tonic-gate ttag++; 7667c478bd9Sstevel@tonic-gate } else { 7677c478bd9Sstevel@tonic-gate /* local tie-tag (network byte-order) */ 7687c478bd9Sstevel@tonic-gate *ttag = sctp->sctp_lvtag; 7697c478bd9Sstevel@tonic-gate ttag++; 7707c478bd9Sstevel@tonic-gate /* peer tie-tag (network byte-order) */ 7717c478bd9Sstevel@tonic-gate *ttag = sctp->sctp_fvtag; 7727c478bd9Sstevel@tonic-gate ttag++; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * Copy in peer's original source address so that we can confirm 7767c478bd9Sstevel@tonic-gate * the reachability later. 7777c478bd9Sstevel@tonic-gate */ 7787c478bd9Sstevel@tonic-gate p = (char *)ttag; 7797c478bd9Sstevel@tonic-gate if (isv4) { 7807c478bd9Sstevel@tonic-gate in6_addr_t peer_addr; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(iackiph->ipha_dst, &peer_addr); 7837c478bd9Sstevel@tonic-gate bcopy(&peer_addr, p, sizeof (in6_addr_t)); 7847c478bd9Sstevel@tonic-gate } else { 7857c478bd9Sstevel@tonic-gate bcopy(&iackip6h->ip6_dst, p, sizeof (in6_addr_t)); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate p += sizeof (in6_addr_t); 7887c478bd9Sstevel@tonic-gate /* Copy in our INIT ACK chunk */ 7897c478bd9Sstevel@tonic-gate bcopy(iack, p, sizeof (*iack)); 7907c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)p; 7917c478bd9Sstevel@tonic-gate /* Set the # of streams we'll end up using */ 7927c478bd9Sstevel@tonic-gate iack->sic_outstr = MIN(sctp->sctp_num_ostr, ntohs(init->sic_instr)); 7937c478bd9Sstevel@tonic-gate iack->sic_instr = MIN(sctp->sctp_num_istr, ntohs(init->sic_outstr)); 7947c478bd9Sstevel@tonic-gate p += sizeof (*iack); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* Copy in the peer's INIT chunk */ 7977c478bd9Sstevel@tonic-gate bcopy(ch, p, ntohs(ch->sch_len)); 7987c478bd9Sstevel@tonic-gate p += ntohs(ch->sch_len); 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * Calculate the HMAC ICV into the digest slot in buf. 8027c478bd9Sstevel@tonic-gate * First, generate a new secret if the current secret is 8037c478bd9Sstevel@tonic-gate * older than the new secret lifetime parameter permits, 8047c478bd9Sstevel@tonic-gate * copying the current secret to sctp_old_secret. 8057c478bd9Sstevel@tonic-gate */ 806f4b3ec61Sdh155122 if (sctps->sctps_new_secret_interval > 0 && 8077c478bd9Sstevel@tonic-gate (sctp->sctp_last_secret_update + 808f4b3ec61Sdh155122 MSEC_TO_TICK(sctps->sctps_new_secret_interval)) <= nowt) { 8097c478bd9Sstevel@tonic-gate bcopy(sctp->sctp_secret, sctp->sctp_old_secret, 8107c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN); 8117c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes(sctp->sctp_secret, 8127c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN); 8137c478bd9Sstevel@tonic-gate sctp->sctp_last_secret_update = nowt; 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate hmac_md5((uchar_t *)now, cookielen - sizeof (*cookieph) - 16, 8177c478bd9Sstevel@tonic-gate (uchar_t *)sctp->sctp_secret, SCTP_SECRET_LEN, (uchar_t *)p); 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate iackmp->b_wptr = iackmp->b_rptr + ipsctplen; 820c513743fSGeorge Shepherd if (pad != 0) 821c513743fSGeorge Shepherd bzero((iackmp->b_wptr - pad), pad); 822c513743fSGeorge Shepherd 8237c478bd9Sstevel@tonic-gate iackmp->b_cont = errmp; /* OK if NULL */ 8247c478bd9Sstevel@tonic-gate 825bd670b35SErik Nordmark if (is_system_labeled()) { 826bd670b35SErik Nordmark ts_label_t *effective_tsl = NULL; 82745916cd2Sjpk 828bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL); 829bd670b35SErik Nordmark 830bd670b35SErik Nordmark /* Discard any old label */ 831bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 832bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 833bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 834bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_TSL; 835bd670b35SErik Nordmark } 836bd670b35SErik Nordmark ixa->ixa_tsl = ira->ira_tsl; /* A multi-level responder */ 837bd670b35SErik Nordmark 838bd670b35SErik Nordmark /* 839bd670b35SErik Nordmark * We need to check for label-related failures which implies 840bd670b35SErik Nordmark * an extra call to tsol_check_dest (as ip_output_simple 841bd670b35SErik Nordmark * also does a tsol_check_dest as part of computing the 842bd670b35SErik Nordmark * label for the packet, but ip_output_simple doesn't return 843bd670b35SErik Nordmark * a specific errno for that case so we can't rely on its 844bd670b35SErik Nordmark * check.) 845bd670b35SErik Nordmark */ 846bd670b35SErik Nordmark if (isv4) { 847bd670b35SErik Nordmark err = tsol_check_dest(ixa->ixa_tsl, &iackiph->ipha_dst, 848bd670b35SErik Nordmark IPV4_VERSION, connp->conn_mac_mode, 849bd670b35SErik Nordmark connp->conn_zone_is_global, &effective_tsl); 850bd670b35SErik Nordmark } else { 851bd670b35SErik Nordmark err = tsol_check_dest(ixa->ixa_tsl, &iackip6h->ip6_dst, 852bd670b35SErik Nordmark IPV6_VERSION, connp->conn_mac_mode, 853bd670b35SErik Nordmark connp->conn_zone_is_global, &effective_tsl); 854bd670b35SErik Nordmark } 85545916cd2Sjpk if (err != 0) { 85645916cd2Sjpk sctp_send_abort(sctp, sctp_init2vtag(ch), 857bd670b35SErik Nordmark SCTP_ERR_AUTH_ERR, NULL, 0, initmp, 0, B_FALSE, 858bd670b35SErik Nordmark ira); 859bd670b35SErik Nordmark ixa_refrele(ixa); 86045916cd2Sjpk freemsg(iackmp); 86145916cd2Sjpk return; 86245916cd2Sjpk } 863bd670b35SErik Nordmark if (effective_tsl != NULL) { 864bd670b35SErik Nordmark /* 865bd670b35SErik Nordmark * Since ip_output_simple will redo the 866bd670b35SErik Nordmark * tsol_check_dest, we just drop the ref. 867bd670b35SErik Nordmark */ 868bd670b35SErik Nordmark label_rele(effective_tsl); 869bd670b35SErik Nordmark } 87045916cd2Sjpk } 87145916cd2Sjpk 8727c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_opkts); 8737c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 8747c478bd9Sstevel@tonic-gate 875bd670b35SErik Nordmark (void) ip_output_simple(iackmp, ixa); 876bd670b35SErik Nordmark ixa_refrele(ixa); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate void 8807c478bd9Sstevel@tonic-gate sctp_send_cookie_ack(sctp_t *sctp) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *cach; 8837c478bd9Sstevel@tonic-gate mblk_t *camp; 884f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 8857c478bd9Sstevel@tonic-gate 886bd670b35SErik Nordmark camp = sctp_make_mp(sctp, sctp->sctp_current, sizeof (*cach)); 8877c478bd9Sstevel@tonic-gate if (camp == NULL) { 8887c478bd9Sstevel@tonic-gate /* XXX should abort, but don't have the inmp anymore */ 889f4b3ec61Sdh155122 SCTP_KSTAT(sctps, sctp_send_cookie_ack_failed); 8907c478bd9Sstevel@tonic-gate return; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate cach = (sctp_chunk_hdr_t *)camp->b_wptr; 8947c478bd9Sstevel@tonic-gate camp->b_wptr = (uchar_t *)(cach + 1); 8957c478bd9Sstevel@tonic-gate cach->sch_id = CHUNK_COOKIE_ACK; 8967c478bd9Sstevel@tonic-gate cach->sch_flags = 0; 8977c478bd9Sstevel@tonic-gate cach->sch_len = htons(sizeof (*cach)); 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 9007c478bd9Sstevel@tonic-gate 901*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, camp, sctp->sctp_current->sf_ixa); 902*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(camp, sctp->sctp_current->sf_ixa); 903bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate static int 907558fbd03Skcpoon sctp_find_al_ind(sctp_parm_hdr_t *sph, ssize_t len, uint32_t *adaptation_code) 9087c478bd9Sstevel@tonic-gate { 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate if (len < sizeof (*sph)) 9117c478bd9Sstevel@tonic-gate return (-1); 9127c478bd9Sstevel@tonic-gate while (sph != NULL) { 9137c478bd9Sstevel@tonic-gate if (sph->sph_type == htons(PARM_ADAPT_LAYER_IND) && 9147c478bd9Sstevel@tonic-gate ntohs(sph->sph_len) >= (sizeof (*sph) + 9157c478bd9Sstevel@tonic-gate sizeof (uint32_t))) { 916558fbd03Skcpoon *adaptation_code = *(uint32_t *)(sph + 1); 9177c478bd9Sstevel@tonic-gate return (0); 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate sph = sctp_next_parm(sph, &len); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate return (-1); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate void 925bd670b35SErik Nordmark sctp_send_cookie_echo(sctp_t *sctp, sctp_chunk_hdr_t *iackch, mblk_t *iackmp, 926bd670b35SErik Nordmark ip_recv_attr_t *ira) 9277c478bd9Sstevel@tonic-gate { 9287c478bd9Sstevel@tonic-gate mblk_t *cemp; 9297c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 9307c478bd9Sstevel@tonic-gate mblk_t *head; 9317c478bd9Sstevel@tonic-gate mblk_t *meta; 9327c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 9337c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *cech; 9347c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 9357c478bd9Sstevel@tonic-gate int32_t cansend; 9367c478bd9Sstevel@tonic-gate int32_t seglen; 9377c478bd9Sstevel@tonic-gate size_t ceclen; 9387c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *cph; 9397c478bd9Sstevel@tonic-gate sctp_data_hdr_t *sdc; 9407c478bd9Sstevel@tonic-gate sctp_tf_t *tf; 941f551bb10Svi117747 int pad = 0; 9427c478bd9Sstevel@tonic-gate int hdrlen; 9437c478bd9Sstevel@tonic-gate mblk_t *errmp = NULL; 9447c478bd9Sstevel@tonic-gate uint_t sctp_options; 9457c478bd9Sstevel@tonic-gate int error; 9467c478bd9Sstevel@tonic-gate uint16_t old_num_str; 947f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)(iackch + 1); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate cph = NULL; 9527c478bd9Sstevel@tonic-gate if (validate_init_params(sctp, iackch, iack, iackmp, &cph, &errmp, 953bd670b35SErik Nordmark &pad, &sctp_options, ira) == 0) { /* result in 'pad' ignored */ 9545dd46ab5SKacheong Poon SCTPS_BUMP_MIB(sctps, sctpAborted); 9557c478bd9Sstevel@tonic-gate sctp_assoc_event(sctp, SCTP_CANT_STR_ASSOC, 0, NULL); 9567c478bd9Sstevel@tonic-gate sctp_clean_death(sctp, ECONNABORTED); 9577c478bd9Sstevel@tonic-gate return; 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate ASSERT(cph != NULL); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_cookie_mp == NULL); 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate /* Got a cookie to echo back; allocate an mblk */ 9647c478bd9Sstevel@tonic-gate ceclen = sizeof (*cech) + ntohs(cph->sph_len) - sizeof (*cph); 9657c478bd9Sstevel@tonic-gate if ((pad = ceclen & (SCTP_ALIGN - 1)) != 0) 9667c478bd9Sstevel@tonic-gate pad = SCTP_ALIGN - pad; 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate if (IPH_HDR_VERSION(iackmp->b_rptr) == IPV4_VERSION) 9697c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr_len; 9707c478bd9Sstevel@tonic-gate else 9717c478bd9Sstevel@tonic-gate hdrlen = sctp->sctp_hdr6_len; 9727c478bd9Sstevel@tonic-gate 973bd670b35SErik Nordmark cemp = allocb(sctps->sctps_wroff_xtra + hdrlen + ceclen + pad, 974bd670b35SErik Nordmark BPRI_MED); 9757c478bd9Sstevel@tonic-gate if (cemp == NULL) { 9767c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 977*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_current->sf_rto); 9787c478bd9Sstevel@tonic-gate if (errmp != NULL) 9797c478bd9Sstevel@tonic-gate freeb(errmp); 9807c478bd9Sstevel@tonic-gate return; 9817c478bd9Sstevel@tonic-gate } 982f4b3ec61Sdh155122 cemp->b_rptr += (sctps->sctps_wroff_xtra + hdrlen); 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate /* Process the INIT ACK */ 9857c478bd9Sstevel@tonic-gate sctp->sctp_sctph->sh_verf = iack->sic_inittag; 9867c478bd9Sstevel@tonic-gate sctp->sctp_sctph6->sh_verf = iack->sic_inittag; 9877c478bd9Sstevel@tonic-gate sctp->sctp_fvtag = iack->sic_inittag; 9887c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = ntohl(iack->sic_inittsn); 9897c478bd9Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 9907c478bd9Sstevel@tonic-gate sctp->sctp_fcsn = sctp->sctp_lastacked; 9917c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = ntohl(iack->sic_a_rwnd); 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate /* 9947c478bd9Sstevel@tonic-gate * Populate sctp with addresses given in the INIT ACK or IP header. 9957c478bd9Sstevel@tonic-gate * Need to set the df bit in the current fp as it has been cleared 9967c478bd9Sstevel@tonic-gate * in sctp_connect(). 9977c478bd9Sstevel@tonic-gate */ 998*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_current->sf_df = B_TRUE; 999bd670b35SErik Nordmark sctp->sctp_ipha->ipha_fragment_offset_and_flags |= IPH_DF_HTONS; 1000bd670b35SErik Nordmark 10017c478bd9Sstevel@tonic-gate /* 10027c478bd9Sstevel@tonic-gate * Since IP uses this info during the fanout process, we need to hold 10037c478bd9Sstevel@tonic-gate * the lock for this hash line while performing this operation. 10047c478bd9Sstevel@tonic-gate */ 1005bd670b35SErik Nordmark /* XXX sctp_conn_fanout + SCTP_CONN_HASH(sctps, connp->conn_ports); */ 10067c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_conn_tfp != NULL); 10077c478bd9Sstevel@tonic-gate tf = sctp->sctp_conn_tfp; 10087c478bd9Sstevel@tonic-gate /* sctp isn't a listener so only need to hold conn fanout lock */ 10097c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 10107c478bd9Sstevel@tonic-gate if (sctp_get_addrparams(sctp, NULL, iackmp, iackch, NULL) != 0) { 10117c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 10127c478bd9Sstevel@tonic-gate freeb(cemp); 10137c478bd9Sstevel@tonic-gate SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current, 1014*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp->sctp_current->sf_rto); 10157c478bd9Sstevel@tonic-gate if (errmp != NULL) 10167c478bd9Sstevel@tonic-gate freeb(errmp); 10177c478bd9Sstevel@tonic-gate return; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate fp = sctp->sctp_current; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * There could be a case when we get an INIT-ACK again, if the INIT 10257c478bd9Sstevel@tonic-gate * is re-transmitted, for e.g., which means we would have already 10267c478bd9Sstevel@tonic-gate * allocated this resource earlier (also for sctp_instr). In this 10277c478bd9Sstevel@tonic-gate * case we check and re-allocate, if necessary. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate old_num_str = sctp->sctp_num_ostr; 10307c478bd9Sstevel@tonic-gate if (ntohs(iack->sic_instr) < sctp->sctp_num_ostr) 10317c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr = ntohs(iack->sic_instr); 10327c478bd9Sstevel@tonic-gate if (sctp->sctp_ostrcntrs == NULL) { 10337c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = kmem_zalloc(sizeof (uint16_t) * 10347c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr, KM_NOSLEEP); 10357c478bd9Sstevel@tonic-gate } else { 10367c478bd9Sstevel@tonic-gate ASSERT(old_num_str > 0); 10377c478bd9Sstevel@tonic-gate if (old_num_str != sctp->sctp_num_ostr) { 10387c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_ostrcntrs, sizeof (uint16_t) * 10397c478bd9Sstevel@tonic-gate old_num_str); 10407c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs = kmem_zalloc(sizeof (uint16_t) * 10417c478bd9Sstevel@tonic-gate sctp->sctp_num_ostr, KM_NOSLEEP); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate if (sctp->sctp_ostrcntrs == NULL) { 10457c478bd9Sstevel@tonic-gate freeb(cemp); 1046*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 10477c478bd9Sstevel@tonic-gate if (errmp != NULL) 10487c478bd9Sstevel@tonic-gate freeb(errmp); 10497c478bd9Sstevel@tonic-gate return; 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate /* 10537c478bd9Sstevel@tonic-gate * Allocate the in stream tracking array. Comments for sctp_ostrcntrs 10547c478bd9Sstevel@tonic-gate * hold here too. 10557c478bd9Sstevel@tonic-gate */ 10567c478bd9Sstevel@tonic-gate old_num_str = sctp->sctp_num_istr; 10577c478bd9Sstevel@tonic-gate if (ntohs(iack->sic_outstr) < sctp->sctp_num_istr) 10587c478bd9Sstevel@tonic-gate sctp->sctp_num_istr = ntohs(iack->sic_outstr); 10597c478bd9Sstevel@tonic-gate if (sctp->sctp_instr == NULL) { 10607c478bd9Sstevel@tonic-gate sctp->sctp_instr = kmem_zalloc(sizeof (*sctp->sctp_instr) * 10617c478bd9Sstevel@tonic-gate sctp->sctp_num_istr, KM_NOSLEEP); 10627c478bd9Sstevel@tonic-gate } else { 10637c478bd9Sstevel@tonic-gate ASSERT(old_num_str > 0); 10647c478bd9Sstevel@tonic-gate if (old_num_str != sctp->sctp_num_istr) { 10657c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_instr, 10667c478bd9Sstevel@tonic-gate sizeof (*sctp->sctp_instr) * old_num_str); 10677c478bd9Sstevel@tonic-gate sctp->sctp_instr = kmem_zalloc( 10687c478bd9Sstevel@tonic-gate sizeof (*sctp->sctp_instr) * sctp->sctp_num_istr, 10697c478bd9Sstevel@tonic-gate KM_NOSLEEP); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate if (sctp->sctp_instr == NULL) { 10737c478bd9Sstevel@tonic-gate kmem_free(sctp->sctp_ostrcntrs, 10747c478bd9Sstevel@tonic-gate sizeof (uint16_t) * sctp->sctp_num_ostr); 10757c478bd9Sstevel@tonic-gate freeb(cemp); 1076*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 10777c478bd9Sstevel@tonic-gate if (errmp != NULL) 10787c478bd9Sstevel@tonic-gate freeb(errmp); 10797c478bd9Sstevel@tonic-gate return; 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate if (!(sctp_options & SCTP_PRSCTP_OPTION) && sctp->sctp_prsctp_aware) 10837c478bd9Sstevel@tonic-gate sctp->sctp_prsctp_aware = B_FALSE; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate if (sctp_find_al_ind((sctp_parm_hdr_t *)(iack + 1), 10867c478bd9Sstevel@tonic-gate ntohs(iackch->sch_len) - (sizeof (*iackch) + sizeof (*iack)), 1087558fbd03Skcpoon &sctp->sctp_rx_adaptation_code) == 0) { 1088558fbd03Skcpoon sctp->sctp_recv_adaptation = 1; 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate cech = (sctp_chunk_hdr_t *)cemp->b_rptr; 10927c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(cech)); 10937c478bd9Sstevel@tonic-gate cech->sch_id = CHUNK_COOKIE; 10947c478bd9Sstevel@tonic-gate cech->sch_flags = 0; 10957c478bd9Sstevel@tonic-gate cech->sch_len = htons(ceclen); 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* Copy the cookie (less the parm hdr) to the chunk */ 10987c478bd9Sstevel@tonic-gate bcopy(cph + 1, cech + 1, ceclen - sizeof (*cph)); 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate cemp->b_wptr = cemp->b_rptr + ceclen; 11017c478bd9Sstevel@tonic-gate 1102df19b344Svi117747 if (sctp->sctp_unsent > 0) { 11037c478bd9Sstevel@tonic-gate sctp_msg_hdr_t *smh; 11047c478bd9Sstevel@tonic-gate mblk_t *prev = NULL; 11057c478bd9Sstevel@tonic-gate uint32_t unsent = 0; 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_unsent; 11087c478bd9Sstevel@tonic-gate do { 11097c478bd9Sstevel@tonic-gate smh = (sctp_msg_hdr_t *)mp->b_rptr; 11107c478bd9Sstevel@tonic-gate if (smh->smh_sid >= sctp->sctp_num_ostr) { 11117c478bd9Sstevel@tonic-gate unsent += smh->smh_msglen; 11127c478bd9Sstevel@tonic-gate if (prev != NULL) 11137c478bd9Sstevel@tonic-gate prev->b_next = mp->b_next; 11147c478bd9Sstevel@tonic-gate else 11157c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent = mp->b_next; 11167c478bd9Sstevel@tonic-gate mp->b_next = NULL; 11177c478bd9Sstevel@tonic-gate sctp_sendfail_event(sctp, mp, SCTP_ERR_BAD_SID, 11187c478bd9Sstevel@tonic-gate B_FALSE); 11197c478bd9Sstevel@tonic-gate if (prev != NULL) 11207c478bd9Sstevel@tonic-gate mp = prev->b_next; 11217c478bd9Sstevel@tonic-gate else 11227c478bd9Sstevel@tonic-gate mp = sctp->sctp_xmit_unsent; 11237c478bd9Sstevel@tonic-gate } else { 11247c478bd9Sstevel@tonic-gate prev = mp; 11257c478bd9Sstevel@tonic-gate mp = mp->b_next; 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate } while (mp != NULL); 11287c478bd9Sstevel@tonic-gate if (unsent > 0) { 11297c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_unsent >= unsent); 11307c478bd9Sstevel@tonic-gate sctp->sctp_unsent -= unsent; 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * Update ULP the amount of queued data, which is 11337c478bd9Sstevel@tonic-gate * sent-unack'ed + unsent. 11347c478bd9Sstevel@tonic-gate * This is not necessary, but doesn't harm, we 11357c478bd9Sstevel@tonic-gate * just use unsent instead of sent-unack'ed + 11367c478bd9Sstevel@tonic-gate * unsent, since there won't be any sent-unack'ed 11377c478bd9Sstevel@tonic-gate * here. 11387c478bd9Sstevel@tonic-gate */ 11390f1702c5SYu Xiangning if (!SCTP_IS_DETACHED(sctp)) 11400f1702c5SYu Xiangning SCTP_TXQ_UPDATE(sctp); 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate if (sctp->sctp_xmit_unsent == NULL) 11437c478bd9Sstevel@tonic-gate sctp->sctp_xmit_unsent_tail = NULL; 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate ceclen += pad; 11467c478bd9Sstevel@tonic-gate cansend = MIN(sctp->sctp_unsent, sctp->sctp_frwnd); 11477c478bd9Sstevel@tonic-gate meta = sctp_get_msg_to_send(sctp, &mp, NULL, &error, ceclen, 11487c478bd9Sstevel@tonic-gate cansend, NULL); 11497c478bd9Sstevel@tonic-gate /* 11507c478bd9Sstevel@tonic-gate * The error cannot be anything else since we could have an non-zero 11517c478bd9Sstevel@tonic-gate * error only if sctp_get_msg_to_send() tries to send a Forward 11527c478bd9Sstevel@tonic-gate * TSN which will not happen here. 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate ASSERT(error == 0); 11557c478bd9Sstevel@tonic-gate if (meta == NULL) 11567c478bd9Sstevel@tonic-gate goto sendcookie; 11577c478bd9Sstevel@tonic-gate sctp->sctp_xmit_tail = meta; 11587c478bd9Sstevel@tonic-gate sdc = (sctp_data_hdr_t *)mp->b_rptr; 11597c478bd9Sstevel@tonic-gate seglen = ntohs(sdc->sdh_len); 1160*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if ((ceclen + seglen) > fp->sf_pmss || 11617c478bd9Sstevel@tonic-gate (seglen - sizeof (*sdc)) > cansend) { 11627c478bd9Sstevel@tonic-gate goto sendcookie; 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate /* OK, if this fails */ 11657c478bd9Sstevel@tonic-gate cemp->b_cont = dupmsg(mp); 11667c478bd9Sstevel@tonic-gate sendcookie: 1167df19b344Svi117747 head = sctp_add_proto_hdr(sctp, fp, cemp, 0, NULL); 1168df19b344Svi117747 if (head == NULL) { 1169df19b344Svi117747 freemsg(cemp); 1170*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 1171df19b344Svi117747 if (errmp != NULL) 1172df19b344Svi117747 freeb(errmp); 1173f4b3ec61Sdh155122 SCTP_KSTAT(sctps, sctp_send_cookie_failed); 1174df19b344Svi117747 return; 1175df19b344Svi117747 } 11767c478bd9Sstevel@tonic-gate /* 11777c478bd9Sstevel@tonic-gate * Even if cookie-echo exceeds MTU for one of the hops, it'll 11787c478bd9Sstevel@tonic-gate * have a chance of getting there. 11797c478bd9Sstevel@tonic-gate */ 1180*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (fp->sf_isv4) { 11817c478bd9Sstevel@tonic-gate ipha_t *iph = (ipha_t *)head->b_rptr; 11827c478bd9Sstevel@tonic-gate iph->ipha_fragment_offset_and_flags = 0; 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks); 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate sctp->sctp_cookie_mp = dupmsg(head); 11877c478bd9Sstevel@tonic-gate /* Don't bundle, we will just resend init if this cookie is lost. */ 11887c478bd9Sstevel@tonic-gate if (sctp->sctp_cookie_mp == NULL) { 11897c478bd9Sstevel@tonic-gate if (cemp->b_cont != NULL) { 11907c478bd9Sstevel@tonic-gate freemsg(cemp->b_cont); 11917c478bd9Sstevel@tonic-gate cemp->b_cont = NULL; 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate } else if (cemp->b_cont != NULL) { 11947c478bd9Sstevel@tonic-gate ASSERT(mp != NULL && mp == meta->b_cont); 11957c478bd9Sstevel@tonic-gate SCTP_CHUNK_CLEAR_FLAGS(cemp->b_cont); 11967c478bd9Sstevel@tonic-gate cemp->b_wptr += pad; 11977c478bd9Sstevel@tonic-gate seglen -= sizeof (*sdc); 11987c478bd9Sstevel@tonic-gate SCTP_CHUNK_SENT(sctp, mp, sdc, fp, seglen, meta); 11997c478bd9Sstevel@tonic-gate } 120077ebe684SGeorge Shepherd if (errmp != NULL) { 120177ebe684SGeorge Shepherd if (cemp->b_cont == NULL) 120277ebe684SGeorge Shepherd cemp->b_wptr += pad; 12037c478bd9Sstevel@tonic-gate linkb(head, errmp); 120477ebe684SGeorge Shepherd } 12057c478bd9Sstevel@tonic-gate sctp->sctp_state = SCTPS_COOKIE_ECHOED; 1206*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto); 12077c478bd9Sstevel@tonic-gate 1208*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India sctp_set_iplen(sctp, head, fp->sf_ixa); 1209*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India (void) conn_ip_output(head, fp->sf_ixa); 1210bd670b35SErik Nordmark BUMP_LOCAL(sctp->sctp_opkts); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate int 12147c478bd9Sstevel@tonic-gate sctp_process_cookie(sctp_t *sctp, sctp_chunk_hdr_t *ch, mblk_t *cmp, 1215558fbd03Skcpoon sctp_init_chunk_t **iackpp, sctp_hdr_t *insctph, int *recv_adaptation, 1216bd670b35SErik Nordmark in6_addr_t *peer_addr, ip_recv_attr_t *ira) 12177c478bd9Sstevel@tonic-gate { 12187c478bd9Sstevel@tonic-gate int32_t clen; 12197c478bd9Sstevel@tonic-gate size_t initplen; 12207c478bd9Sstevel@tonic-gate uchar_t *p; 12217c478bd9Sstevel@tonic-gate uchar_t *given_hash; 12227c478bd9Sstevel@tonic-gate uchar_t needed_hash[16]; 12237c478bd9Sstevel@tonic-gate int64_t ts; 12247c478bd9Sstevel@tonic-gate int64_t diff; 12257c478bd9Sstevel@tonic-gate uint32_t *lt; 12267c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 12277c478bd9Sstevel@tonic-gate sctp_chunk_hdr_t *initch; 12287c478bd9Sstevel@tonic-gate sctp_init_chunk_t *init; 12297c478bd9Sstevel@tonic-gate uint32_t *lttag; 12307c478bd9Sstevel@tonic-gate uint32_t *fttag; 12317c478bd9Sstevel@tonic-gate uint32_t ports; 1232f4b3ec61Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps; 1233bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_ibchunks); 12367c478bd9Sstevel@tonic-gate /* Verify the ICV */ 12377c478bd9Sstevel@tonic-gate clen = ntohs(ch->sch_len) - sizeof (*ch) - 16; 12387c478bd9Sstevel@tonic-gate if (clen < 0) { 12397c478bd9Sstevel@tonic-gate dprint(1, ("invalid cookie chunk length %d\n", 12407c478bd9Sstevel@tonic-gate ntohs(ch->sch_len))); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate return (-1); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate p = (uchar_t *)(ch + 1); 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate hmac_md5(p, clen, (uchar_t *)sctp->sctp_secret, SCTP_SECRET_LEN, 12477c478bd9Sstevel@tonic-gate needed_hash); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate /* The given hash follows the cookie data */ 12507c478bd9Sstevel@tonic-gate given_hash = p + clen; 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate if (bcmp(given_hash, needed_hash, 16) != 0) { 12537c478bd9Sstevel@tonic-gate /* The secret may have changed; try the old secret */ 12547c478bd9Sstevel@tonic-gate hmac_md5(p, clen, (uchar_t *)sctp->sctp_old_secret, 12557c478bd9Sstevel@tonic-gate SCTP_SECRET_LEN, needed_hash); 12567c478bd9Sstevel@tonic-gate if (bcmp(given_hash, needed_hash, 16) != 0) { 12577c478bd9Sstevel@tonic-gate return (-1); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /* Timestamp is int64_t, and we only guarantee 32-bit alignment */ 12627c478bd9Sstevel@tonic-gate bcopy(p, &ts, sizeof (ts)); 126312f47623Skcpoon /* Cookie life time, uint32_t */ 12647c478bd9Sstevel@tonic-gate lt = (uint32_t *)(p + sizeof (ts)); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * To quote PRC, "this is our baby", so let's continue. 12687c478bd9Sstevel@tonic-gate * We need to pull out the encapsulated INIT ACK and 12697c478bd9Sstevel@tonic-gate * INIT chunks. Note that we don't process these until 12707c478bd9Sstevel@tonic-gate * we have verified the timestamp, but we need them before 12717c478bd9Sstevel@tonic-gate * processing the timestamp since if the time check fails, 12727c478bd9Sstevel@tonic-gate * we need to get the verification tag from the INIT in order 12737c478bd9Sstevel@tonic-gate * to send a stale cookie error. 12747c478bd9Sstevel@tonic-gate */ 12757c478bd9Sstevel@tonic-gate lttag = (uint32_t *)(lt + 1); 12767c478bd9Sstevel@tonic-gate fttag = lttag + 1; 12777c478bd9Sstevel@tonic-gate if (peer_addr != NULL) 12787c478bd9Sstevel@tonic-gate bcopy(fttag + 1, peer_addr, sizeof (in6_addr_t)); 12797c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)((char *)(fttag + 1) + sizeof (in6_addr_t)); 12807c478bd9Sstevel@tonic-gate initch = (sctp_chunk_hdr_t *)(iack + 1); 12817c478bd9Sstevel@tonic-gate init = (sctp_init_chunk_t *)(initch + 1); 12827c478bd9Sstevel@tonic-gate initplen = ntohs(initch->sch_len) - (sizeof (*init) + sizeof (*initch)); 12837c478bd9Sstevel@tonic-gate *iackpp = iack; 1284558fbd03Skcpoon *recv_adaptation = 0; 12857c478bd9Sstevel@tonic-gate 128612f47623Skcpoon /* 128712f47623Skcpoon * Check the staleness of the Cookie, specified in 3.3.10.3 of 128812f47623Skcpoon * RFC 2960. 128912f47623Skcpoon * 129012f47623Skcpoon * The mesaure of staleness is the difference, in microseconds, 129112f47623Skcpoon * between the current time and the time the State Cookie expires. 129212f47623Skcpoon * So it is lbolt64 - (ts + *lt). If it is positive, it means 129312f47623Skcpoon * that the Cookie has expired. 129412f47623Skcpoon */ 12955dd46ab5SKacheong Poon diff = LBOLT_FASTPATH64 - (ts + *lt); 129612f47623Skcpoon if (diff > 0 && (init->sic_inittag != sctp->sctp_fvtag || 12977c478bd9Sstevel@tonic-gate iack->sic_inittag != sctp->sctp_lvtag)) { 12987c478bd9Sstevel@tonic-gate uint32_t staleness; 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate staleness = TICK_TO_USEC(diff); 13017c478bd9Sstevel@tonic-gate staleness = htonl(staleness); 13027c478bd9Sstevel@tonic-gate sctp_send_abort(sctp, init->sic_inittag, SCTP_ERR_STALE_COOKIE, 1303bd670b35SErik Nordmark (char *)&staleness, sizeof (staleness), cmp, 1, B_FALSE, 1304bd670b35SErik Nordmark ira); 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate dprint(1, ("stale cookie %d\n", staleness)); 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate return (-1); 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate /* Check for attack by adding addresses to a restart */ 13127c478bd9Sstevel@tonic-gate bcopy(insctph, &ports, sizeof (ports)); 1313f4b3ec61Sdh155122 if (sctp_secure_restart_check(cmp, initch, ports, KM_NOSLEEP, 1314bd670b35SErik Nordmark sctps, ira) != 1) { 13157c478bd9Sstevel@tonic-gate return (-1); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate /* Look for adaptation code if there any parms in the INIT chunk */ 13197c478bd9Sstevel@tonic-gate if ((initplen >= sizeof (sctp_parm_hdr_t)) && 13207c478bd9Sstevel@tonic-gate (sctp_find_al_ind((sctp_parm_hdr_t *)(init + 1), initplen, 1321558fbd03Skcpoon &sctp->sctp_rx_adaptation_code) == 0)) { 1322558fbd03Skcpoon *recv_adaptation = 1; 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* Examine tie-tags */ 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_COOKIE_WAIT) { 13287c478bd9Sstevel@tonic-gate if (sctp->sctp_state == SCTPS_ESTABLISHED && 13297c478bd9Sstevel@tonic-gate init->sic_inittag == sctp->sctp_fvtag && 13307c478bd9Sstevel@tonic-gate iack->sic_inittag == sctp->sctp_lvtag && 13317c478bd9Sstevel@tonic-gate *fttag == 0 && *lttag == 0) { 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate dprint(1, ("duplicate cookie from %x:%x:%x:%x (%d)\n", 1334*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_PRINTADDR(sctp->sctp_current->sf_faddr), 1335bd670b35SErik Nordmark (int)(connp->conn_fport))); 13367c478bd9Sstevel@tonic-gate return (-1); 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate if (init->sic_inittag != sctp->sctp_fvtag && 13407c478bd9Sstevel@tonic-gate iack->sic_inittag != sctp->sctp_lvtag && 13417c478bd9Sstevel@tonic-gate *fttag == sctp->sctp_fvtag && 13427c478bd9Sstevel@tonic-gate *lttag == sctp->sctp_lvtag) { 13437c478bd9Sstevel@tonic-gate int i; 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate /* Section 5.2.4 case A: restart */ 13467c478bd9Sstevel@tonic-gate sctp->sctp_fvtag = init->sic_inittag; 13477c478bd9Sstevel@tonic-gate sctp->sctp_lvtag = iack->sic_inittag; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate sctp->sctp_sctph->sh_verf = init->sic_inittag; 13507c478bd9Sstevel@tonic-gate sctp->sctp_sctph6->sh_verf = init->sic_inittag; 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate sctp->sctp_ftsn = ntohl(init->sic_inittsn); 13537c478bd9Sstevel@tonic-gate sctp->sctp_lastacked = sctp->sctp_ftsn - 1; 13547c478bd9Sstevel@tonic-gate sctp->sctp_frwnd = ntohl(init->sic_a_rwnd); 13557c478bd9Sstevel@tonic-gate sctp->sctp_fcsn = sctp->sctp_lastacked; 13567c478bd9Sstevel@tonic-gate 13575dd46ab5SKacheong Poon if (sctp->sctp_state < SCTPS_ESTABLISHED) 13585dd46ab5SKacheong Poon SCTP_ASSOC_EST(sctps, sctp); 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate dprint(1, ("sctp peer %x:%x:%x:%x (%d) restarted\n", 1361*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_PRINTADDR(sctp->sctp_current->sf_faddr), 1362bd670b35SErik Nordmark (int)(connp->conn_fport))); 13637c478bd9Sstevel@tonic-gate /* reset parameters */ 13647c478bd9Sstevel@tonic-gate sctp_congest_reset(sctp); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* reset stream bookkeeping */ 13677c478bd9Sstevel@tonic-gate sctp_instream_cleanup(sctp, B_FALSE); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate sctp->sctp_istr_nmsgs = 0; 13707c478bd9Sstevel@tonic-gate sctp->sctp_rxqueued = 0; 13717c478bd9Sstevel@tonic-gate for (i = 0; i < sctp->sctp_num_ostr; i++) { 13727c478bd9Sstevel@tonic-gate sctp->sctp_ostrcntrs[i] = 0; 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate /* XXX flush xmit_list? */ 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate return (0); 13777c478bd9Sstevel@tonic-gate } else if (init->sic_inittag != sctp->sctp_fvtag && 13787c478bd9Sstevel@tonic-gate iack->sic_inittag == sctp->sctp_lvtag) { 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* Section 5.2.4 case B: INIT collision */ 13817c478bd9Sstevel@tonic-gate if (sctp->sctp_state < SCTPS_ESTABLISHED) { 13827c478bd9Sstevel@tonic-gate if (!sctp_initialize_params(sctp, init, iack)) 13837c478bd9Sstevel@tonic-gate return (-1); /* Drop? */ 13845dd46ab5SKacheong Poon SCTP_ASSOC_EST(sctps, sctp); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate dprint(1, ("init collision with %x:%x:%x:%x (%d)\n", 1388*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_PRINTADDR(sctp->sctp_current->sf_faddr), 1389bd670b35SErik Nordmark (int)(connp->conn_fport))); 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate return (0); 13927c478bd9Sstevel@tonic-gate } else if (iack->sic_inittag != sctp->sctp_lvtag && 13937c478bd9Sstevel@tonic-gate init->sic_inittag == sctp->sctp_fvtag && 13947c478bd9Sstevel@tonic-gate *fttag == 0 && *lttag == 0) { 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* Section 5.2.4 case C: late COOKIE */ 13977c478bd9Sstevel@tonic-gate dprint(1, ("late cookie from %x:%x:%x:%x (%d)\n", 1398*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_PRINTADDR(sctp->sctp_current->sf_faddr), 1399bd670b35SErik Nordmark (int)(connp->conn_fport))); 14007c478bd9Sstevel@tonic-gate return (-1); 14017c478bd9Sstevel@tonic-gate } else if (init->sic_inittag == sctp->sctp_fvtag && 14027c478bd9Sstevel@tonic-gate iack->sic_inittag == sctp->sctp_lvtag) { 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * Section 5.2.4 case D: COOKIE ECHO retransmit 14067c478bd9Sstevel@tonic-gate * Don't check cookie lifetime 14077c478bd9Sstevel@tonic-gate */ 14087c478bd9Sstevel@tonic-gate dprint(1, ("cookie tags match from %x:%x:%x:%x (%d)\n", 1409*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India SCTP_PRINTADDR(sctp->sctp_current->sf_faddr), 1410bd670b35SErik Nordmark (int)(connp->conn_fport))); 14117c478bd9Sstevel@tonic-gate if (sctp->sctp_state < SCTPS_ESTABLISHED) { 14127c478bd9Sstevel@tonic-gate if (!sctp_initialize_params(sctp, init, iack)) 14137c478bd9Sstevel@tonic-gate return (-1); /* Drop? */ 14145dd46ab5SKacheong Poon SCTP_ASSOC_EST(sctps, sctp); 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate return (0); 14177c478bd9Sstevel@tonic-gate } else { 14187c478bd9Sstevel@tonic-gate /* unrecognized case -- silently drop it */ 14197c478bd9Sstevel@tonic-gate return (-1); 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate return (0); 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * Similar to ip_fanout_sctp, except that the src addr(s) are drawn 14287c478bd9Sstevel@tonic-gate * from address parameters in an INIT ACK's address list. This 14297c478bd9Sstevel@tonic-gate * function is used when an INIT ACK is received but IP's fanout 14307c478bd9Sstevel@tonic-gate * function could not find a sctp via the normal lookup routine. 14317c478bd9Sstevel@tonic-gate * This can happen when a host sends an INIT ACK from a different 14327c478bd9Sstevel@tonic-gate * address than the INIT was sent to. 14337c478bd9Sstevel@tonic-gate * 14347c478bd9Sstevel@tonic-gate * Returns the sctp_t if found, or NULL if not found. 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate sctp_t * 14377c478bd9Sstevel@tonic-gate sctp_addrlist2sctp(mblk_t *mp, sctp_hdr_t *sctph, sctp_chunk_hdr_t *ich, 1438e35d2278Svi117747 zoneid_t zoneid, sctp_stack_t *sctps) 14397c478bd9Sstevel@tonic-gate { 14407c478bd9Sstevel@tonic-gate int isv4; 14417c478bd9Sstevel@tonic-gate ipha_t *iph; 14427c478bd9Sstevel@tonic-gate ip6_t *ip6h; 14437c478bd9Sstevel@tonic-gate in6_addr_t dst; 1444a5407c02SAnil udupa in6_addr_t src, *srcp = &src; 14457c478bd9Sstevel@tonic-gate sctp_parm_hdr_t *ph; 14467c478bd9Sstevel@tonic-gate ssize_t remaining; 14477c478bd9Sstevel@tonic-gate sctp_init_chunk_t *iack; 14487c478bd9Sstevel@tonic-gate uint32_t ports; 14497c478bd9Sstevel@tonic-gate sctp_t *sctp = NULL; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate ASSERT(ich->sch_id == CHUNK_INIT_ACK); 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate isv4 = (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION); 14547c478bd9Sstevel@tonic-gate if (isv4) { 14557c478bd9Sstevel@tonic-gate iph = (ipha_t *)mp->b_rptr; 14567c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(iph->ipha_dst, &dst); 14577c478bd9Sstevel@tonic-gate } else { 14587c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 14597c478bd9Sstevel@tonic-gate dst = ip6h->ip6_dst; 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate ports = *(uint32_t *)sctph; 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate dprint(1, ("sctp_addrlist2sctp: ports=%u, dst = %x:%x:%x:%x\n", 14657c478bd9Sstevel@tonic-gate ports, SCTP_PRINTADDR(dst))); 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate /* pull out any address parameters */ 14687c478bd9Sstevel@tonic-gate remaining = ntohs(ich->sch_len) - sizeof (*ich) - sizeof (*iack); 14697c478bd9Sstevel@tonic-gate if (remaining < sizeof (*ph)) { 14707c478bd9Sstevel@tonic-gate return (NULL); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate iack = (sctp_init_chunk_t *)(ich + 1); 14747c478bd9Sstevel@tonic-gate ph = (sctp_parm_hdr_t *)(iack + 1); 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate while (ph != NULL) { 14777c478bd9Sstevel@tonic-gate /* 1478a5407c02SAnil udupa * params have been verified in sctp_check_input(), 1479a5407c02SAnil udupa * so no need to do it again here. 1480bd670b35SErik Nordmark * 1481bd670b35SErik Nordmark * For labeled systems, there's no need to check the 1482bd670b35SErik Nordmark * label here. It's known to be good as we checked 1483bd670b35SErik Nordmark * before allowing the connection to become bound. 1484a5407c02SAnil udupa * 1485a5407c02SAnil udupa * According to RFC4960 : 1486a5407c02SAnil udupa * All integer fields in an SCTP packet MUST be transmitted 1487a5407c02SAnil udupa * in network byte order, unless otherwise stated. 1488a5407c02SAnil udupa * Therefore convert the param type to network byte order. 14897c478bd9Sstevel@tonic-gate */ 1490a5407c02SAnil udupa if (ph->sph_type == htons(PARM_ADDR4)) { 14917c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED((struct in_addr *)(ph + 1), 1492a5407c02SAnil udupa srcp); 14937c478bd9Sstevel@tonic-gate 1494a5407c02SAnil udupa sctp = sctp_conn_match(&srcp, 1, &dst, ports, zoneid, 1495bd670b35SErik Nordmark 0, sctps); 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate dprint(1, 14987c478bd9Sstevel@tonic-gate ("sctp_addrlist2sctp: src=%x:%x:%x:%x, sctp=%p\n", 149945916cd2Sjpk SCTP_PRINTADDR(src), (void *)sctp)); 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate if (sctp != NULL) { 15037c478bd9Sstevel@tonic-gate return (sctp); 15047c478bd9Sstevel@tonic-gate } 1505a5407c02SAnil udupa } else if (ph->sph_type == htons(PARM_ADDR6)) { 1506a5407c02SAnil udupa srcp = (in6_addr_t *)(ph + 1); 1507a5407c02SAnil udupa sctp = sctp_conn_match(&srcp, 1, &dst, ports, zoneid, 1508bd670b35SErik Nordmark 0, sctps); 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate dprint(1, 15117c478bd9Sstevel@tonic-gate ("sctp_addrlist2sctp: src=%x:%x:%x:%x, sctp=%p\n", 151245916cd2Sjpk SCTP_PRINTADDR(src), (void *)sctp)); 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate if (sctp != NULL) { 15157c478bd9Sstevel@tonic-gate return (sctp); 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate ph = sctp_next_parm(ph, &remaining); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate return (NULL); 15237c478bd9Sstevel@tonic-gate } 1524