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 */ 217c478bd9Sstevel@tonic-gate 227c478bd9Sstevel@tonic-gate /* 236be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 26*de710d24SJosef 'Jeff' Sipek #include <sys/sysmacros.h> 277c478bd9Sstevel@tonic-gate #include <sys/socket.h> 287c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 3045916cd2Sjpk #include <sys/tsol/tndb.h> 3145916cd2Sjpk #include <sys/tsol/tnet.h> 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <netinet/in.h> 347c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <inet/common.h> 377c478bd9Sstevel@tonic-gate #include <inet/ip.h> 387c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 397c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 407c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h> 417c478bd9Sstevel@tonic-gate #include <inet/ipp_common.h> 427c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include "sctp_impl.h" 457c478bd9Sstevel@tonic-gate #include "sctp_addr.h" 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* Default association hash size. The size must be a power of 2. */ 487c478bd9Sstevel@tonic-gate #define SCTP_CONN_HASH_SIZE 8192 497c478bd9Sstevel@tonic-gate 50f4b3ec61Sdh155122 uint_t sctp_conn_hash_size = SCTP_CONN_HASH_SIZE; /* /etc/system */ 517c478bd9Sstevel@tonic-gate 521d8c4025Svi117747 /* 531d8c4025Svi117747 * Cluster networking hook for traversing current assoc list. 541d8c4025Svi117747 * This routine is used to extract the current list of live associations 551d8c4025Svi117747 * which must continue to to be dispatched to this node. 561d8c4025Svi117747 */ 571d8c4025Svi117747 int cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), void *, 581d8c4025Svi117747 boolean_t); 59f4b3ec61Sdh155122 static int cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, 60f4b3ec61Sdh155122 void *), void *arg, boolean_t cansleep, sctp_stack_t *sctps); 611d8c4025Svi117747 627c478bd9Sstevel@tonic-gate void 63f4b3ec61Sdh155122 sctp_hash_init(sctp_stack_t *sctps) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate int i; 667c478bd9Sstevel@tonic-gate 67f4b3ec61Sdh155122 /* Start with /etc/system value */ 68f4b3ec61Sdh155122 sctps->sctps_conn_hash_size = sctp_conn_hash_size; 69f4b3ec61Sdh155122 70*de710d24SJosef 'Jeff' Sipek if (!ISP2(sctps->sctps_conn_hash_size)) { 717c478bd9Sstevel@tonic-gate /* Not a power of two. Round up to nearest power of two */ 727c478bd9Sstevel@tonic-gate for (i = 0; i < 31; i++) { 73f4b3ec61Sdh155122 if (sctps->sctps_conn_hash_size < (1 << i)) 747c478bd9Sstevel@tonic-gate break; 757c478bd9Sstevel@tonic-gate } 76f4b3ec61Sdh155122 sctps->sctps_conn_hash_size = 1 << i; 777c478bd9Sstevel@tonic-gate } 78f4b3ec61Sdh155122 if (sctps->sctps_conn_hash_size < SCTP_CONN_HASH_SIZE) { 79f4b3ec61Sdh155122 sctps->sctps_conn_hash_size = SCTP_CONN_HASH_SIZE; 807c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "using sctp_conn_hash_size = %u\n", 81f4b3ec61Sdh155122 sctps->sctps_conn_hash_size); 827c478bd9Sstevel@tonic-gate } 83f4b3ec61Sdh155122 sctps->sctps_conn_fanout = 84f4b3ec61Sdh155122 (sctp_tf_t *)kmem_zalloc(sctps->sctps_conn_hash_size * 857c478bd9Sstevel@tonic-gate sizeof (sctp_tf_t), KM_SLEEP); 86f4b3ec61Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) { 87f4b3ec61Sdh155122 mutex_init(&sctps->sctps_conn_fanout[i].tf_lock, NULL, 887c478bd9Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 897c478bd9Sstevel@tonic-gate } 90f4b3ec61Sdh155122 sctps->sctps_listen_fanout = kmem_zalloc(SCTP_LISTEN_FANOUT_SIZE * 91f4b3ec61Sdh155122 sizeof (sctp_tf_t), KM_SLEEP); 92f4b3ec61Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) { 93f4b3ec61Sdh155122 mutex_init(&sctps->sctps_listen_fanout[i].tf_lock, NULL, 947c478bd9Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 957c478bd9Sstevel@tonic-gate } 96f4b3ec61Sdh155122 sctps->sctps_bind_fanout = kmem_zalloc(SCTP_BIND_FANOUT_SIZE * 97f4b3ec61Sdh155122 sizeof (sctp_tf_t), KM_SLEEP); 98f4b3ec61Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) { 99f4b3ec61Sdh155122 mutex_init(&sctps->sctps_bind_fanout[i].tf_lock, NULL, 1007c478bd9Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate void 105f4b3ec61Sdh155122 sctp_hash_destroy(sctp_stack_t *sctps) 1067c478bd9Sstevel@tonic-gate { 1077c478bd9Sstevel@tonic-gate int i; 1087c478bd9Sstevel@tonic-gate 109f4b3ec61Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) { 110f4b3ec61Sdh155122 mutex_destroy(&sctps->sctps_conn_fanout[i].tf_lock); 1117c478bd9Sstevel@tonic-gate } 112f4b3ec61Sdh155122 kmem_free(sctps->sctps_conn_fanout, sctps->sctps_conn_hash_size * 113f4b3ec61Sdh155122 sizeof (sctp_tf_t)); 114f4b3ec61Sdh155122 sctps->sctps_conn_fanout = NULL; 115f4b3ec61Sdh155122 116f4b3ec61Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) { 117f4b3ec61Sdh155122 mutex_destroy(&sctps->sctps_listen_fanout[i].tf_lock); 1187c478bd9Sstevel@tonic-gate } 119f4b3ec61Sdh155122 kmem_free(sctps->sctps_listen_fanout, SCTP_LISTEN_FANOUT_SIZE * 120f4b3ec61Sdh155122 sizeof (sctp_tf_t)); 121f4b3ec61Sdh155122 sctps->sctps_listen_fanout = NULL; 122f4b3ec61Sdh155122 123f4b3ec61Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) { 124f4b3ec61Sdh155122 mutex_destroy(&sctps->sctps_bind_fanout[i].tf_lock); 1257c478bd9Sstevel@tonic-gate } 126f4b3ec61Sdh155122 kmem_free(sctps->sctps_bind_fanout, SCTP_BIND_FANOUT_SIZE * 127f4b3ec61Sdh155122 sizeof (sctp_tf_t)); 128f4b3ec61Sdh155122 sctps->sctps_bind_fanout = NULL; 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 131769b977dSvi117747 /* 1321d8c4025Svi117747 * Exported routine for extracting active SCTP associations. 1331d8c4025Svi117747 * Like TCP, we terminate the walk if the callback returns non-zero. 134f4b3ec61Sdh155122 * 135f4b3ec61Sdh155122 * Need to walk all sctp_stack_t instances since this clustering 136f4b3ec61Sdh155122 * interface is assumed global for all instances 1371d8c4025Svi117747 */ 1381d8c4025Svi117747 int 139f4b3ec61Sdh155122 cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), 140f4b3ec61Sdh155122 void *arg, boolean_t cansleep) 141f4b3ec61Sdh155122 { 142f4b3ec61Sdh155122 netstack_handle_t nh; 143f4b3ec61Sdh155122 netstack_t *ns; 144f4b3ec61Sdh155122 int ret = 0; 145f4b3ec61Sdh155122 146f4b3ec61Sdh155122 netstack_next_init(&nh); 147f4b3ec61Sdh155122 while ((ns = netstack_next(&nh)) != NULL) { 148f4b3ec61Sdh155122 ret = cl_sctp_walk_list_stack(cl_callback, arg, cansleep, 149f4b3ec61Sdh155122 ns->netstack_sctp); 150f4b3ec61Sdh155122 netstack_rele(ns); 151f4b3ec61Sdh155122 } 152f4b3ec61Sdh155122 netstack_next_fini(&nh); 153f4b3ec61Sdh155122 return (ret); 154f4b3ec61Sdh155122 } 155f4b3ec61Sdh155122 156f4b3ec61Sdh155122 static int 157f4b3ec61Sdh155122 cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, void *), 158f4b3ec61Sdh155122 void *arg, boolean_t cansleep, sctp_stack_t *sctps) 1591d8c4025Svi117747 { 1601d8c4025Svi117747 sctp_t *sctp; 1611d8c4025Svi117747 sctp_t *sctp_prev; 1621d8c4025Svi117747 cl_sctp_info_t cl_sctpi; 1631d8c4025Svi117747 uchar_t *slist; 1641d8c4025Svi117747 uchar_t *flist; 1651d8c4025Svi117747 1661d8c4025Svi117747 sctp_prev = NULL; 167f4b3ec61Sdh155122 mutex_enter(&sctps->sctps_g_lock); 168bd670b35SErik Nordmark sctp = list_head(&sctps->sctps_g_list); 1691d8c4025Svi117747 while (sctp != NULL) { 1701d8c4025Svi117747 size_t ssize; 1711d8c4025Svi117747 size_t fsize; 1721d8c4025Svi117747 1731d8c4025Svi117747 mutex_enter(&sctp->sctp_reflock); 1741d8c4025Svi117747 if (sctp->sctp_condemned || sctp->sctp_state <= SCTPS_LISTEN) { 1751d8c4025Svi117747 mutex_exit(&sctp->sctp_reflock); 176f4b3ec61Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 1771d8c4025Svi117747 continue; 1781d8c4025Svi117747 } 1791d8c4025Svi117747 sctp->sctp_refcnt++; 1801d8c4025Svi117747 mutex_exit(&sctp->sctp_reflock); 181f4b3ec61Sdh155122 mutex_exit(&sctps->sctps_g_lock); 1821d8c4025Svi117747 if (sctp_prev != NULL) 1831d8c4025Svi117747 SCTP_REFRELE(sctp_prev); 1841d8c4025Svi117747 RUN_SCTP(sctp); 1851d8c4025Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 1861d8c4025Svi117747 fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs; 1871d8c4025Svi117747 1881d8c4025Svi117747 slist = kmem_alloc(ssize, cansleep ? KM_SLEEP : KM_NOSLEEP); 1891d8c4025Svi117747 flist = kmem_alloc(fsize, cansleep ? KM_SLEEP : KM_NOSLEEP); 1901d8c4025Svi117747 if (slist == NULL || flist == NULL) { 1911d8c4025Svi117747 WAKE_SCTP(sctp); 1921d8c4025Svi117747 if (slist != NULL) 1931d8c4025Svi117747 kmem_free(slist, ssize); 1941d8c4025Svi117747 if (flist != NULL) 1951d8c4025Svi117747 kmem_free(flist, fsize); 1961d8c4025Svi117747 SCTP_REFRELE(sctp); 1971d8c4025Svi117747 return (1); 1981d8c4025Svi117747 } 1991d8c4025Svi117747 cl_sctpi.cl_sctpi_version = CL_SCTPI_V1; 2001d8c4025Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 2011d8c4025Svi117747 sctp_get_faddr_list(sctp, flist, fsize); 2021d8c4025Svi117747 cl_sctpi.cl_sctpi_nladdr = sctp->sctp_nsaddrs; 2031d8c4025Svi117747 cl_sctpi.cl_sctpi_nfaddr = sctp->sctp_nfaddrs; 204bd670b35SErik Nordmark cl_sctpi.cl_sctpi_family = sctp->sctp_connp->conn_family; 205bd670b35SErik Nordmark if (cl_sctpi.cl_sctpi_family == AF_INET) 206bd670b35SErik Nordmark cl_sctpi.cl_sctpi_ipversion = IPV4_VERSION; 207bd670b35SErik Nordmark else 208bd670b35SErik Nordmark cl_sctpi.cl_sctpi_ipversion = IPV6_VERSION; 2091d8c4025Svi117747 cl_sctpi.cl_sctpi_state = sctp->sctp_state; 210bd670b35SErik Nordmark cl_sctpi.cl_sctpi_lport = sctp->sctp_connp->conn_lport; 211bd670b35SErik Nordmark cl_sctpi.cl_sctpi_fport = sctp->sctp_connp->conn_fport; 2121d8c4025Svi117747 cl_sctpi.cl_sctpi_handle = (cl_sctp_handle_t)sctp; 2131d8c4025Svi117747 WAKE_SCTP(sctp); 2141d8c4025Svi117747 cl_sctpi.cl_sctpi_laddrp = slist; 2151d8c4025Svi117747 cl_sctpi.cl_sctpi_faddrp = flist; 2161d8c4025Svi117747 if ((*cl_callback)(&cl_sctpi, arg) != 0) { 2171d8c4025Svi117747 kmem_free(slist, ssize); 2181d8c4025Svi117747 kmem_free(flist, fsize); 2191d8c4025Svi117747 SCTP_REFRELE(sctp); 2201d8c4025Svi117747 return (1); 2211d8c4025Svi117747 } 2221d8c4025Svi117747 /* list will be freed by cl_callback */ 2231d8c4025Svi117747 sctp_prev = sctp; 224f4b3ec61Sdh155122 mutex_enter(&sctps->sctps_g_lock); 225f4b3ec61Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp); 2261d8c4025Svi117747 } 227f4b3ec61Sdh155122 mutex_exit(&sctps->sctps_g_lock); 2281d8c4025Svi117747 if (sctp_prev != NULL) 2291d8c4025Svi117747 SCTP_REFRELE(sctp_prev); 2301d8c4025Svi117747 return (0); 2311d8c4025Svi117747 } 2321d8c4025Svi117747 2337c478bd9Sstevel@tonic-gate sctp_t * 234a5407c02SAnil udupa sctp_conn_match(in6_addr_t **faddrpp, uint32_t nfaddr, in6_addr_t *laddr, 235a5407c02SAnil udupa uint32_t ports, zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate sctp_tf_t *tf; 2387c478bd9Sstevel@tonic-gate sctp_t *sctp; 2397c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 240bd670b35SErik Nordmark conn_t *connp; 241a5407c02SAnil udupa in6_addr_t **faddrs, **endaddrs = &faddrpp[nfaddr]; 2427c478bd9Sstevel@tonic-gate 243f4b3ec61Sdh155122 tf = &(sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, ports)]); 2447c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 2457c478bd9Sstevel@tonic-gate 246a5407c02SAnil udupa for (sctp = tf->tf_sctp; sctp != NULL; sctp = 247a5407c02SAnil udupa sctp->sctp_conn_hash_next) { 248bd670b35SErik Nordmark connp = sctp->sctp_connp; 249bd670b35SErik Nordmark if (ports != connp->conn_ports) 2507c478bd9Sstevel@tonic-gate continue; 251bd670b35SErik Nordmark if (!(connp->conn_zoneid == zoneid || 252bd670b35SErik Nordmark connp->conn_allzones || 253bd670b35SErik Nordmark ((connp->conn_mac_mode != CONN_MAC_DEFAULT) && 254bd670b35SErik Nordmark (iraflags & IRAF_TX_MAC_EXEMPTABLE) && 255bd670b35SErik Nordmark (iraflags & IRAF_TX_SHARED_ADDR)))) 256bd670b35SErik Nordmark continue; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* check for faddr match */ 2596be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) { 260a5407c02SAnil udupa for (faddrs = faddrpp; faddrs < endaddrs; faddrs++) { 2616be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (IN6_ARE_ADDR_EQUAL(*faddrs, 2626be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India &fp->sf_faddr)) { 2637c478bd9Sstevel@tonic-gate /* check for laddr match */ 264a5407c02SAnil udupa if (sctp_saddr_lookup(sctp, laddr, 0) 265a5407c02SAnil udupa != NULL) { 2667c478bd9Sstevel@tonic-gate SCTP_REFHOLD(sctp); 267a5407c02SAnil udupa mutex_exit(&tf->tf_lock); 268a5407c02SAnil udupa return (sctp); 2697c478bd9Sstevel@tonic-gate } 270a5407c02SAnil udupa } 271a5407c02SAnil udupa } 272a5407c02SAnil udupa } 273a5407c02SAnil udupa 2747c478bd9Sstevel@tonic-gate /* no match; continue to the next in the chain */ 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 2787c478bd9Sstevel@tonic-gate return (sctp); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate static sctp_t * 282e35d2278Svi117747 listen_match(in6_addr_t *laddr, uint32_t ports, zoneid_t zoneid, 283bd670b35SErik Nordmark iaflags_t iraflags, sctp_stack_t *sctps) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate sctp_t *sctp; 2867c478bd9Sstevel@tonic-gate sctp_tf_t *tf; 2877c478bd9Sstevel@tonic-gate uint16_t lport; 288bd670b35SErik Nordmark conn_t *connp; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate lport = ((uint16_t *)&ports)[1]; 2917c478bd9Sstevel@tonic-gate 292f4b3ec61Sdh155122 tf = &(sctps->sctps_listen_fanout[SCTP_LISTEN_HASH(ntohs(lport))]); 2937c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_listen_hash_next) { 296bd670b35SErik Nordmark connp = sctp->sctp_connp; 297bd670b35SErik Nordmark if (lport != connp->conn_lport) 2987c478bd9Sstevel@tonic-gate continue; 299bd670b35SErik Nordmark 300bd670b35SErik Nordmark if (!(connp->conn_zoneid == zoneid || 301bd670b35SErik Nordmark connp->conn_allzones || 302bd670b35SErik Nordmark ((connp->conn_mac_mode != CONN_MAC_DEFAULT) && 303bd670b35SErik Nordmark (iraflags & IRAF_TX_MAC_EXEMPTABLE) && 304bd670b35SErik Nordmark (iraflags & IRAF_TX_SHARED_ADDR)))) 305bd670b35SErik Nordmark continue; 3067c478bd9Sstevel@tonic-gate 3071d8c4025Svi117747 if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) { 3087c478bd9Sstevel@tonic-gate SCTP_REFHOLD(sctp); 3097c478bd9Sstevel@tonic-gate goto done; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate /* no match; continue to the next in the chain */ 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate done: 3157c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 3167c478bd9Sstevel@tonic-gate return (sctp); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 31945916cd2Sjpk /* called by ipsec_sctp_pol */ 3207c478bd9Sstevel@tonic-gate conn_t * 3217c478bd9Sstevel@tonic-gate sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 322bd670b35SErik Nordmark zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps) 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate sctp_t *sctp; 3257c478bd9Sstevel@tonic-gate 326a5407c02SAnil udupa sctp = sctp_conn_match(&src, 1, dst, ports, zoneid, iraflags, sctps); 327bd670b35SErik Nordmark if (sctp == NULL) { 3287c478bd9Sstevel@tonic-gate /* Not in conn fanout; check listen fanout */ 329bd670b35SErik Nordmark sctp = listen_match(dst, ports, zoneid, iraflags, sctps); 330bd670b35SErik Nordmark if (sctp == NULL) 3317c478bd9Sstevel@tonic-gate return (NULL); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate return (sctp->sctp_connp); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 336bd670b35SErik Nordmark /* 337a5407c02SAnil udupa * This is called from sctp_fanout() with IP header src & dst addresses. 338a5407c02SAnil udupa * First call sctp_conn_match() to get a match by passing in src & dst 339a5407c02SAnil udupa * addresses from IP header. 340a5407c02SAnil udupa * However sctp_conn_match() can return no match under condition such as : 341a5407c02SAnil udupa * A host can send an INIT ACK from a different address than the INIT was sent 342a5407c02SAnil udupa * to (in a multi-homed env). 343a5407c02SAnil udupa * According to RFC4960, a host can send additional addresses in an INIT 344a5407c02SAnil udupa * ACK chunk. 345a5407c02SAnil udupa * Therefore extract all addresses from the INIT ACK chunk, pass to 346a5407c02SAnil udupa * sctp_conn_match() to get a match. 347a5407c02SAnil udupa */ 348a5407c02SAnil udupa static sctp_t * 349a5407c02SAnil udupa sctp_lookup_by_faddrs(mblk_t *mp, sctp_hdr_t *sctph, in6_addr_t *srcp, 350a5407c02SAnil udupa in6_addr_t *dstp, uint32_t ports, zoneid_t zoneid, sctp_stack_t *sctps, 351a5407c02SAnil udupa iaflags_t iraflags) 352a5407c02SAnil udupa { 353a5407c02SAnil udupa sctp_t *sctp; 354a5407c02SAnil udupa sctp_chunk_hdr_t *ich; 355a5407c02SAnil udupa sctp_init_chunk_t *iack; 356a5407c02SAnil udupa sctp_parm_hdr_t *ph; 357a5407c02SAnil udupa ssize_t mlen, remaining; 358a5407c02SAnil udupa uint16_t param_type, addr_len = PARM_ADDR4_LEN; 359a5407c02SAnil udupa in6_addr_t src; 360a5407c02SAnil udupa in6_addr_t **addrbuf = NULL, **faddrpp = NULL; 361a5407c02SAnil udupa boolean_t isv4; 362a5407c02SAnil udupa uint32_t totaddr, nfaddr = 0; 363a5407c02SAnil udupa 364a5407c02SAnil udupa /* 365a5407c02SAnil udupa * If we get a match with the passed-in IP header src & dst addresses, 366a5407c02SAnil udupa * quickly return the matched sctp. 367a5407c02SAnil udupa */ 368a5407c02SAnil udupa if ((sctp = sctp_conn_match(&srcp, 1, dstp, ports, zoneid, iraflags, 369a5407c02SAnil udupa sctps)) != NULL) { 370a5407c02SAnil udupa return (sctp); 371a5407c02SAnil udupa } 372a5407c02SAnil udupa 373a5407c02SAnil udupa /* 374a5407c02SAnil udupa * Currently sctph is set to NULL in icmp error fanout case 375a5407c02SAnil udupa * (ip_fanout_sctp()). 376a5407c02SAnil udupa * The above sctp_conn_match() should handle that, otherwise 377a5407c02SAnil udupa * return no match found. 378a5407c02SAnil udupa */ 379a5407c02SAnil udupa if (sctph == NULL) 380a5407c02SAnil udupa return (NULL); 381a5407c02SAnil udupa 382a5407c02SAnil udupa /* 383a5407c02SAnil udupa * Do a pullup again in case the previous one was partially successful, 384a5407c02SAnil udupa * so try to complete the pullup here and have a single contiguous 385a5407c02SAnil udupa * chunk for processing of entire INIT ACK chunk below. 386a5407c02SAnil udupa */ 387a5407c02SAnil udupa if (mp->b_cont != NULL) { 388a5407c02SAnil udupa if (pullupmsg(mp, -1) == 0) { 389a5407c02SAnil udupa return (NULL); 390a5407c02SAnil udupa } 391a5407c02SAnil udupa } 392a5407c02SAnil udupa 393a5407c02SAnil udupa mlen = mp->b_wptr - (uchar_t *)(sctph + 1); 394a5407c02SAnil udupa if ((ich = sctp_first_chunk((uchar_t *)(sctph + 1), mlen)) == NULL) { 395a5407c02SAnil udupa return (NULL); 396a5407c02SAnil udupa } 397a5407c02SAnil udupa 398a5407c02SAnil udupa if (ich->sch_id == CHUNK_INIT_ACK) { 399a5407c02SAnil udupa remaining = ntohs(ich->sch_len) - sizeof (*ich) - 400a5407c02SAnil udupa sizeof (*iack); 401a5407c02SAnil udupa if (remaining < sizeof (*ph)) { 402a5407c02SAnil udupa return (NULL); 403a5407c02SAnil udupa } 404a5407c02SAnil udupa 405a5407c02SAnil udupa isv4 = (iraflags & IRAF_IS_IPV4) ? B_TRUE : B_FALSE; 406a5407c02SAnil udupa if (!isv4) 407a5407c02SAnil udupa addr_len = PARM_ADDR6_LEN; 408a5407c02SAnil udupa totaddr = remaining/addr_len; 409a5407c02SAnil udupa 410a5407c02SAnil udupa iack = (sctp_init_chunk_t *)(ich + 1); 411a5407c02SAnil udupa ph = (sctp_parm_hdr_t *)(iack + 1); 412a5407c02SAnil udupa 413a5407c02SAnil udupa addrbuf = (in6_addr_t **) 414a5407c02SAnil udupa kmem_zalloc(totaddr * sizeof (in6_addr_t *), KM_NOSLEEP); 415a5407c02SAnil udupa if (addrbuf == NULL) 416a5407c02SAnil udupa return (NULL); 417a5407c02SAnil udupa faddrpp = addrbuf; 418a5407c02SAnil udupa 419a5407c02SAnil udupa while (ph != NULL) { 420a5407c02SAnil udupa /* 421a5407c02SAnil udupa * According to RFC4960 : 422a5407c02SAnil udupa * All integer fields in an SCTP packet MUST be 423a5407c02SAnil udupa * transmitted in network byte order, 424a5407c02SAnil udupa * unless otherwise stated. 425a5407c02SAnil udupa * Therefore convert the param type to host byte order. 426a5407c02SAnil udupa * Also do not add src address present in IP header 427a5407c02SAnil udupa * as it has already been thru sctp_conn_match() above. 428a5407c02SAnil udupa */ 429a5407c02SAnil udupa param_type = ntohs(ph->sph_type); 430a5407c02SAnil udupa switch (param_type) { 431a5407c02SAnil udupa case PARM_ADDR4: 432a5407c02SAnil udupa IN6_INADDR_TO_V4MAPPED((struct in_addr *) 433a5407c02SAnil udupa (ph + 1), &src); 434a5407c02SAnil udupa if (IN6_ARE_ADDR_EQUAL(&src, srcp)) 435a5407c02SAnil udupa break; 436a5407c02SAnil udupa *faddrpp = (in6_addr_t *) 437a5407c02SAnil udupa kmem_zalloc(sizeof (in6_addr_t), 438a5407c02SAnil udupa KM_NOSLEEP); 439a5407c02SAnil udupa if (*faddrpp == NULL) 440a5407c02SAnil udupa break; 441a5407c02SAnil udupa IN6_INADDR_TO_V4MAPPED((struct in_addr *) 442a5407c02SAnil udupa (ph + 1), *faddrpp); 443a5407c02SAnil udupa nfaddr++; 444a5407c02SAnil udupa faddrpp++; 445a5407c02SAnil udupa break; 446a5407c02SAnil udupa case PARM_ADDR6: 447a5407c02SAnil udupa *faddrpp = (in6_addr_t *)(ph + 1); 448a5407c02SAnil udupa if (IN6_ARE_ADDR_EQUAL(*faddrpp, srcp)) 449a5407c02SAnil udupa break; 450a5407c02SAnil udupa nfaddr++; 451a5407c02SAnil udupa faddrpp++; 452a5407c02SAnil udupa break; 453a5407c02SAnil udupa default: 454a5407c02SAnil udupa break; 455a5407c02SAnil udupa } 456a5407c02SAnil udupa ph = sctp_next_parm(ph, &remaining); 457a5407c02SAnil udupa } 458a5407c02SAnil udupa 459a5407c02SAnil udupa ASSERT(nfaddr < totaddr); 460a5407c02SAnil udupa 461a5407c02SAnil udupa if (nfaddr > 0) { 462a5407c02SAnil udupa sctp = sctp_conn_match(addrbuf, nfaddr, dstp, ports, 463a5407c02SAnil udupa zoneid, iraflags, sctps); 464a5407c02SAnil udupa 465a5407c02SAnil udupa if (isv4) { 466a5407c02SAnil udupa for (faddrpp = addrbuf; nfaddr > 0; 467a5407c02SAnil udupa faddrpp++, nfaddr--) { 468a5407c02SAnil udupa if (IN6_IS_ADDR_V4MAPPED(*faddrpp)) { 469a5407c02SAnil udupa kmem_free(*faddrpp, 470a5407c02SAnil udupa sizeof (in6_addr_t)); 471a5407c02SAnil udupa } 472a5407c02SAnil udupa } 473a5407c02SAnil udupa } 474a5407c02SAnil udupa } 475a5407c02SAnil udupa kmem_free(addrbuf, totaddr * sizeof (in6_addr_t *)); 476a5407c02SAnil udupa } 477a5407c02SAnil udupa return (sctp); 478a5407c02SAnil udupa } 479a5407c02SAnil udupa 480a5407c02SAnil udupa /* 481bd670b35SErik Nordmark * Fanout to a sctp instance. 482bd670b35SErik Nordmark */ 48345916cd2Sjpk conn_t * 48445916cd2Sjpk sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports, 485a5407c02SAnil udupa ip_recv_attr_t *ira, mblk_t *mp, sctp_stack_t *sctps, sctp_hdr_t *sctph) 48645916cd2Sjpk { 487bd670b35SErik Nordmark zoneid_t zoneid = ira->ira_zoneid; 488bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 48945916cd2Sjpk sctp_t *sctp; 49045916cd2Sjpk 491a5407c02SAnil udupa sctp = sctp_lookup_by_faddrs(mp, sctph, src, dst, ports, zoneid, 492a5407c02SAnil udupa sctps, iraflags); 493bd670b35SErik Nordmark if (sctp == NULL) { 49445916cd2Sjpk /* Not in conn fanout; check listen fanout */ 495bd670b35SErik Nordmark sctp = listen_match(dst, ports, zoneid, iraflags, sctps); 496bd670b35SErik Nordmark if (sctp == NULL) 49745916cd2Sjpk return (NULL); 498d7ab25acSkp158701 /* 499d7ab25acSkp158701 * On systems running trusted extensions, check if dst 500d7ab25acSkp158701 * should accept the packet. "IPV6_VERSION" indicates 501d7ab25acSkp158701 * that dst is in 16 byte AF_INET6 format. IPv4-mapped 502d7ab25acSkp158701 * IPv6 addresses are supported. 503d7ab25acSkp158701 */ 504bd670b35SErik Nordmark if ((iraflags & IRAF_SYSTEM_LABELED) && 505bd670b35SErik Nordmark !tsol_receive_local(mp, dst, IPV6_VERSION, ira, 506bd670b35SErik Nordmark sctp->sctp_connp)) { 507d7ab25acSkp158701 DTRACE_PROBE3( 508d7ab25acSkp158701 tx__ip__log__info__classify__sctp, 509d7ab25acSkp158701 char *, 510d7ab25acSkp158701 "connp(1) could not receive mp(2)", 511d7ab25acSkp158701 conn_t *, sctp->sctp_connp, mblk_t *, mp); 512d7ab25acSkp158701 SCTP_REFRELE(sctp); 513d7ab25acSkp158701 return (NULL); 514d7ab25acSkp158701 } 51545916cd2Sjpk } 516bd670b35SErik Nordmark /* 517bd670b35SErik Nordmark * For labeled systems, there's no need to check the 518bd670b35SErik Nordmark * label here. It's known to be good as we checked 519bd670b35SErik Nordmark * before allowing the connection to become bound. 520bd670b35SErik Nordmark */ 52145916cd2Sjpk return (sctp->sctp_connp); 52245916cd2Sjpk } 52345916cd2Sjpk 5247c478bd9Sstevel@tonic-gate /* 525bd670b35SErik Nordmark * Fanout for ICMP errors for SCTP 5267c478bd9Sstevel@tonic-gate * The caller puts <fport, lport> in the ports parameter. 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate void 529bd670b35SErik Nordmark ip_fanout_sctp(mblk_t *mp, ipha_t *ipha, ip6_t *ip6h, uint32_t ports, 530bd670b35SErik Nordmark ip_recv_attr_t *ira) 5317c478bd9Sstevel@tonic-gate { 5327c478bd9Sstevel@tonic-gate sctp_t *sctp; 5337c478bd9Sstevel@tonic-gate conn_t *connp; 5347c478bd9Sstevel@tonic-gate in6_addr_t map_src, map_dst; 5357c478bd9Sstevel@tonic-gate in6_addr_t *src, *dst; 536bd670b35SErik Nordmark boolean_t secure; 537bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 538bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 539bd670b35SErik Nordmark netstack_t *ns = ipst->ips_netstack; 540bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 541bd670b35SErik Nordmark sctp_stack_t *sctps = ns->netstack_sctp; 542bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 543bd670b35SErik Nordmark ill_t *rill = ira->ira_rill; 544f4b3ec61Sdh155122 545bd670b35SErik Nordmark ASSERT(iraflags & IRAF_ICMP_ERROR); 5467c478bd9Sstevel@tonic-gate 547bd670b35SErik Nordmark secure = iraflags & IRAF_IPSEC_SECURE; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* Assume IP provides aligned packets - otherwise toss */ 5507c478bd9Sstevel@tonic-gate if (!OK_32PTR(mp->b_rptr)) { 551bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 552bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 553bd670b35SErik Nordmark freemsg(mp); 5547c478bd9Sstevel@tonic-gate return; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 557bd670b35SErik Nordmark if (!(iraflags & IRAF_IS_IPV4)) { 5587c478bd9Sstevel@tonic-gate src = &ip6h->ip6_src; 5597c478bd9Sstevel@tonic-gate dst = &ip6h->ip6_dst; 5607c478bd9Sstevel@tonic-gate } else { 5617c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src); 5627c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst); 5637c478bd9Sstevel@tonic-gate src = &map_src; 5647c478bd9Sstevel@tonic-gate dst = &map_dst; 5657c478bd9Sstevel@tonic-gate } 566a5407c02SAnil udupa connp = sctp_fanout(src, dst, ports, ira, mp, sctps, NULL); 567f4b3ec61Sdh155122 if (connp == NULL) { 568bd670b35SErik Nordmark ip_fanout_sctp_raw(mp, ipha, ip6h, ports, ira); 5697c478bd9Sstevel@tonic-gate return; 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate sctp = CONN2SCTP(connp); 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * We check some fields in conn_t without holding a lock. 5757c478bd9Sstevel@tonic-gate * This should be fine. 5767c478bd9Sstevel@tonic-gate */ 577bd670b35SErik Nordmark if (((iraflags & IRAF_IS_IPV4) ? 578bd670b35SErik Nordmark CONN_INBOUND_POLICY_PRESENT(connp, ipss) : 579bd670b35SErik Nordmark CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss)) || 580bd670b35SErik Nordmark secure) { 581bd670b35SErik Nordmark mp = ipsec_check_inbound_policy(mp, connp, ipha, 582bd670b35SErik Nordmark ip6h, ira); 5837c478bd9Sstevel@tonic-gate if (mp == NULL) { 5847c478bd9Sstevel@tonic-gate SCTP_REFRELE(sctp); 5857c478bd9Sstevel@tonic-gate return; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 589bd670b35SErik Nordmark ira->ira_ill = ira->ira_rill = NULL; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock); 5927c478bd9Sstevel@tonic-gate if (sctp->sctp_running) { 593bd670b35SErik Nordmark sctp_add_recvq(sctp, mp, B_FALSE, ira); 5947c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5957c478bd9Sstevel@tonic-gate } else { 5967c478bd9Sstevel@tonic-gate sctp->sctp_running = B_TRUE; 5977c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate mutex_enter(&sctp->sctp_recvq_lock); 6007c478bd9Sstevel@tonic-gate if (sctp->sctp_recvq != NULL) { 601bd670b35SErik Nordmark sctp_add_recvq(sctp, mp, B_TRUE, ira); 6027c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 6037c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 6047c478bd9Sstevel@tonic-gate } else { 6057c478bd9Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock); 606bd670b35SErik Nordmark if (ira->ira_flags & IRAF_ICMP_ERROR) { 607bd670b35SErik Nordmark sctp_icmp_error(sctp, mp); 608bd670b35SErik Nordmark } else { 609bd670b35SErik Nordmark sctp_input_data(sctp, mp, ira); 610bd670b35SErik Nordmark } 6117c478bd9Sstevel@tonic-gate WAKE_SCTP(sctp); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate SCTP_REFRELE(sctp); 615bd670b35SErik Nordmark ira->ira_ill = ill; 616bd670b35SErik Nordmark ira->ira_rill = rill; 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate void 6207c478bd9Sstevel@tonic-gate sctp_conn_hash_remove(sctp_t *sctp) 6217c478bd9Sstevel@tonic-gate { 6227c478bd9Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_conn_tfp; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate if (!tf) { 6257c478bd9Sstevel@tonic-gate return; 6267c478bd9Sstevel@tonic-gate } 6271d8c4025Svi117747 /* 6281d8c4025Svi117747 * On a clustered note send this notification to the clustering 6291d8c4025Svi117747 * subsystem. 6301d8c4025Svi117747 */ 6311d8c4025Svi117747 if (cl_sctp_disconnect != NULL) { 632bd670b35SErik Nordmark (*cl_sctp_disconnect)(sctp->sctp_connp->conn_family, 6331d8c4025Svi117747 (cl_sctp_handle_t)sctp); 6341d8c4025Svi117747 } 6351d8c4025Svi117747 6367c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6377c478bd9Sstevel@tonic-gate ASSERT(tf->tf_sctp); 6387c478bd9Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 6397c478bd9Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_conn_hash_next; 6407c478bd9Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 6417c478bd9Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_conn_hash_prev == sctp); 6427c478bd9Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = NULL; 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate } else { 6457c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev); 6467c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev->sctp_conn_hash_next == sctp); 6477c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_prev->sctp_conn_hash_next = 6487c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_next; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) { 6517c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_next->sctp_conn_hash_prev 6527c478bd9Sstevel@tonic-gate == sctp); 6537c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_next->sctp_conn_hash_prev = 6547c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_prev; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_next = NULL; 6587c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 6597c478bd9Sstevel@tonic-gate sctp->sctp_conn_tfp = NULL; 6607c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate void 6647c478bd9Sstevel@tonic-gate sctp_conn_hash_insert(sctp_tf_t *tf, sctp_t *sctp, int caller_holds_lock) 6657c478bd9Sstevel@tonic-gate { 6667c478bd9Sstevel@tonic-gate if (sctp->sctp_conn_tfp) { 6677c478bd9Sstevel@tonic-gate sctp_conn_hash_remove(sctp); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate if (!caller_holds_lock) { 6717c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 6727c478bd9Sstevel@tonic-gate } else { 6737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_next = tf->tf_sctp; 6777c478bd9Sstevel@tonic-gate if (tf->tf_sctp) { 6787c478bd9Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = sctp; 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL; 6817c478bd9Sstevel@tonic-gate tf->tf_sctp = sctp; 6827c478bd9Sstevel@tonic-gate sctp->sctp_conn_tfp = tf; 6837c478bd9Sstevel@tonic-gate if (!caller_holds_lock) { 6847c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate void 6897c478bd9Sstevel@tonic-gate sctp_listen_hash_remove(sctp_t *sctp) 6907c478bd9Sstevel@tonic-gate { 6917c478bd9Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_listen_tfp; 692bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate if (!tf) { 6957c478bd9Sstevel@tonic-gate return; 6967c478bd9Sstevel@tonic-gate } 6971d8c4025Svi117747 /* 6981d8c4025Svi117747 * On a clustered note send this notification to the clustering 6991d8c4025Svi117747 * subsystem. 7001d8c4025Svi117747 */ 7011d8c4025Svi117747 if (cl_sctp_unlisten != NULL) { 7021d8c4025Svi117747 uchar_t *slist; 7031d8c4025Svi117747 ssize_t ssize; 7041d8c4025Svi117747 7051d8c4025Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 7061d8c4025Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 7071d8c4025Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 708bd670b35SErik Nordmark (*cl_sctp_unlisten)(connp->conn_family, slist, 709bd670b35SErik Nordmark sctp->sctp_nsaddrs, connp->conn_lport); 7101d8c4025Svi117747 /* list will be freed by the clustering module */ 7111d8c4025Svi117747 } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 7147c478bd9Sstevel@tonic-gate ASSERT(tf->tf_sctp); 7157c478bd9Sstevel@tonic-gate if (tf->tf_sctp == sctp) { 7167c478bd9Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_listen_hash_next; 717e6f13f86SKacheong Poon if (sctp->sctp_listen_hash_next != NULL) { 7187c478bd9Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_listen_hash_prev == sctp); 7197c478bd9Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = NULL; 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate } else { 7227c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev); 7237c478bd9Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev->sctp_listen_hash_next == 7247c478bd9Sstevel@tonic-gate sctp); 725e6f13f86SKacheong Poon ASSERT(sctp->sctp_listen_hash_next == NULL || 726e6f13f86SKacheong Poon sctp->sctp_listen_hash_next->sctp_listen_hash_prev == sctp); 727e6f13f86SKacheong Poon 7287c478bd9Sstevel@tonic-gate sctp->sctp_listen_hash_prev->sctp_listen_hash_next = 7297c478bd9Sstevel@tonic-gate sctp->sctp_listen_hash_next; 7307c478bd9Sstevel@tonic-gate 731e6f13f86SKacheong Poon if (sctp->sctp_listen_hash_next != NULL) { 732bd670b35SErik Nordmark sctp_t *next = sctp->sctp_listen_hash_next; 733bd670b35SErik Nordmark 734bd670b35SErik Nordmark ASSERT(next->sctp_listen_hash_prev == sctp); 735bd670b35SErik Nordmark next->sctp_listen_hash_prev = 7367c478bd9Sstevel@tonic-gate sctp->sctp_listen_hash_prev; 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate sctp->sctp_listen_hash_next = NULL; 7407c478bd9Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 7417c478bd9Sstevel@tonic-gate sctp->sctp_listen_tfp = NULL; 7427c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate void 7467c478bd9Sstevel@tonic-gate sctp_listen_hash_insert(sctp_tf_t *tf, sctp_t *sctp) 7477c478bd9Sstevel@tonic-gate { 748bd670b35SErik Nordmark conn_t *connp = sctp->sctp_connp; 749bd670b35SErik Nordmark 7507c478bd9Sstevel@tonic-gate if (sctp->sctp_listen_tfp) { 7517c478bd9Sstevel@tonic-gate sctp_listen_hash_remove(sctp); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate mutex_enter(&tf->tf_lock); 7557c478bd9Sstevel@tonic-gate sctp->sctp_listen_hash_next = tf->tf_sctp; 7567c478bd9Sstevel@tonic-gate if (tf->tf_sctp) { 7577c478bd9Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = sctp; 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL; 7607c478bd9Sstevel@tonic-gate tf->tf_sctp = sctp; 7617c478bd9Sstevel@tonic-gate sctp->sctp_listen_tfp = tf; 7627c478bd9Sstevel@tonic-gate mutex_exit(&tf->tf_lock); 7631d8c4025Svi117747 /* 7641d8c4025Svi117747 * On a clustered note send this notification to the clustering 7651d8c4025Svi117747 * subsystem. 7661d8c4025Svi117747 */ 7671d8c4025Svi117747 if (cl_sctp_listen != NULL) { 7681d8c4025Svi117747 uchar_t *slist; 7691d8c4025Svi117747 ssize_t ssize; 7701d8c4025Svi117747 7711d8c4025Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs; 7721d8c4025Svi117747 slist = kmem_alloc(ssize, KM_SLEEP); 7731d8c4025Svi117747 sctp_get_saddr_list(sctp, slist, ssize); 774bd670b35SErik Nordmark (*cl_sctp_listen)(connp->conn_family, slist, 775bd670b35SErik Nordmark sctp->sctp_nsaddrs, connp->conn_lport); 7761d8c4025Svi117747 /* list will be freed by the clustering module */ 7771d8c4025Svi117747 } 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate /* 7817c478bd9Sstevel@tonic-gate * Hash list insertion routine for sctp_t structures. 7827c478bd9Sstevel@tonic-gate * Inserts entries with the ones bound to a specific IP address first 7837c478bd9Sstevel@tonic-gate * followed by those bound to INADDR_ANY. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate void 7867c478bd9Sstevel@tonic-gate sctp_bind_hash_insert(sctp_tf_t *tbf, sctp_t *sctp, int caller_holds_lock) 7877c478bd9Sstevel@tonic-gate { 7887c478bd9Sstevel@tonic-gate sctp_t **sctpp; 7897c478bd9Sstevel@tonic-gate sctp_t *sctpnext; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate if (sctp->sctp_ptpbhn != NULL) { 7927c478bd9Sstevel@tonic-gate ASSERT(!caller_holds_lock); 7937c478bd9Sstevel@tonic-gate sctp_bind_hash_remove(sctp); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate sctpp = &tbf->tf_sctp; 7967c478bd9Sstevel@tonic-gate if (!caller_holds_lock) { 7977c478bd9Sstevel@tonic-gate mutex_enter(&tbf->tf_lock); 7987c478bd9Sstevel@tonic-gate } else { 7997c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tbf->tf_lock)); 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate sctpnext = sctpp[0]; 8027c478bd9Sstevel@tonic-gate if (sctpnext) { 8037c478bd9Sstevel@tonic-gate sctpnext->sctp_ptpbhn = &sctp->sctp_bind_hash; 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate sctp->sctp_bind_hash = sctpnext; 8067c478bd9Sstevel@tonic-gate sctp->sctp_ptpbhn = sctpp; 8077c478bd9Sstevel@tonic-gate sctpp[0] = sctp; 8087c478bd9Sstevel@tonic-gate /* For sctp_*_hash_remove */ 8097c478bd9Sstevel@tonic-gate sctp->sctp_bind_lockp = &tbf->tf_lock; 8107c478bd9Sstevel@tonic-gate if (!caller_holds_lock) 8117c478bd9Sstevel@tonic-gate mutex_exit(&tbf->tf_lock); 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * Hash list removal routine for sctp_t structures. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate void 8187c478bd9Sstevel@tonic-gate sctp_bind_hash_remove(sctp_t *sctp) 8197c478bd9Sstevel@tonic-gate { 8207c478bd9Sstevel@tonic-gate sctp_t *sctpnext; 8217c478bd9Sstevel@tonic-gate kmutex_t *lockp; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate lockp = sctp->sctp_bind_lockp; 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate if (sctp->sctp_ptpbhn == NULL) 8267c478bd9Sstevel@tonic-gate return; 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate ASSERT(lockp != NULL); 8297c478bd9Sstevel@tonic-gate mutex_enter(lockp); 8307c478bd9Sstevel@tonic-gate if (sctp->sctp_ptpbhn) { 8317c478bd9Sstevel@tonic-gate sctpnext = sctp->sctp_bind_hash; 8327c478bd9Sstevel@tonic-gate if (sctpnext) { 8337c478bd9Sstevel@tonic-gate sctpnext->sctp_ptpbhn = sctp->sctp_ptpbhn; 8347c478bd9Sstevel@tonic-gate sctp->sctp_bind_hash = NULL; 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate *sctp->sctp_ptpbhn = sctpnext; 8377c478bd9Sstevel@tonic-gate sctp->sctp_ptpbhn = NULL; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate mutex_exit(lockp); 8407c478bd9Sstevel@tonic-gate sctp->sctp_bind_lockp = NULL; 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate /* 844e6f13f86SKacheong Poon * Similar to but different from sctp_conn_match(). 8457c478bd9Sstevel@tonic-gate * 8467c478bd9Sstevel@tonic-gate * Matches sets of addresses as follows: if the argument addr set is 8477c478bd9Sstevel@tonic-gate * a complete subset of the corresponding addr set in the sctp_t, it 8487c478bd9Sstevel@tonic-gate * is a match. 8497c478bd9Sstevel@tonic-gate * 8507c478bd9Sstevel@tonic-gate * Caller must hold tf->tf_lock. 8517c478bd9Sstevel@tonic-gate * 8527c478bd9Sstevel@tonic-gate * Returns with a SCTP_REFHOLD sctp structure. Caller must do a SCTP_REFRELE. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate sctp_t * 8557c478bd9Sstevel@tonic-gate sctp_lookup(sctp_t *sctp1, in6_addr_t *faddr, sctp_tf_t *tf, uint32_t *ports, 8567c478bd9Sstevel@tonic-gate int min_state) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate sctp_t *sctp; 8597c478bd9Sstevel@tonic-gate sctp_faddr_t *fp; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock)); 8627c478bd9Sstevel@tonic-gate 863e6f13f86SKacheong Poon for (sctp = tf->tf_sctp; sctp != NULL; 864e6f13f86SKacheong Poon sctp = sctp->sctp_conn_hash_next) { 865bd670b35SErik Nordmark if (*ports != sctp->sctp_connp->conn_ports || 866bd670b35SErik Nordmark sctp->sctp_state < min_state) { 8677c478bd9Sstevel@tonic-gate continue; 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate /* check for faddr match */ 8716be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) { 8726be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India if (IN6_ARE_ADDR_EQUAL(faddr, &fp->sf_faddr)) { 8737c478bd9Sstevel@tonic-gate break; 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 877e6f13f86SKacheong Poon if (fp == NULL) { 8787c478bd9Sstevel@tonic-gate /* no faddr match; keep looking */ 8797c478bd9Sstevel@tonic-gate continue; 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate 882e6f13f86SKacheong Poon /* 883e6f13f86SKacheong Poon * There is an existing association with the same peer 884e6f13f86SKacheong Poon * address. So now we need to check if our local address 885e6f13f86SKacheong Poon * set overlaps with the one of the existing association. 886e6f13f86SKacheong Poon * If they overlap, we should return it. 887e6f13f86SKacheong Poon */ 888e6f13f86SKacheong Poon if (sctp_compare_saddrs(sctp1, sctp) <= SCTP_ADDR_OVERLAP) { 8897c478bd9Sstevel@tonic-gate goto done; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* no match; continue searching */ 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate done: 896e6f13f86SKacheong Poon if (sctp != NULL) { 8977c478bd9Sstevel@tonic-gate SCTP_REFHOLD(sctp); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate return (sctp); 9007c478bd9Sstevel@tonic-gate } 901