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 2008 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, 72 NULL 73 }; 74 75 static int 76 socksctp_init(void) 77 { 78 sosctp_sockcache = kmem_cache_create("sctpsock", 79 sizeof (struct sctp_sonode), 0, socksctp_constructor, 80 socksctp_destructor, NULL, NULL, NULL, 0); 81 sosctp_assoccache = kmem_cache_create("sctp_assoc", 82 sizeof (struct sctp_soassoc), 0, NULL, NULL, NULL, NULL, NULL, 0); 83 return (0); 84 } 85 86 static void 87 socksctp_fini(void) 88 { 89 kmem_cache_destroy(sosctp_sockcache); 90 kmem_cache_destroy(sosctp_assoccache); 91 } 92 93 /*ARGSUSED*/ 94 static int 95 socksctp_constructor(void *buf, void *cdrarg, int kmflags) 96 { 97 struct sctp_sonode *ss = buf; 98 struct sonode *so = &ss->ss_so; 99 100 ss->ss_type = SOSCTP_SOCKET; 101 return (sonode_constructor((void *)so, cdrarg, kmflags)); 102 } 103 104 /*ARGSUSED*/ 105 static void 106 socksctp_destructor(void *buf, void *cdrarg) 107 { 108 struct sctp_sonode *ss = buf; 109 struct sonode *so = &ss->ss_so; 110 111 sonode_destructor((void *)so, cdrarg); 112 } 113 114 /* 115 * Creates a sctp socket data structure. 116 */ 117 /* ARGSUSED */ 118 struct sonode * 119 socksctp_create(struct sockparams *sp, int family, int type, int protocol, 120 int version, int sflags, int *errorp, cred_t *cr) 121 { 122 struct sctp_sonode *ss; 123 struct sonode *so; 124 int kmflags = (sflags & SOCKET_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP; 125 126 if (version == SOV_STREAM) { 127 *errorp = EINVAL; 128 return (NULL); 129 } 130 131 /* 132 * We only support two types of SCTP socket. Let sotpi_create() 133 * handle all other cases, such as raw socket. 134 */ 135 if (!(family == AF_INET || family == AF_INET6) || 136 !(type == SOCK_STREAM || type == SOCK_SEQPACKET)) { 137 *errorp = EINVAL; 138 return (NULL); 139 } 140 141 ss = kmem_cache_alloc(sosctp_sockcache, kmflags); 142 if (ss == NULL) { 143 *errorp = ENOMEM; 144 return (NULL); 145 } 146 147 so = &ss->ss_so; 148 149 ss->ss_maxassoc = 0; 150 ss->ss_assoccnt = 0; 151 ss->ss_assocs = NULL; 152 153 if (type == SOCK_STREAM) { 154 sonode_init(so, sp, family, type, protocol, 155 &sosctp_sonodeops); 156 } else { 157 sonode_init(so, sp, family, type, protocol, 158 &sosctp_seq_sonodeops); 159 ASSERT(type == SOCK_SEQPACKET); 160 mutex_enter(&so->so_lock); 161 (void) sosctp_aid_grow(ss, 1, kmflags); 162 mutex_exit(&so->so_lock); 163 } 164 165 if (version == SOV_DEFAULT) { 166 version = so_default_version; 167 } 168 so->so_version = (short)version; 169 170 dprint(2, ("sosctp_create: %p domain %d type %d\n", (void *)so, family, 171 type)); 172 173 return (so); 174 } 175 176 /* 177 * Free SCTP socket data structure. 178 */ 179 void 180 socksctp_destroy(struct sonode *so) 181 { 182 struct sctp_sonode *ss; 183 184 ASSERT((so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET) && 185 so->so_protocol == IPPROTO_SCTP); 186 187 sosctp_fini(so, CRED()); 188 189 ss = SOTOSSO(so); 190 kmem_cache_free(sosctp_sockcache, ss); 191 } 192 193 int 194 _init(void) 195 { 196 int error = 0; 197 198 (void) socksctp_init(); 199 200 if ((error = mod_install(&modlinkage)) != 0) 201 socksctp_fini(); 202 203 return (error); 204 } 205 206 int 207 _fini(void) 208 { 209 int error = 0; 210 211 if ((error = mod_remove(&modlinkage)) == 0) 212 socksctp_fini(); 213 214 return (error); 215 } 216 217 int 218 _info(struct modinfo *modinfop) 219 { 220 return (mod_info(&modlinkage, modinfop)); 221 } 222