1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/sysmacros.h> 28 #include <sys/strsubr.h> 29 #include <sys/socket.h> 30 #include <sys/socketvar.h> 31 #include <sys/modctl.h> 32 #include <sys/cmn_err.h> 33 #include <netinet/sctp.h> 34 #include <fs/sockfs/sockcommon.h> 35 #include "socksctp.h" 36 37 struct sonode *socksctp_create(struct sockparams *, int, int, int, 38 int, int, int *, cred_t *); 39 void socksctp_destroy(struct sonode *); 40 41 static int socksctp_constructor(void *, void *, int); 42 static void socksctp_destructor(void *, void *); 43 44 static __smod_priv_t sosctp_priv = { 45 socksctp_create, 46 socksctp_destroy, 47 NULL 48 }; 49 50 static smod_reg_t sinfo = { 51 SOCKMOD_VERSION, 52 "socksctp", 53 SOCK_UC_VERSION, 54 SOCK_DC_VERSION, 55 NULL, 56 &sosctp_priv 57 }; 58 59 kmem_cache_t *sosctp_assoccache; 60 static kmem_cache_t *sosctp_sockcache; 61 62 /* 63 * Module linkage information for the kernel. 64 */ 65 static struct modlsockmod modlsockmod = { 66 &mod_sockmodops, "SCTP socket module", &sinfo 67 }; 68 69 static struct modlinkage modlinkage = { 70 MODREV_1, 71 { &modlsockmod, NULL } 72 }; 73 74 static int 75 socksctp_init(void) 76 { 77 sosctp_sockcache = kmem_cache_create("sctpsock", 78 sizeof (struct sctp_sonode), 0, socksctp_constructor, 79 socksctp_destructor, NULL, NULL, NULL, 0); 80 sosctp_assoccache = kmem_cache_create("sctp_assoc", 81 sizeof (struct sctp_soassoc), 0, NULL, NULL, NULL, NULL, NULL, 0); 82 return (0); 83 } 84 85 static void 86 socksctp_fini(void) 87 { 88 kmem_cache_destroy(sosctp_sockcache); 89 kmem_cache_destroy(sosctp_assoccache); 90 } 91 92 /*ARGSUSED*/ 93 static int 94 socksctp_constructor(void *buf, void *cdrarg, int kmflags) 95 { 96 struct sctp_sonode *ss = buf; 97 struct sonode *so = &ss->ss_so; 98 99 ss->ss_type = SOSCTP_SOCKET; 100 return (sonode_constructor((void *)so, cdrarg, kmflags)); 101 } 102 103 /*ARGSUSED*/ 104 static void 105 socksctp_destructor(void *buf, void *cdrarg) 106 { 107 struct sctp_sonode *ss = buf; 108 struct sonode *so = &ss->ss_so; 109 110 sonode_destructor((void *)so, cdrarg); 111 } 112 113 /* 114 * Creates a sctp socket data structure. 115 */ 116 /* ARGSUSED */ 117 struct sonode * 118 socksctp_create(struct sockparams *sp, int family, int type, int protocol, 119 int version, int sflags, int *errorp, cred_t *cr) 120 { 121 struct sctp_sonode *ss; 122 struct sonode *so; 123 int kmflags = (sflags & SOCKET_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP; 124 125 if (version == SOV_STREAM) { 126 *errorp = EINVAL; 127 return (NULL); 128 } 129 130 /* 131 * We only support two types of SCTP socket. Let sotpi_create() 132 * handle all other cases, such as raw socket. 133 */ 134 if (!(family == AF_INET || family == AF_INET6) || 135 !(type == SOCK_STREAM || type == SOCK_SEQPACKET)) { 136 *errorp = EINVAL; 137 return (NULL); 138 } 139 140 ss = kmem_cache_alloc(sosctp_sockcache, kmflags); 141 if (ss == NULL) { 142 *errorp = ENOMEM; 143 return (NULL); 144 } 145 146 so = &ss->ss_so; 147 148 ss->ss_maxassoc = 0; 149 ss->ss_assoccnt = 0; 150 ss->ss_assocs = NULL; 151 152 if (type == SOCK_STREAM) { 153 sonode_init(so, sp, family, type, protocol, 154 &sosctp_sonodeops); 155 } else { 156 sonode_init(so, sp, family, type, protocol, 157 &sosctp_seq_sonodeops); 158 ASSERT(type == SOCK_SEQPACKET); 159 mutex_enter(&so->so_lock); 160 (void) sosctp_aid_grow(ss, 1, kmflags); 161 mutex_exit(&so->so_lock); 162 } 163 164 if (version == SOV_DEFAULT) { 165 version = so_default_version; 166 } 167 so->so_version = (short)version; 168 169 dprint(2, ("sosctp_create: %p domain %d type %d\n", (void *)so, family, 170 type)); 171 172 /* 173 * set the default values to be INFPSZ 174 * if a protocol desires it can change the value later 175 */ 176 so->so_proto_props.sopp_rxhiwat = SOCKET_RECVHIWATER; 177 so->so_proto_props.sopp_rxlowat = SOCKET_RECVLOWATER; 178 so->so_proto_props.sopp_maxpsz = INFPSZ; 179 so->so_proto_props.sopp_maxblk = INFPSZ; 180 181 return (so); 182 } 183 184 /* 185 * Free SCTP socket data structure. 186 */ 187 void 188 socksctp_destroy(struct sonode *so) 189 { 190 struct sctp_sonode *ss; 191 192 ASSERT((so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET) && 193 so->so_protocol == IPPROTO_SCTP); 194 195 sosctp_fini(so, CRED()); 196 197 ss = SOTOSSO(so); 198 kmem_cache_free(sosctp_sockcache, ss); 199 } 200 201 int 202 _init(void) 203 { 204 int error = 0; 205 206 (void) socksctp_init(); 207 208 if ((error = mod_install(&modlinkage)) != 0) 209 socksctp_fini(); 210 211 return (error); 212 } 213 214 int 215 _fini(void) 216 { 217 int error = 0; 218 219 if ((error = mod_remove(&modlinkage)) == 0) 220 socksctp_fini(); 221 222 return (error); 223 } 224 225 int 226 _info(struct modinfo *modinfop) 227 { 228 return (mod_info(&modlinkage, modinfop)); 229 }