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,
  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         /*
 174          * set the default values to be INFPSZ
 175          * if a protocol desires it can change the value later
 176          */
 177         so->so_proto_props.sopp_rxhiwat = SOCKET_RECVHIWATER;
 178         so->so_proto_props.sopp_rxlowat = SOCKET_RECVLOWATER;
 179         so->so_proto_props.sopp_maxpsz = INFPSZ;
 180         so->so_proto_props.sopp_maxblk = INFPSZ;
 181 
 182         return (so);
 183 }
 184 
 185 /*
 186  * Free SCTP socket data structure.
 187  */
 188 void
 189 socksctp_destroy(struct sonode *so)
 190 {
 191         struct sctp_sonode *ss;
 192 
 193         ASSERT((so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET) &&
 194             so->so_protocol == IPPROTO_SCTP);
 195 
 196         sosctp_fini(so, CRED());
 197 
 198         ss = SOTOSSO(so);
 199         kmem_cache_free(sosctp_sockcache, ss);
 200 }
 201 
 202 int
 203 _init(void)
 204 {
 205         int error = 0;
 206 
 207         (void) socksctp_init();
 208 
 209         if ((error = mod_install(&modlinkage)) != 0)
 210                 socksctp_fini();
 211 
 212         return (error);
 213 }
 214 
 215 int
 216 _fini(void)
 217 {
 218         int error = 0;
 219 
 220         if ((error = mod_remove(&modlinkage)) == 0)
 221                 socksctp_fini();
 222 
 223         return (error);
 224 }
 225 
 226 int
 227 _info(struct modinfo *modinfop)
 228 {
 229         return (mod_info(&modlinkage, modinfop));
 230 }