10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51676Sjpk * Common Development and Distribution License (the "License").
61676Sjpk * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate
220Sstevel@tonic-gate /*
23*13009SChandrasekar.Marimuthu@Sun.COM * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/socket.h>
270Sstevel@tonic-gate #include <sys/ddi.h>
280Sstevel@tonic-gate #include <sys/sunddi.h>
291676Sjpk #include <sys/tsol/tndb.h>
301676Sjpk #include <sys/tsol/tnet.h>
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <netinet/in.h>
330Sstevel@tonic-gate #include <netinet/ip6.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate #include <inet/common.h>
360Sstevel@tonic-gate #include <inet/ip.h>
370Sstevel@tonic-gate #include <inet/ip6.h>
380Sstevel@tonic-gate #include <inet/ipclassifier.h>
390Sstevel@tonic-gate #include <inet/ipsec_impl.h>
400Sstevel@tonic-gate #include <inet/ipp_common.h>
410Sstevel@tonic-gate #include <inet/sctp_ip.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate #include "sctp_impl.h"
440Sstevel@tonic-gate #include "sctp_addr.h"
450Sstevel@tonic-gate
460Sstevel@tonic-gate /* Default association hash size. The size must be a power of 2. */
470Sstevel@tonic-gate #define SCTP_CONN_HASH_SIZE 8192
480Sstevel@tonic-gate
493448Sdh155122 uint_t sctp_conn_hash_size = SCTP_CONN_HASH_SIZE; /* /etc/system */
500Sstevel@tonic-gate
51852Svi117747 /*
52852Svi117747 * Cluster networking hook for traversing current assoc list.
53852Svi117747 * This routine is used to extract the current list of live associations
54852Svi117747 * which must continue to to be dispatched to this node.
55852Svi117747 */
56852Svi117747 int cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *), void *,
57852Svi117747 boolean_t);
583448Sdh155122 static int cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *,
593448Sdh155122 void *), void *arg, boolean_t cansleep, sctp_stack_t *sctps);
60852Svi117747
610Sstevel@tonic-gate void
sctp_hash_init(sctp_stack_t * sctps)623448Sdh155122 sctp_hash_init(sctp_stack_t *sctps)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate int i;
650Sstevel@tonic-gate
663448Sdh155122 /* Start with /etc/system value */
673448Sdh155122 sctps->sctps_conn_hash_size = sctp_conn_hash_size;
683448Sdh155122
693448Sdh155122 if (sctps->sctps_conn_hash_size & (sctps->sctps_conn_hash_size - 1)) {
700Sstevel@tonic-gate /* Not a power of two. Round up to nearest power of two */
710Sstevel@tonic-gate for (i = 0; i < 31; i++) {
723448Sdh155122 if (sctps->sctps_conn_hash_size < (1 << i))
730Sstevel@tonic-gate break;
740Sstevel@tonic-gate }
753448Sdh155122 sctps->sctps_conn_hash_size = 1 << i;
760Sstevel@tonic-gate }
773448Sdh155122 if (sctps->sctps_conn_hash_size < SCTP_CONN_HASH_SIZE) {
783448Sdh155122 sctps->sctps_conn_hash_size = SCTP_CONN_HASH_SIZE;
790Sstevel@tonic-gate cmn_err(CE_CONT, "using sctp_conn_hash_size = %u\n",
803448Sdh155122 sctps->sctps_conn_hash_size);
810Sstevel@tonic-gate }
823448Sdh155122 sctps->sctps_conn_fanout =
837480SKacheong.Poon@Sun.COM (sctp_tf_t *)kmem_zalloc(sctps->sctps_conn_hash_size *
8411042SErik.Nordmark@Sun.COM sizeof (sctp_tf_t), KM_SLEEP);
853448Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) {
863448Sdh155122 mutex_init(&sctps->sctps_conn_fanout[i].tf_lock, NULL,
877480SKacheong.Poon@Sun.COM MUTEX_DEFAULT, NULL);
880Sstevel@tonic-gate }
893448Sdh155122 sctps->sctps_listen_fanout = kmem_zalloc(SCTP_LISTEN_FANOUT_SIZE *
903448Sdh155122 sizeof (sctp_tf_t), KM_SLEEP);
913448Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) {
923448Sdh155122 mutex_init(&sctps->sctps_listen_fanout[i].tf_lock, NULL,
930Sstevel@tonic-gate MUTEX_DEFAULT, NULL);
940Sstevel@tonic-gate }
953448Sdh155122 sctps->sctps_bind_fanout = kmem_zalloc(SCTP_BIND_FANOUT_SIZE *
963448Sdh155122 sizeof (sctp_tf_t), KM_SLEEP);
973448Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) {
983448Sdh155122 mutex_init(&sctps->sctps_bind_fanout[i].tf_lock, NULL,
990Sstevel@tonic-gate MUTEX_DEFAULT, NULL);
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate void
sctp_hash_destroy(sctp_stack_t * sctps)1043448Sdh155122 sctp_hash_destroy(sctp_stack_t *sctps)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate int i;
1070Sstevel@tonic-gate
1083448Sdh155122 for (i = 0; i < sctps->sctps_conn_hash_size; i++) {
1093448Sdh155122 mutex_destroy(&sctps->sctps_conn_fanout[i].tf_lock);
1103448Sdh155122 }
1113448Sdh155122 kmem_free(sctps->sctps_conn_fanout, sctps->sctps_conn_hash_size *
1123448Sdh155122 sizeof (sctp_tf_t));
1133448Sdh155122 sctps->sctps_conn_fanout = NULL;
1143448Sdh155122
1153448Sdh155122 for (i = 0; i < SCTP_LISTEN_FANOUT_SIZE; i++) {
1163448Sdh155122 mutex_destroy(&sctps->sctps_listen_fanout[i].tf_lock);
1170Sstevel@tonic-gate }
1183448Sdh155122 kmem_free(sctps->sctps_listen_fanout, SCTP_LISTEN_FANOUT_SIZE *
1193448Sdh155122 sizeof (sctp_tf_t));
1203448Sdh155122 sctps->sctps_listen_fanout = NULL;
1213448Sdh155122
1223448Sdh155122 for (i = 0; i < SCTP_BIND_FANOUT_SIZE; i++) {
1233448Sdh155122 mutex_destroy(&sctps->sctps_bind_fanout[i].tf_lock);
1240Sstevel@tonic-gate }
1253448Sdh155122 kmem_free(sctps->sctps_bind_fanout, SCTP_BIND_FANOUT_SIZE *
1263448Sdh155122 sizeof (sctp_tf_t));
1273448Sdh155122 sctps->sctps_bind_fanout = NULL;
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate
1301932Svi117747 /*
131852Svi117747 * Exported routine for extracting active SCTP associations.
132852Svi117747 * Like TCP, we terminate the walk if the callback returns non-zero.
1333448Sdh155122 *
1343448Sdh155122 * Need to walk all sctp_stack_t instances since this clustering
1353448Sdh155122 * interface is assumed global for all instances
136852Svi117747 */
137852Svi117747 int
cl_sctp_walk_list(int (* cl_callback)(cl_sctp_info_t *,void *),void * arg,boolean_t cansleep)1383448Sdh155122 cl_sctp_walk_list(int (*cl_callback)(cl_sctp_info_t *, void *),
1393448Sdh155122 void *arg, boolean_t cansleep)
1403448Sdh155122 {
1413448Sdh155122 netstack_handle_t nh;
1423448Sdh155122 netstack_t *ns;
1433448Sdh155122 int ret = 0;
1443448Sdh155122
1453448Sdh155122 netstack_next_init(&nh);
1463448Sdh155122 while ((ns = netstack_next(&nh)) != NULL) {
1473448Sdh155122 ret = cl_sctp_walk_list_stack(cl_callback, arg, cansleep,
1483448Sdh155122 ns->netstack_sctp);
1493448Sdh155122 netstack_rele(ns);
1503448Sdh155122 }
1513448Sdh155122 netstack_next_fini(&nh);
1523448Sdh155122 return (ret);
1533448Sdh155122 }
1543448Sdh155122
1553448Sdh155122 static int
cl_sctp_walk_list_stack(int (* cl_callback)(cl_sctp_info_t *,void *),void * arg,boolean_t cansleep,sctp_stack_t * sctps)1563448Sdh155122 cl_sctp_walk_list_stack(int (*cl_callback)(cl_sctp_info_t *, void *),
1573448Sdh155122 void *arg, boolean_t cansleep, sctp_stack_t *sctps)
158852Svi117747 {
159852Svi117747 sctp_t *sctp;
160852Svi117747 sctp_t *sctp_prev;
161852Svi117747 cl_sctp_info_t cl_sctpi;
162852Svi117747 uchar_t *slist;
163852Svi117747 uchar_t *flist;
164852Svi117747
165852Svi117747 sctp_prev = NULL;
1663448Sdh155122 mutex_enter(&sctps->sctps_g_lock);
16711042SErik.Nordmark@Sun.COM sctp = list_head(&sctps->sctps_g_list);
168852Svi117747 while (sctp != NULL) {
169852Svi117747 size_t ssize;
170852Svi117747 size_t fsize;
171852Svi117747
172852Svi117747 mutex_enter(&sctp->sctp_reflock);
173852Svi117747 if (sctp->sctp_condemned || sctp->sctp_state <= SCTPS_LISTEN) {
174852Svi117747 mutex_exit(&sctp->sctp_reflock);
1753448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp);
176852Svi117747 continue;
177852Svi117747 }
178852Svi117747 sctp->sctp_refcnt++;
179852Svi117747 mutex_exit(&sctp->sctp_reflock);
1803448Sdh155122 mutex_exit(&sctps->sctps_g_lock);
181852Svi117747 if (sctp_prev != NULL)
182852Svi117747 SCTP_REFRELE(sctp_prev);
183852Svi117747 RUN_SCTP(sctp);
184852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
185852Svi117747 fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
186852Svi117747
187852Svi117747 slist = kmem_alloc(ssize, cansleep ? KM_SLEEP : KM_NOSLEEP);
188852Svi117747 flist = kmem_alloc(fsize, cansleep ? KM_SLEEP : KM_NOSLEEP);
189852Svi117747 if (slist == NULL || flist == NULL) {
190852Svi117747 WAKE_SCTP(sctp);
191852Svi117747 if (slist != NULL)
192852Svi117747 kmem_free(slist, ssize);
193852Svi117747 if (flist != NULL)
194852Svi117747 kmem_free(flist, fsize);
195852Svi117747 SCTP_REFRELE(sctp);
196852Svi117747 return (1);
197852Svi117747 }
198852Svi117747 cl_sctpi.cl_sctpi_version = CL_SCTPI_V1;
199852Svi117747 sctp_get_saddr_list(sctp, slist, ssize);
200852Svi117747 sctp_get_faddr_list(sctp, flist, fsize);
201852Svi117747 cl_sctpi.cl_sctpi_nladdr = sctp->sctp_nsaddrs;
202852Svi117747 cl_sctpi.cl_sctpi_nfaddr = sctp->sctp_nfaddrs;
20311042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_family = sctp->sctp_connp->conn_family;
20411042SErik.Nordmark@Sun.COM if (cl_sctpi.cl_sctpi_family == AF_INET)
20511042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_ipversion = IPV4_VERSION;
20611042SErik.Nordmark@Sun.COM else
20711042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_ipversion = IPV6_VERSION;
208852Svi117747 cl_sctpi.cl_sctpi_state = sctp->sctp_state;
20911042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_lport = sctp->sctp_connp->conn_lport;
21011042SErik.Nordmark@Sun.COM cl_sctpi.cl_sctpi_fport = sctp->sctp_connp->conn_fport;
211852Svi117747 cl_sctpi.cl_sctpi_handle = (cl_sctp_handle_t)sctp;
212852Svi117747 WAKE_SCTP(sctp);
213852Svi117747 cl_sctpi.cl_sctpi_laddrp = slist;
214852Svi117747 cl_sctpi.cl_sctpi_faddrp = flist;
215852Svi117747 if ((*cl_callback)(&cl_sctpi, arg) != 0) {
216852Svi117747 kmem_free(slist, ssize);
217852Svi117747 kmem_free(flist, fsize);
218852Svi117747 SCTP_REFRELE(sctp);
219852Svi117747 return (1);
220852Svi117747 }
221852Svi117747 /* list will be freed by cl_callback */
222852Svi117747 sctp_prev = sctp;
2233448Sdh155122 mutex_enter(&sctps->sctps_g_lock);
2243448Sdh155122 sctp = list_next(&sctps->sctps_g_list, sctp);
225852Svi117747 }
2263448Sdh155122 mutex_exit(&sctps->sctps_g_lock);
227852Svi117747 if (sctp_prev != NULL)
228852Svi117747 SCTP_REFRELE(sctp_prev);
229852Svi117747 return (0);
230852Svi117747 }
231852Svi117747
2320Sstevel@tonic-gate sctp_t *
sctp_conn_match(in6_addr_t ** faddrpp,uint32_t nfaddr,in6_addr_t * laddr,uint32_t ports,zoneid_t zoneid,iaflags_t iraflags,sctp_stack_t * sctps)23312339Sanil.udupa@sun.com sctp_conn_match(in6_addr_t **faddrpp, uint32_t nfaddr, in6_addr_t *laddr,
23412339Sanil.udupa@sun.com uint32_t ports, zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate sctp_tf_t *tf;
2370Sstevel@tonic-gate sctp_t *sctp;
2380Sstevel@tonic-gate sctp_faddr_t *fp;
23911042SErik.Nordmark@Sun.COM conn_t *connp;
24012339Sanil.udupa@sun.com in6_addr_t **faddrs, **endaddrs = &faddrpp[nfaddr];
2410Sstevel@tonic-gate
2423448Sdh155122 tf = &(sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, ports)]);
2430Sstevel@tonic-gate mutex_enter(&tf->tf_lock);
2440Sstevel@tonic-gate
24512339Sanil.udupa@sun.com for (sctp = tf->tf_sctp; sctp != NULL; sctp =
24612339Sanil.udupa@sun.com sctp->sctp_conn_hash_next) {
24711042SErik.Nordmark@Sun.COM connp = sctp->sctp_connp;
24811042SErik.Nordmark@Sun.COM if (ports != connp->conn_ports)
2490Sstevel@tonic-gate continue;
25011042SErik.Nordmark@Sun.COM if (!(connp->conn_zoneid == zoneid ||
25111042SErik.Nordmark@Sun.COM connp->conn_allzones ||
25211042SErik.Nordmark@Sun.COM ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
25311042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_MAC_EXEMPTABLE) &&
25411042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_SHARED_ADDR))))
25511042SErik.Nordmark@Sun.COM continue;
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /* check for faddr match */
258*13009SChandrasekar.Marimuthu@Sun.COM for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
25912339Sanil.udupa@sun.com for (faddrs = faddrpp; faddrs < endaddrs; faddrs++) {
260*13009SChandrasekar.Marimuthu@Sun.COM if (IN6_ARE_ADDR_EQUAL(*faddrs,
261*13009SChandrasekar.Marimuthu@Sun.COM &fp->sf_faddr)) {
26212339Sanil.udupa@sun.com /* check for laddr match */
26312339Sanil.udupa@sun.com if (sctp_saddr_lookup(sctp, laddr, 0)
26412339Sanil.udupa@sun.com != NULL) {
26512339Sanil.udupa@sun.com SCTP_REFHOLD(sctp);
26612339Sanil.udupa@sun.com mutex_exit(&tf->tf_lock);
26712339Sanil.udupa@sun.com return (sctp);
26812339Sanil.udupa@sun.com }
26912339Sanil.udupa@sun.com }
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate /* no match; continue to the next in the chain */
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate mutex_exit(&tf->tf_lock);
2770Sstevel@tonic-gate return (sctp);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate static sctp_t *
listen_match(in6_addr_t * laddr,uint32_t ports,zoneid_t zoneid,iaflags_t iraflags,sctp_stack_t * sctps)2813510Svi117747 listen_match(in6_addr_t *laddr, uint32_t ports, zoneid_t zoneid,
28211042SErik.Nordmark@Sun.COM iaflags_t iraflags, sctp_stack_t *sctps)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate sctp_t *sctp;
2850Sstevel@tonic-gate sctp_tf_t *tf;
2860Sstevel@tonic-gate uint16_t lport;
28711042SErik.Nordmark@Sun.COM conn_t *connp;
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate lport = ((uint16_t *)&ports)[1];
2900Sstevel@tonic-gate
2913448Sdh155122 tf = &(sctps->sctps_listen_fanout[SCTP_LISTEN_HASH(ntohs(lport))]);
2920Sstevel@tonic-gate mutex_enter(&tf->tf_lock);
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_listen_hash_next) {
29511042SErik.Nordmark@Sun.COM connp = sctp->sctp_connp;
29611042SErik.Nordmark@Sun.COM if (lport != connp->conn_lport)
2970Sstevel@tonic-gate continue;
29811042SErik.Nordmark@Sun.COM
29911042SErik.Nordmark@Sun.COM if (!(connp->conn_zoneid == zoneid ||
30011042SErik.Nordmark@Sun.COM connp->conn_allzones ||
30111042SErik.Nordmark@Sun.COM ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
30211042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_MAC_EXEMPTABLE) &&
30311042SErik.Nordmark@Sun.COM (iraflags & IRAF_TX_SHARED_ADDR))))
30411042SErik.Nordmark@Sun.COM continue;
3050Sstevel@tonic-gate
3063510Svi117747 if (sctp_saddr_lookup(sctp, laddr, 0) != NULL) {
3073510Svi117747 SCTP_REFHOLD(sctp);
3083510Svi117747 goto done;
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate /* no match; continue to the next in the chain */
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate done:
3140Sstevel@tonic-gate mutex_exit(&tf->tf_lock);
3150Sstevel@tonic-gate return (sctp);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3181676Sjpk /* called by ipsec_sctp_pol */
3190Sstevel@tonic-gate conn_t *
sctp_find_conn(in6_addr_t * src,in6_addr_t * dst,uint32_t ports,zoneid_t zoneid,iaflags_t iraflags,sctp_stack_t * sctps)3200Sstevel@tonic-gate sctp_find_conn(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
32111042SErik.Nordmark@Sun.COM zoneid_t zoneid, iaflags_t iraflags, sctp_stack_t *sctps)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate sctp_t *sctp;
3240Sstevel@tonic-gate
32512339Sanil.udupa@sun.com sctp = sctp_conn_match(&src, 1, dst, ports, zoneid, iraflags, sctps);
32611042SErik.Nordmark@Sun.COM if (sctp == NULL) {
3270Sstevel@tonic-gate /* Not in conn fanout; check listen fanout */
32811042SErik.Nordmark@Sun.COM sctp = listen_match(dst, ports, zoneid, iraflags, sctps);
32911042SErik.Nordmark@Sun.COM if (sctp == NULL)
3300Sstevel@tonic-gate return (NULL);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate return (sctp->sctp_connp);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
33511042SErik.Nordmark@Sun.COM /*
33612339Sanil.udupa@sun.com * This is called from sctp_fanout() with IP header src & dst addresses.
33712339Sanil.udupa@sun.com * First call sctp_conn_match() to get a match by passing in src & dst
33812339Sanil.udupa@sun.com * addresses from IP header.
33912339Sanil.udupa@sun.com * However sctp_conn_match() can return no match under condition such as :
34012339Sanil.udupa@sun.com * A host can send an INIT ACK from a different address than the INIT was sent
34112339Sanil.udupa@sun.com * to (in a multi-homed env).
34212339Sanil.udupa@sun.com * According to RFC4960, a host can send additional addresses in an INIT
34312339Sanil.udupa@sun.com * ACK chunk.
34412339Sanil.udupa@sun.com * Therefore extract all addresses from the INIT ACK chunk, pass to
34512339Sanil.udupa@sun.com * sctp_conn_match() to get a match.
34612339Sanil.udupa@sun.com */
34712339Sanil.udupa@sun.com static sctp_t *
sctp_lookup_by_faddrs(mblk_t * mp,sctp_hdr_t * sctph,in6_addr_t * srcp,in6_addr_t * dstp,uint32_t ports,zoneid_t zoneid,sctp_stack_t * sctps,iaflags_t iraflags)34812339Sanil.udupa@sun.com sctp_lookup_by_faddrs(mblk_t *mp, sctp_hdr_t *sctph, in6_addr_t *srcp,
34912339Sanil.udupa@sun.com in6_addr_t *dstp, uint32_t ports, zoneid_t zoneid, sctp_stack_t *sctps,
35012339Sanil.udupa@sun.com iaflags_t iraflags)
35112339Sanil.udupa@sun.com {
35212339Sanil.udupa@sun.com sctp_t *sctp;
35312339Sanil.udupa@sun.com sctp_chunk_hdr_t *ich;
35412339Sanil.udupa@sun.com sctp_init_chunk_t *iack;
35512339Sanil.udupa@sun.com sctp_parm_hdr_t *ph;
35612339Sanil.udupa@sun.com ssize_t mlen, remaining;
35712339Sanil.udupa@sun.com uint16_t param_type, addr_len = PARM_ADDR4_LEN;
35812339Sanil.udupa@sun.com in6_addr_t src;
35912339Sanil.udupa@sun.com in6_addr_t **addrbuf = NULL, **faddrpp = NULL;
36012339Sanil.udupa@sun.com boolean_t isv4;
36112339Sanil.udupa@sun.com uint32_t totaddr, nfaddr = 0;
36212339Sanil.udupa@sun.com
36312339Sanil.udupa@sun.com /*
36412339Sanil.udupa@sun.com * If we get a match with the passed-in IP header src & dst addresses,
36512339Sanil.udupa@sun.com * quickly return the matched sctp.
36612339Sanil.udupa@sun.com */
36712339Sanil.udupa@sun.com if ((sctp = sctp_conn_match(&srcp, 1, dstp, ports, zoneid, iraflags,
36812339Sanil.udupa@sun.com sctps)) != NULL) {
36912339Sanil.udupa@sun.com return (sctp);
37012339Sanil.udupa@sun.com }
37112339Sanil.udupa@sun.com
37212339Sanil.udupa@sun.com /*
37312339Sanil.udupa@sun.com * Currently sctph is set to NULL in icmp error fanout case
37412339Sanil.udupa@sun.com * (ip_fanout_sctp()).
37512339Sanil.udupa@sun.com * The above sctp_conn_match() should handle that, otherwise
37612339Sanil.udupa@sun.com * return no match found.
37712339Sanil.udupa@sun.com */
37812339Sanil.udupa@sun.com if (sctph == NULL)
37912339Sanil.udupa@sun.com return (NULL);
38012339Sanil.udupa@sun.com
38112339Sanil.udupa@sun.com /*
38212339Sanil.udupa@sun.com * Do a pullup again in case the previous one was partially successful,
38312339Sanil.udupa@sun.com * so try to complete the pullup here and have a single contiguous
38412339Sanil.udupa@sun.com * chunk for processing of entire INIT ACK chunk below.
38512339Sanil.udupa@sun.com */
38612339Sanil.udupa@sun.com if (mp->b_cont != NULL) {
38712339Sanil.udupa@sun.com if (pullupmsg(mp, -1) == 0) {
38812339Sanil.udupa@sun.com return (NULL);
38912339Sanil.udupa@sun.com }
39012339Sanil.udupa@sun.com }
39112339Sanil.udupa@sun.com
39212339Sanil.udupa@sun.com mlen = mp->b_wptr - (uchar_t *)(sctph + 1);
39312339Sanil.udupa@sun.com if ((ich = sctp_first_chunk((uchar_t *)(sctph + 1), mlen)) == NULL) {
39412339Sanil.udupa@sun.com return (NULL);
39512339Sanil.udupa@sun.com }
39612339Sanil.udupa@sun.com
39712339Sanil.udupa@sun.com if (ich->sch_id == CHUNK_INIT_ACK) {
39812339Sanil.udupa@sun.com remaining = ntohs(ich->sch_len) - sizeof (*ich) -
39912339Sanil.udupa@sun.com sizeof (*iack);
40012339Sanil.udupa@sun.com if (remaining < sizeof (*ph)) {
40112339Sanil.udupa@sun.com return (NULL);
40212339Sanil.udupa@sun.com }
40312339Sanil.udupa@sun.com
40412339Sanil.udupa@sun.com isv4 = (iraflags & IRAF_IS_IPV4) ? B_TRUE : B_FALSE;
40512339Sanil.udupa@sun.com if (!isv4)
40612339Sanil.udupa@sun.com addr_len = PARM_ADDR6_LEN;
40712339Sanil.udupa@sun.com totaddr = remaining/addr_len;
40812339Sanil.udupa@sun.com
40912339Sanil.udupa@sun.com iack = (sctp_init_chunk_t *)(ich + 1);
41012339Sanil.udupa@sun.com ph = (sctp_parm_hdr_t *)(iack + 1);
41112339Sanil.udupa@sun.com
41212339Sanil.udupa@sun.com addrbuf = (in6_addr_t **)
41312339Sanil.udupa@sun.com kmem_zalloc(totaddr * sizeof (in6_addr_t *), KM_NOSLEEP);
41412339Sanil.udupa@sun.com if (addrbuf == NULL)
41512339Sanil.udupa@sun.com return (NULL);
41612339Sanil.udupa@sun.com faddrpp = addrbuf;
41712339Sanil.udupa@sun.com
41812339Sanil.udupa@sun.com while (ph != NULL) {
41912339Sanil.udupa@sun.com /*
42012339Sanil.udupa@sun.com * According to RFC4960 :
42112339Sanil.udupa@sun.com * All integer fields in an SCTP packet MUST be
42212339Sanil.udupa@sun.com * transmitted in network byte order,
42312339Sanil.udupa@sun.com * unless otherwise stated.
42412339Sanil.udupa@sun.com * Therefore convert the param type to host byte order.
42512339Sanil.udupa@sun.com * Also do not add src address present in IP header
42612339Sanil.udupa@sun.com * as it has already been thru sctp_conn_match() above.
42712339Sanil.udupa@sun.com */
42812339Sanil.udupa@sun.com param_type = ntohs(ph->sph_type);
42912339Sanil.udupa@sun.com switch (param_type) {
43012339Sanil.udupa@sun.com case PARM_ADDR4:
43112339Sanil.udupa@sun.com IN6_INADDR_TO_V4MAPPED((struct in_addr *)
43212339Sanil.udupa@sun.com (ph + 1), &src);
43312339Sanil.udupa@sun.com if (IN6_ARE_ADDR_EQUAL(&src, srcp))
43412339Sanil.udupa@sun.com break;
43512339Sanil.udupa@sun.com *faddrpp = (in6_addr_t *)
43612339Sanil.udupa@sun.com kmem_zalloc(sizeof (in6_addr_t),
43712339Sanil.udupa@sun.com KM_NOSLEEP);
43812339Sanil.udupa@sun.com if (*faddrpp == NULL)
43912339Sanil.udupa@sun.com break;
44012339Sanil.udupa@sun.com IN6_INADDR_TO_V4MAPPED((struct in_addr *)
44112339Sanil.udupa@sun.com (ph + 1), *faddrpp);
44212339Sanil.udupa@sun.com nfaddr++;
44312339Sanil.udupa@sun.com faddrpp++;
44412339Sanil.udupa@sun.com break;
44512339Sanil.udupa@sun.com case PARM_ADDR6:
44612339Sanil.udupa@sun.com *faddrpp = (in6_addr_t *)(ph + 1);
44712339Sanil.udupa@sun.com if (IN6_ARE_ADDR_EQUAL(*faddrpp, srcp))
44812339Sanil.udupa@sun.com break;
44912339Sanil.udupa@sun.com nfaddr++;
45012339Sanil.udupa@sun.com faddrpp++;
45112339Sanil.udupa@sun.com break;
45212339Sanil.udupa@sun.com default:
45312339Sanil.udupa@sun.com break;
45412339Sanil.udupa@sun.com }
45512339Sanil.udupa@sun.com ph = sctp_next_parm(ph, &remaining);
45612339Sanil.udupa@sun.com }
45712339Sanil.udupa@sun.com
45812339Sanil.udupa@sun.com ASSERT(nfaddr < totaddr);
45912339Sanil.udupa@sun.com
46012339Sanil.udupa@sun.com if (nfaddr > 0) {
46112339Sanil.udupa@sun.com sctp = sctp_conn_match(addrbuf, nfaddr, dstp, ports,
46212339Sanil.udupa@sun.com zoneid, iraflags, sctps);
46312339Sanil.udupa@sun.com
46412339Sanil.udupa@sun.com if (isv4) {
46512339Sanil.udupa@sun.com for (faddrpp = addrbuf; nfaddr > 0;
46612339Sanil.udupa@sun.com faddrpp++, nfaddr--) {
46712339Sanil.udupa@sun.com if (IN6_IS_ADDR_V4MAPPED(*faddrpp)) {
46812339Sanil.udupa@sun.com kmem_free(*faddrpp,
46912339Sanil.udupa@sun.com sizeof (in6_addr_t));
47012339Sanil.udupa@sun.com }
47112339Sanil.udupa@sun.com }
47212339Sanil.udupa@sun.com }
47312339Sanil.udupa@sun.com }
47412339Sanil.udupa@sun.com kmem_free(addrbuf, totaddr * sizeof (in6_addr_t *));
47512339Sanil.udupa@sun.com }
47612339Sanil.udupa@sun.com return (sctp);
47712339Sanil.udupa@sun.com }
47812339Sanil.udupa@sun.com
47912339Sanil.udupa@sun.com /*
48011042SErik.Nordmark@Sun.COM * Fanout to a sctp instance.
48111042SErik.Nordmark@Sun.COM */
4821676Sjpk conn_t *
sctp_fanout(in6_addr_t * src,in6_addr_t * dst,uint32_t ports,ip_recv_attr_t * ira,mblk_t * mp,sctp_stack_t * sctps,sctp_hdr_t * sctph)4831676Sjpk sctp_fanout(in6_addr_t *src, in6_addr_t *dst, uint32_t ports,
48412339Sanil.udupa@sun.com ip_recv_attr_t *ira, mblk_t *mp, sctp_stack_t *sctps, sctp_hdr_t *sctph)
4851676Sjpk {
48611042SErik.Nordmark@Sun.COM zoneid_t zoneid = ira->ira_zoneid;
48711042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags;
4881676Sjpk sctp_t *sctp;
4891676Sjpk
49012339Sanil.udupa@sun.com sctp = sctp_lookup_by_faddrs(mp, sctph, src, dst, ports, zoneid,
49112339Sanil.udupa@sun.com sctps, iraflags);
49211042SErik.Nordmark@Sun.COM if (sctp == NULL) {
4931676Sjpk /* Not in conn fanout; check listen fanout */
49411042SErik.Nordmark@Sun.COM sctp = listen_match(dst, ports, zoneid, iraflags, sctps);
49511042SErik.Nordmark@Sun.COM if (sctp == NULL)
4961676Sjpk return (NULL);
4972776Skp158701 /*
4982776Skp158701 * On systems running trusted extensions, check if dst
4992776Skp158701 * should accept the packet. "IPV6_VERSION" indicates
5002776Skp158701 * that dst is in 16 byte AF_INET6 format. IPv4-mapped
5012776Skp158701 * IPv6 addresses are supported.
5022776Skp158701 */
50311042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_SYSTEM_LABELED) &&
50411042SErik.Nordmark@Sun.COM !tsol_receive_local(mp, dst, IPV6_VERSION, ira,
50511042SErik.Nordmark@Sun.COM sctp->sctp_connp)) {
5062776Skp158701 DTRACE_PROBE3(
5072776Skp158701 tx__ip__log__info__classify__sctp,
5082776Skp158701 char *,
5092776Skp158701 "connp(1) could not receive mp(2)",
5102776Skp158701 conn_t *, sctp->sctp_connp, mblk_t *, mp);
5112776Skp158701 SCTP_REFRELE(sctp);
5122776Skp158701 return (NULL);
5132776Skp158701 }
5141676Sjpk }
51511042SErik.Nordmark@Sun.COM /*
51611042SErik.Nordmark@Sun.COM * For labeled systems, there's no need to check the
51711042SErik.Nordmark@Sun.COM * label here. It's known to be good as we checked
51811042SErik.Nordmark@Sun.COM * before allowing the connection to become bound.
51911042SErik.Nordmark@Sun.COM */
5201676Sjpk return (sctp->sctp_connp);
5211676Sjpk }
5221676Sjpk
5230Sstevel@tonic-gate /*
52411042SErik.Nordmark@Sun.COM * Fanout for ICMP errors for SCTP
5250Sstevel@tonic-gate * The caller puts <fport, lport> in the ports parameter.
5260Sstevel@tonic-gate */
5270Sstevel@tonic-gate void
ip_fanout_sctp(mblk_t * mp,ipha_t * ipha,ip6_t * ip6h,uint32_t ports,ip_recv_attr_t * ira)52811042SErik.Nordmark@Sun.COM ip_fanout_sctp(mblk_t *mp, ipha_t *ipha, ip6_t *ip6h, uint32_t ports,
52911042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira)
5300Sstevel@tonic-gate {
53111042SErik.Nordmark@Sun.COM sctp_t *sctp;
53211042SErik.Nordmark@Sun.COM conn_t *connp;
53311042SErik.Nordmark@Sun.COM in6_addr_t map_src, map_dst;
53411042SErik.Nordmark@Sun.COM in6_addr_t *src, *dst;
53511042SErik.Nordmark@Sun.COM boolean_t secure;
53611042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill;
53711042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst;
53811042SErik.Nordmark@Sun.COM netstack_t *ns = ipst->ips_netstack;
53911042SErik.Nordmark@Sun.COM ipsec_stack_t *ipss = ns->netstack_ipsec;
54011042SErik.Nordmark@Sun.COM sctp_stack_t *sctps = ns->netstack_sctp;
54111042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags;
54211042SErik.Nordmark@Sun.COM ill_t *rill = ira->ira_rill;
5433448Sdh155122
54411042SErik.Nordmark@Sun.COM ASSERT(iraflags & IRAF_ICMP_ERROR);
5450Sstevel@tonic-gate
54611042SErik.Nordmark@Sun.COM secure = iraflags & IRAF_IPSEC_SECURE;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate /* Assume IP provides aligned packets - otherwise toss */
5490Sstevel@tonic-gate if (!OK_32PTR(mp->b_rptr)) {
55011042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
55111042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill);
55211042SErik.Nordmark@Sun.COM freemsg(mp);
5530Sstevel@tonic-gate return;
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate
55611042SErik.Nordmark@Sun.COM if (!(iraflags & IRAF_IS_IPV4)) {
5570Sstevel@tonic-gate src = &ip6h->ip6_src;
5580Sstevel@tonic-gate dst = &ip6h->ip6_dst;
5590Sstevel@tonic-gate } else {
5600Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src);
5610Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst);
5620Sstevel@tonic-gate src = &map_src;
5630Sstevel@tonic-gate dst = &map_dst;
5640Sstevel@tonic-gate }
56512339Sanil.udupa@sun.com connp = sctp_fanout(src, dst, ports, ira, mp, sctps, NULL);
5663448Sdh155122 if (connp == NULL) {
56711042SErik.Nordmark@Sun.COM ip_fanout_sctp_raw(mp, ipha, ip6h, ports, ira);
5680Sstevel@tonic-gate return;
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate sctp = CONN2SCTP(connp);
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate /*
5730Sstevel@tonic-gate * We check some fields in conn_t without holding a lock.
5740Sstevel@tonic-gate * This should be fine.
5750Sstevel@tonic-gate */
57611042SErik.Nordmark@Sun.COM if (((iraflags & IRAF_IS_IPV4) ?
57711042SErik.Nordmark@Sun.COM CONN_INBOUND_POLICY_PRESENT(connp, ipss) :
57811042SErik.Nordmark@Sun.COM CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss)) ||
57911042SErik.Nordmark@Sun.COM secure) {
58011042SErik.Nordmark@Sun.COM mp = ipsec_check_inbound_policy(mp, connp, ipha,
58111042SErik.Nordmark@Sun.COM ip6h, ira);
58211042SErik.Nordmark@Sun.COM if (mp == NULL) {
5830Sstevel@tonic-gate SCTP_REFRELE(sctp);
5840Sstevel@tonic-gate return;
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate
58811042SErik.Nordmark@Sun.COM ira->ira_ill = ira->ira_rill = NULL;
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate mutex_enter(&sctp->sctp_lock);
5910Sstevel@tonic-gate if (sctp->sctp_running) {
59211042SErik.Nordmark@Sun.COM sctp_add_recvq(sctp, mp, B_FALSE, ira);
5930Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock);
5940Sstevel@tonic-gate } else {
5950Sstevel@tonic-gate sctp->sctp_running = B_TRUE;
5960Sstevel@tonic-gate mutex_exit(&sctp->sctp_lock);
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate mutex_enter(&sctp->sctp_recvq_lock);
5990Sstevel@tonic-gate if (sctp->sctp_recvq != NULL) {
60011042SErik.Nordmark@Sun.COM sctp_add_recvq(sctp, mp, B_TRUE, ira);
6010Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock);
6020Sstevel@tonic-gate WAKE_SCTP(sctp);
6030Sstevel@tonic-gate } else {
6040Sstevel@tonic-gate mutex_exit(&sctp->sctp_recvq_lock);
60511042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_ICMP_ERROR) {
60611042SErik.Nordmark@Sun.COM sctp_icmp_error(sctp, mp);
60711042SErik.Nordmark@Sun.COM } else {
60811042SErik.Nordmark@Sun.COM sctp_input_data(sctp, mp, ira);
60911042SErik.Nordmark@Sun.COM }
6100Sstevel@tonic-gate WAKE_SCTP(sctp);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate SCTP_REFRELE(sctp);
61411042SErik.Nordmark@Sun.COM ira->ira_ill = ill;
61511042SErik.Nordmark@Sun.COM ira->ira_rill = rill;
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate void
sctp_conn_hash_remove(sctp_t * sctp)6190Sstevel@tonic-gate sctp_conn_hash_remove(sctp_t *sctp)
6200Sstevel@tonic-gate {
6210Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_conn_tfp;
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate if (!tf) {
6240Sstevel@tonic-gate return;
6250Sstevel@tonic-gate }
626852Svi117747 /*
627852Svi117747 * On a clustered note send this notification to the clustering
628852Svi117747 * subsystem.
629852Svi117747 */
630852Svi117747 if (cl_sctp_disconnect != NULL) {
63111042SErik.Nordmark@Sun.COM (*cl_sctp_disconnect)(sctp->sctp_connp->conn_family,
632852Svi117747 (cl_sctp_handle_t)sctp);
633852Svi117747 }
634852Svi117747
6350Sstevel@tonic-gate mutex_enter(&tf->tf_lock);
6360Sstevel@tonic-gate ASSERT(tf->tf_sctp);
6370Sstevel@tonic-gate if (tf->tf_sctp == sctp) {
6380Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_conn_hash_next;
6390Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) {
6400Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_conn_hash_prev == sctp);
6410Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = NULL;
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate } else {
6440Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev);
6450Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_prev->sctp_conn_hash_next == sctp);
6460Sstevel@tonic-gate sctp->sctp_conn_hash_prev->sctp_conn_hash_next =
6470Sstevel@tonic-gate sctp->sctp_conn_hash_next;
6480Sstevel@tonic-gate
6490Sstevel@tonic-gate if (sctp->sctp_conn_hash_next) {
6500Sstevel@tonic-gate ASSERT(sctp->sctp_conn_hash_next->sctp_conn_hash_prev
6510Sstevel@tonic-gate == sctp);
6520Sstevel@tonic-gate sctp->sctp_conn_hash_next->sctp_conn_hash_prev =
6530Sstevel@tonic-gate sctp->sctp_conn_hash_prev;
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate sctp->sctp_conn_hash_next = NULL;
6570Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL;
6580Sstevel@tonic-gate sctp->sctp_conn_tfp = NULL;
6590Sstevel@tonic-gate mutex_exit(&tf->tf_lock);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate void
sctp_conn_hash_insert(sctp_tf_t * tf,sctp_t * sctp,int caller_holds_lock)6630Sstevel@tonic-gate sctp_conn_hash_insert(sctp_tf_t *tf, sctp_t *sctp, int caller_holds_lock)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate if (sctp->sctp_conn_tfp) {
6660Sstevel@tonic-gate sctp_conn_hash_remove(sctp);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate if (!caller_holds_lock) {
6700Sstevel@tonic-gate mutex_enter(&tf->tf_lock);
6710Sstevel@tonic-gate } else {
6720Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock));
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate sctp->sctp_conn_hash_next = tf->tf_sctp;
6760Sstevel@tonic-gate if (tf->tf_sctp) {
6770Sstevel@tonic-gate tf->tf_sctp->sctp_conn_hash_prev = sctp;
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate sctp->sctp_conn_hash_prev = NULL;
6800Sstevel@tonic-gate tf->tf_sctp = sctp;
6810Sstevel@tonic-gate sctp->sctp_conn_tfp = tf;
6820Sstevel@tonic-gate if (!caller_holds_lock) {
6830Sstevel@tonic-gate mutex_exit(&tf->tf_lock);
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate void
sctp_listen_hash_remove(sctp_t * sctp)6880Sstevel@tonic-gate sctp_listen_hash_remove(sctp_t *sctp)
6890Sstevel@tonic-gate {
6900Sstevel@tonic-gate sctp_tf_t *tf = sctp->sctp_listen_tfp;
69111042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate if (!tf) {
6940Sstevel@tonic-gate return;
6950Sstevel@tonic-gate }
696852Svi117747 /*
697852Svi117747 * On a clustered note send this notification to the clustering
698852Svi117747 * subsystem.
699852Svi117747 */
700852Svi117747 if (cl_sctp_unlisten != NULL) {
701852Svi117747 uchar_t *slist;
702852Svi117747 ssize_t ssize;
703852Svi117747
704852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
705852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP);
706852Svi117747 sctp_get_saddr_list(sctp, slist, ssize);
70711042SErik.Nordmark@Sun.COM (*cl_sctp_unlisten)(connp->conn_family, slist,
70811042SErik.Nordmark@Sun.COM sctp->sctp_nsaddrs, connp->conn_lport);
709852Svi117747 /* list will be freed by the clustering module */
710852Svi117747 }
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate mutex_enter(&tf->tf_lock);
7130Sstevel@tonic-gate ASSERT(tf->tf_sctp);
7140Sstevel@tonic-gate if (tf->tf_sctp == sctp) {
7150Sstevel@tonic-gate tf->tf_sctp = sctp->sctp_listen_hash_next;
7167480SKacheong.Poon@Sun.COM if (sctp->sctp_listen_hash_next != NULL) {
7170Sstevel@tonic-gate ASSERT(tf->tf_sctp->sctp_listen_hash_prev == sctp);
7180Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = NULL;
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate } else {
7210Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev);
7220Sstevel@tonic-gate ASSERT(sctp->sctp_listen_hash_prev->sctp_listen_hash_next ==
7230Sstevel@tonic-gate sctp);
7247480SKacheong.Poon@Sun.COM ASSERT(sctp->sctp_listen_hash_next == NULL ||
7257480SKacheong.Poon@Sun.COM sctp->sctp_listen_hash_next->sctp_listen_hash_prev == sctp);
7267480SKacheong.Poon@Sun.COM
7270Sstevel@tonic-gate sctp->sctp_listen_hash_prev->sctp_listen_hash_next =
7280Sstevel@tonic-gate sctp->sctp_listen_hash_next;
7290Sstevel@tonic-gate
7307480SKacheong.Poon@Sun.COM if (sctp->sctp_listen_hash_next != NULL) {
73111042SErik.Nordmark@Sun.COM sctp_t *next = sctp->sctp_listen_hash_next;
73211042SErik.Nordmark@Sun.COM
73311042SErik.Nordmark@Sun.COM ASSERT(next->sctp_listen_hash_prev == sctp);
73411042SErik.Nordmark@Sun.COM next->sctp_listen_hash_prev =
7350Sstevel@tonic-gate sctp->sctp_listen_hash_prev;
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate sctp->sctp_listen_hash_next = NULL;
7390Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL;
7400Sstevel@tonic-gate sctp->sctp_listen_tfp = NULL;
7410Sstevel@tonic-gate mutex_exit(&tf->tf_lock);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate void
sctp_listen_hash_insert(sctp_tf_t * tf,sctp_t * sctp)7450Sstevel@tonic-gate sctp_listen_hash_insert(sctp_tf_t *tf, sctp_t *sctp)
7460Sstevel@tonic-gate {
74711042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
74811042SErik.Nordmark@Sun.COM
7490Sstevel@tonic-gate if (sctp->sctp_listen_tfp) {
7500Sstevel@tonic-gate sctp_listen_hash_remove(sctp);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate mutex_enter(&tf->tf_lock);
7540Sstevel@tonic-gate sctp->sctp_listen_hash_next = tf->tf_sctp;
7550Sstevel@tonic-gate if (tf->tf_sctp) {
7560Sstevel@tonic-gate tf->tf_sctp->sctp_listen_hash_prev = sctp;
7570Sstevel@tonic-gate }
7580Sstevel@tonic-gate sctp->sctp_listen_hash_prev = NULL;
7590Sstevel@tonic-gate tf->tf_sctp = sctp;
7600Sstevel@tonic-gate sctp->sctp_listen_tfp = tf;
7610Sstevel@tonic-gate mutex_exit(&tf->tf_lock);
762852Svi117747 /*
763852Svi117747 * On a clustered note send this notification to the clustering
764852Svi117747 * subsystem.
765852Svi117747 */
766852Svi117747 if (cl_sctp_listen != NULL) {
767852Svi117747 uchar_t *slist;
768852Svi117747 ssize_t ssize;
769852Svi117747
770852Svi117747 ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
771852Svi117747 slist = kmem_alloc(ssize, KM_SLEEP);
772852Svi117747 sctp_get_saddr_list(sctp, slist, ssize);
77311042SErik.Nordmark@Sun.COM (*cl_sctp_listen)(connp->conn_family, slist,
77411042SErik.Nordmark@Sun.COM sctp->sctp_nsaddrs, connp->conn_lport);
775852Svi117747 /* list will be freed by the clustering module */
776852Svi117747 }
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate /*
7800Sstevel@tonic-gate * Hash list insertion routine for sctp_t structures.
7810Sstevel@tonic-gate * Inserts entries with the ones bound to a specific IP address first
7820Sstevel@tonic-gate * followed by those bound to INADDR_ANY.
7830Sstevel@tonic-gate */
7840Sstevel@tonic-gate void
sctp_bind_hash_insert(sctp_tf_t * tbf,sctp_t * sctp,int caller_holds_lock)7850Sstevel@tonic-gate sctp_bind_hash_insert(sctp_tf_t *tbf, sctp_t *sctp, int caller_holds_lock)
7860Sstevel@tonic-gate {
7870Sstevel@tonic-gate sctp_t **sctpp;
7880Sstevel@tonic-gate sctp_t *sctpnext;
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate if (sctp->sctp_ptpbhn != NULL) {
7910Sstevel@tonic-gate ASSERT(!caller_holds_lock);
7920Sstevel@tonic-gate sctp_bind_hash_remove(sctp);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate sctpp = &tbf->tf_sctp;
7950Sstevel@tonic-gate if (!caller_holds_lock) {
7960Sstevel@tonic-gate mutex_enter(&tbf->tf_lock);
7970Sstevel@tonic-gate } else {
7980Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tbf->tf_lock));
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate sctpnext = sctpp[0];
8010Sstevel@tonic-gate if (sctpnext) {
8020Sstevel@tonic-gate sctpnext->sctp_ptpbhn = &sctp->sctp_bind_hash;
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate sctp->sctp_bind_hash = sctpnext;
8050Sstevel@tonic-gate sctp->sctp_ptpbhn = sctpp;
8060Sstevel@tonic-gate sctpp[0] = sctp;
8070Sstevel@tonic-gate /* For sctp_*_hash_remove */
8080Sstevel@tonic-gate sctp->sctp_bind_lockp = &tbf->tf_lock;
8090Sstevel@tonic-gate if (!caller_holds_lock)
8100Sstevel@tonic-gate mutex_exit(&tbf->tf_lock);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate /*
8140Sstevel@tonic-gate * Hash list removal routine for sctp_t structures.
8150Sstevel@tonic-gate */
8160Sstevel@tonic-gate void
sctp_bind_hash_remove(sctp_t * sctp)8170Sstevel@tonic-gate sctp_bind_hash_remove(sctp_t *sctp)
8180Sstevel@tonic-gate {
8190Sstevel@tonic-gate sctp_t *sctpnext;
8200Sstevel@tonic-gate kmutex_t *lockp;
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate lockp = sctp->sctp_bind_lockp;
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate if (sctp->sctp_ptpbhn == NULL)
8250Sstevel@tonic-gate return;
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate ASSERT(lockp != NULL);
8280Sstevel@tonic-gate mutex_enter(lockp);
8290Sstevel@tonic-gate if (sctp->sctp_ptpbhn) {
8300Sstevel@tonic-gate sctpnext = sctp->sctp_bind_hash;
8310Sstevel@tonic-gate if (sctpnext) {
8320Sstevel@tonic-gate sctpnext->sctp_ptpbhn = sctp->sctp_ptpbhn;
8330Sstevel@tonic-gate sctp->sctp_bind_hash = NULL;
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate *sctp->sctp_ptpbhn = sctpnext;
8360Sstevel@tonic-gate sctp->sctp_ptpbhn = NULL;
8370Sstevel@tonic-gate }
8380Sstevel@tonic-gate mutex_exit(lockp);
8390Sstevel@tonic-gate sctp->sctp_bind_lockp = NULL;
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate /*
8437480SKacheong.Poon@Sun.COM * Similar to but different from sctp_conn_match().
8440Sstevel@tonic-gate *
8450Sstevel@tonic-gate * Matches sets of addresses as follows: if the argument addr set is
8460Sstevel@tonic-gate * a complete subset of the corresponding addr set in the sctp_t, it
8470Sstevel@tonic-gate * is a match.
8480Sstevel@tonic-gate *
8490Sstevel@tonic-gate * Caller must hold tf->tf_lock.
8500Sstevel@tonic-gate *
8510Sstevel@tonic-gate * Returns with a SCTP_REFHOLD sctp structure. Caller must do a SCTP_REFRELE.
8520Sstevel@tonic-gate */
8530Sstevel@tonic-gate sctp_t *
sctp_lookup(sctp_t * sctp1,in6_addr_t * faddr,sctp_tf_t * tf,uint32_t * ports,int min_state)8540Sstevel@tonic-gate sctp_lookup(sctp_t *sctp1, in6_addr_t *faddr, sctp_tf_t *tf, uint32_t *ports,
8550Sstevel@tonic-gate int min_state)
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate sctp_t *sctp;
8580Sstevel@tonic-gate sctp_faddr_t *fp;
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate ASSERT(MUTEX_HELD(&tf->tf_lock));
8610Sstevel@tonic-gate
8627480SKacheong.Poon@Sun.COM for (sctp = tf->tf_sctp; sctp != NULL;
8637480SKacheong.Poon@Sun.COM sctp = sctp->sctp_conn_hash_next) {
86411042SErik.Nordmark@Sun.COM if (*ports != sctp->sctp_connp->conn_ports ||
86511042SErik.Nordmark@Sun.COM sctp->sctp_state < min_state) {
8660Sstevel@tonic-gate continue;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate /* check for faddr match */
870*13009SChandrasekar.Marimuthu@Sun.COM for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
871*13009SChandrasekar.Marimuthu@Sun.COM if (IN6_ARE_ADDR_EQUAL(faddr, &fp->sf_faddr)) {
8720Sstevel@tonic-gate break;
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate
8767480SKacheong.Poon@Sun.COM if (fp == NULL) {
8770Sstevel@tonic-gate /* no faddr match; keep looking */
8780Sstevel@tonic-gate continue;
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate
8817480SKacheong.Poon@Sun.COM /*
8827480SKacheong.Poon@Sun.COM * There is an existing association with the same peer
8837480SKacheong.Poon@Sun.COM * address. So now we need to check if our local address
8847480SKacheong.Poon@Sun.COM * set overlaps with the one of the existing association.
8857480SKacheong.Poon@Sun.COM * If they overlap, we should return it.
8867480SKacheong.Poon@Sun.COM */
8877480SKacheong.Poon@Sun.COM if (sctp_compare_saddrs(sctp1, sctp) <= SCTP_ADDR_OVERLAP) {
8880Sstevel@tonic-gate goto done;
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate /* no match; continue searching */
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate done:
8957480SKacheong.Poon@Sun.COM if (sctp != NULL) {
8960Sstevel@tonic-gate SCTP_REFHOLD(sctp);
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate return (sctp);
8990Sstevel@tonic-gate }
900