xref: /onnv-gate/usr/src/uts/common/inet/sockmods/sockmod_sctp.c (revision 9059:ab57be184037)
18348SEric.Yu@Sun.COM /*
28348SEric.Yu@Sun.COM  * CDDL HEADER START
38348SEric.Yu@Sun.COM  *
48348SEric.Yu@Sun.COM  * The contents of this file are subject to the terms of the
58348SEric.Yu@Sun.COM  * Common Development and Distribution License (the "License").
68348SEric.Yu@Sun.COM  * You may not use this file except in compliance with the License.
78348SEric.Yu@Sun.COM  *
88348SEric.Yu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98348SEric.Yu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108348SEric.Yu@Sun.COM  * See the License for the specific language governing permissions
118348SEric.Yu@Sun.COM  * and limitations under the License.
128348SEric.Yu@Sun.COM  *
138348SEric.Yu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148348SEric.Yu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158348SEric.Yu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168348SEric.Yu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178348SEric.Yu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188348SEric.Yu@Sun.COM  *
198348SEric.Yu@Sun.COM  * CDDL HEADER END
208348SEric.Yu@Sun.COM  */
218348SEric.Yu@Sun.COM 
228348SEric.Yu@Sun.COM /*
23*9059SErik.Nordmark@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
248348SEric.Yu@Sun.COM  * Use is subject to license terms.
258348SEric.Yu@Sun.COM  */
268348SEric.Yu@Sun.COM 
278348SEric.Yu@Sun.COM #include <sys/sysmacros.h>
288348SEric.Yu@Sun.COM #include <sys/strsubr.h>
298348SEric.Yu@Sun.COM #include <sys/socket.h>
308348SEric.Yu@Sun.COM #include <sys/socketvar.h>
318348SEric.Yu@Sun.COM #include <sys/modctl.h>
328348SEric.Yu@Sun.COM #include <sys/cmn_err.h>
338348SEric.Yu@Sun.COM #include <netinet/sctp.h>
348348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h>
358348SEric.Yu@Sun.COM #include "socksctp.h"
368348SEric.Yu@Sun.COM 
378348SEric.Yu@Sun.COM struct sonode 	*socksctp_create(struct sockparams *, int, int, int,
388348SEric.Yu@Sun.COM 			    int, int, int *, cred_t *);
398348SEric.Yu@Sun.COM void 		socksctp_destroy(struct sonode *);
408348SEric.Yu@Sun.COM 
418348SEric.Yu@Sun.COM static int 	socksctp_constructor(void *, void *, int);
428348SEric.Yu@Sun.COM static void 	socksctp_destructor(void *, void *);
438348SEric.Yu@Sun.COM 
448348SEric.Yu@Sun.COM static __smod_priv_t sosctp_priv = {
458348SEric.Yu@Sun.COM 	socksctp_create,
468348SEric.Yu@Sun.COM 	socksctp_destroy,
478348SEric.Yu@Sun.COM 	NULL
488348SEric.Yu@Sun.COM };
498348SEric.Yu@Sun.COM 
508348SEric.Yu@Sun.COM static smod_reg_t sinfo = {
518348SEric.Yu@Sun.COM 	SOCKMOD_VERSION,
528348SEric.Yu@Sun.COM 	"socksctp",
538348SEric.Yu@Sun.COM 	SOCK_UC_VERSION,
548348SEric.Yu@Sun.COM 	SOCK_DC_VERSION,
558348SEric.Yu@Sun.COM 	NULL,
568348SEric.Yu@Sun.COM 	&sosctp_priv
578348SEric.Yu@Sun.COM };
588348SEric.Yu@Sun.COM 
598348SEric.Yu@Sun.COM kmem_cache_t *sosctp_assoccache;
608348SEric.Yu@Sun.COM static kmem_cache_t *sosctp_sockcache;
618348SEric.Yu@Sun.COM 
628348SEric.Yu@Sun.COM /*
638348SEric.Yu@Sun.COM  * Module linkage information for the kernel.
648348SEric.Yu@Sun.COM  */
658348SEric.Yu@Sun.COM static struct modlsockmod modlsockmod = {
668348SEric.Yu@Sun.COM 	&mod_sockmodops, "SCTP socket module", &sinfo
678348SEric.Yu@Sun.COM };
688348SEric.Yu@Sun.COM 
698348SEric.Yu@Sun.COM static struct modlinkage modlinkage = {
708348SEric.Yu@Sun.COM 	MODREV_1,
718348SEric.Yu@Sun.COM 	&modlsockmod,
728348SEric.Yu@Sun.COM 	NULL
738348SEric.Yu@Sun.COM };
748348SEric.Yu@Sun.COM 
758348SEric.Yu@Sun.COM static int
socksctp_init(void)768348SEric.Yu@Sun.COM socksctp_init(void)
778348SEric.Yu@Sun.COM {
788348SEric.Yu@Sun.COM 	sosctp_sockcache = kmem_cache_create("sctpsock",
798348SEric.Yu@Sun.COM 	    sizeof (struct sctp_sonode), 0, socksctp_constructor,
808348SEric.Yu@Sun.COM 	    socksctp_destructor, NULL, NULL, NULL, 0);
818348SEric.Yu@Sun.COM 	sosctp_assoccache = kmem_cache_create("sctp_assoc",
828348SEric.Yu@Sun.COM 	    sizeof (struct sctp_soassoc), 0, NULL, NULL, NULL, NULL, NULL, 0);
838348SEric.Yu@Sun.COM 	return (0);
848348SEric.Yu@Sun.COM }
858348SEric.Yu@Sun.COM 
868348SEric.Yu@Sun.COM static void
socksctp_fini(void)878348SEric.Yu@Sun.COM socksctp_fini(void)
888348SEric.Yu@Sun.COM {
898348SEric.Yu@Sun.COM 	kmem_cache_destroy(sosctp_sockcache);
908348SEric.Yu@Sun.COM 	kmem_cache_destroy(sosctp_assoccache);
918348SEric.Yu@Sun.COM }
928348SEric.Yu@Sun.COM 
938348SEric.Yu@Sun.COM /*ARGSUSED*/
948348SEric.Yu@Sun.COM static int
socksctp_constructor(void * buf,void * cdrarg,int kmflags)958348SEric.Yu@Sun.COM socksctp_constructor(void *buf, void *cdrarg, int kmflags)
968348SEric.Yu@Sun.COM {
978348SEric.Yu@Sun.COM 	struct sctp_sonode *ss = buf;
988348SEric.Yu@Sun.COM 	struct sonode *so = &ss->ss_so;
998348SEric.Yu@Sun.COM 
1008348SEric.Yu@Sun.COM 	ss->ss_type = SOSCTP_SOCKET;
1018348SEric.Yu@Sun.COM 	return (sonode_constructor((void *)so, cdrarg, kmflags));
1028348SEric.Yu@Sun.COM }
1038348SEric.Yu@Sun.COM 
1048348SEric.Yu@Sun.COM /*ARGSUSED*/
1058348SEric.Yu@Sun.COM static void
socksctp_destructor(void * buf,void * cdrarg)1068348SEric.Yu@Sun.COM socksctp_destructor(void *buf, void *cdrarg)
1078348SEric.Yu@Sun.COM {
1088348SEric.Yu@Sun.COM 	struct sctp_sonode *ss = buf;
1098348SEric.Yu@Sun.COM 	struct sonode *so = &ss->ss_so;
1108348SEric.Yu@Sun.COM 
1118348SEric.Yu@Sun.COM 	sonode_destructor((void *)so, cdrarg);
1128348SEric.Yu@Sun.COM }
1138348SEric.Yu@Sun.COM 
1148348SEric.Yu@Sun.COM /*
1158348SEric.Yu@Sun.COM  * Creates a sctp socket data structure.
1168348SEric.Yu@Sun.COM  */
1178348SEric.Yu@Sun.COM /* ARGSUSED */
1188348SEric.Yu@Sun.COM struct sonode *
socksctp_create(struct sockparams * sp,int family,int type,int protocol,int version,int sflags,int * errorp,cred_t * cr)1198348SEric.Yu@Sun.COM socksctp_create(struct sockparams *sp, int family, int type, int protocol,
1208348SEric.Yu@Sun.COM     int version, int sflags, int *errorp, cred_t *cr)
1218348SEric.Yu@Sun.COM {
1228348SEric.Yu@Sun.COM 	struct sctp_sonode *ss;
1238348SEric.Yu@Sun.COM 	struct sonode *so;
1248348SEric.Yu@Sun.COM 	int kmflags = (sflags & SOCKET_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
1258348SEric.Yu@Sun.COM 
1268348SEric.Yu@Sun.COM 	if (version == SOV_STREAM) {
1278348SEric.Yu@Sun.COM 		*errorp = EINVAL;
1288348SEric.Yu@Sun.COM 		return (NULL);
1298348SEric.Yu@Sun.COM 	}
1308348SEric.Yu@Sun.COM 
1318348SEric.Yu@Sun.COM 	/*
1328348SEric.Yu@Sun.COM 	 * We only support two types of SCTP socket.  Let sotpi_create()
1338348SEric.Yu@Sun.COM 	 * handle all other cases, such as raw socket.
1348348SEric.Yu@Sun.COM 	 */
1358348SEric.Yu@Sun.COM 	if (!(family == AF_INET || family == AF_INET6) ||
1368348SEric.Yu@Sun.COM 	    !(type == SOCK_STREAM || type == SOCK_SEQPACKET)) {
1378348SEric.Yu@Sun.COM 		*errorp = EINVAL;
1388348SEric.Yu@Sun.COM 		return (NULL);
1398348SEric.Yu@Sun.COM 	}
1408348SEric.Yu@Sun.COM 
1418348SEric.Yu@Sun.COM 	ss = kmem_cache_alloc(sosctp_sockcache, kmflags);
1428348SEric.Yu@Sun.COM 	if (ss == NULL) {
1438348SEric.Yu@Sun.COM 		*errorp = ENOMEM;
1448348SEric.Yu@Sun.COM 		return (NULL);
1458348SEric.Yu@Sun.COM 	}
1468348SEric.Yu@Sun.COM 
1478348SEric.Yu@Sun.COM 	so = &ss->ss_so;
1488348SEric.Yu@Sun.COM 
1498348SEric.Yu@Sun.COM 	ss->ss_maxassoc	= 0;
1508348SEric.Yu@Sun.COM 	ss->ss_assoccnt	= 0;
1518348SEric.Yu@Sun.COM 	ss->ss_assocs	= NULL;
1528348SEric.Yu@Sun.COM 
1538348SEric.Yu@Sun.COM 	if (type == SOCK_STREAM) {
1548348SEric.Yu@Sun.COM 		sonode_init(so, sp, family, type, protocol,
1558348SEric.Yu@Sun.COM 		    &sosctp_sonodeops);
1568348SEric.Yu@Sun.COM 	} else {
1578348SEric.Yu@Sun.COM 		sonode_init(so, sp, family, type, protocol,
1588348SEric.Yu@Sun.COM 		    &sosctp_seq_sonodeops);
1598348SEric.Yu@Sun.COM 		ASSERT(type == SOCK_SEQPACKET);
1608348SEric.Yu@Sun.COM 		mutex_enter(&so->so_lock);
1618348SEric.Yu@Sun.COM 		(void) sosctp_aid_grow(ss, 1, kmflags);
1628348SEric.Yu@Sun.COM 		mutex_exit(&so->so_lock);
1638348SEric.Yu@Sun.COM 	}
1648348SEric.Yu@Sun.COM 
1658348SEric.Yu@Sun.COM 	if (version == SOV_DEFAULT) {
1668348SEric.Yu@Sun.COM 		version = so_default_version;
1678348SEric.Yu@Sun.COM 	}
1688348SEric.Yu@Sun.COM 	so->so_version = (short)version;
1698348SEric.Yu@Sun.COM 
1708348SEric.Yu@Sun.COM 	dprint(2, ("sosctp_create: %p domain %d type %d\n", (void *)so, family,
1718348SEric.Yu@Sun.COM 	    type));
1728348SEric.Yu@Sun.COM 
173*9059SErik.Nordmark@Sun.COM 	/*
174*9059SErik.Nordmark@Sun.COM 	 * set the default values to be INFPSZ
175*9059SErik.Nordmark@Sun.COM 	 * if a protocol desires it can change the value later
176*9059SErik.Nordmark@Sun.COM 	 */
177*9059SErik.Nordmark@Sun.COM 	so->so_proto_props.sopp_rxhiwat = SOCKET_RECVHIWATER;
178*9059SErik.Nordmark@Sun.COM 	so->so_proto_props.sopp_rxlowat = SOCKET_RECVLOWATER;
179*9059SErik.Nordmark@Sun.COM 	so->so_proto_props.sopp_maxpsz = INFPSZ;
180*9059SErik.Nordmark@Sun.COM 	so->so_proto_props.sopp_maxblk = INFPSZ;
181*9059SErik.Nordmark@Sun.COM 
1828348SEric.Yu@Sun.COM 	return (so);
1838348SEric.Yu@Sun.COM }
1848348SEric.Yu@Sun.COM 
1858348SEric.Yu@Sun.COM /*
1868348SEric.Yu@Sun.COM  * Free SCTP socket data structure.
1878348SEric.Yu@Sun.COM  */
1888348SEric.Yu@Sun.COM void
socksctp_destroy(struct sonode * so)1898348SEric.Yu@Sun.COM socksctp_destroy(struct sonode *so)
1908348SEric.Yu@Sun.COM {
1918348SEric.Yu@Sun.COM 	struct sctp_sonode *ss;
1928348SEric.Yu@Sun.COM 
1938348SEric.Yu@Sun.COM 	ASSERT((so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET) &&
1948348SEric.Yu@Sun.COM 	    so->so_protocol == IPPROTO_SCTP);
1958348SEric.Yu@Sun.COM 
1968348SEric.Yu@Sun.COM 	sosctp_fini(so, CRED());
1978348SEric.Yu@Sun.COM 
1988348SEric.Yu@Sun.COM 	ss = SOTOSSO(so);
1998348SEric.Yu@Sun.COM 	kmem_cache_free(sosctp_sockcache, ss);
2008348SEric.Yu@Sun.COM }
2018348SEric.Yu@Sun.COM 
2028348SEric.Yu@Sun.COM int
_init(void)2038348SEric.Yu@Sun.COM _init(void)
2048348SEric.Yu@Sun.COM {
2058348SEric.Yu@Sun.COM 	int error = 0;
2068348SEric.Yu@Sun.COM 
2078348SEric.Yu@Sun.COM 	(void) socksctp_init();
2088348SEric.Yu@Sun.COM 
2098348SEric.Yu@Sun.COM 	if ((error = mod_install(&modlinkage)) != 0)
2108348SEric.Yu@Sun.COM 		socksctp_fini();
2118348SEric.Yu@Sun.COM 
2128348SEric.Yu@Sun.COM 	return (error);
2138348SEric.Yu@Sun.COM }
2148348SEric.Yu@Sun.COM 
2158348SEric.Yu@Sun.COM int
_fini(void)2168348SEric.Yu@Sun.COM _fini(void)
2178348SEric.Yu@Sun.COM {
2188348SEric.Yu@Sun.COM 	int error = 0;
2198348SEric.Yu@Sun.COM 
2208348SEric.Yu@Sun.COM 	if ((error = mod_remove(&modlinkage)) == 0)
2218348SEric.Yu@Sun.COM 		socksctp_fini();
2228348SEric.Yu@Sun.COM 
2238348SEric.Yu@Sun.COM 	return (error);
2248348SEric.Yu@Sun.COM }
2258348SEric.Yu@Sun.COM 
2268348SEric.Yu@Sun.COM int
_info(struct modinfo * modinfop)2278348SEric.Yu@Sun.COM _info(struct modinfo *modinfop)
2288348SEric.Yu@Sun.COM {
2298348SEric.Yu@Sun.COM 	return (mod_info(&modlinkage, modinfop));
2308348SEric.Yu@Sun.COM }
231