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 }