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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <sys/types.h> 28 #include <sys/conf.h> 29 #include <sys/modctl.h> 30 #include <sys/stat.h> 31 #include <sys/stream.h> 32 #include <sys/strsun.h> 33 #include <sys/stropts.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/sunldi.h> 37 #include <sys/file.h> 38 #include <sys/priv_names.h> 39 #include <inet/common.h> 40 41 #define _SUN_TPI_VERSION 2 42 #include <sys/tihdr.h> 43 #include <sys/timod.h> 44 #include <sys/tiuser.h> 45 #include <sys/suntpi.h> 46 #include <sys/socket.h> 47 #include <sys/sockio.h> 48 #include <inet/common.h> 49 #include <inet/ip.h> 50 #include <inet/mi.h> 51 #include <sys/policy.h> 52 #include "sys/random.h" 53 #include <inet/sdp_itf.h> 54 #include <sys/ib/ibtl/ibti.h> 55 56 57 /* 58 * This is a pseudo driver which creates an entry for /dev/sdp in the device 59 * tree. A regular installation will end up modifying sock2path file announcing 60 * support for sdp using AF_INET/SOCK_STREAM/PROTO_SDP parameters in socket 61 * call. On a non IB hardware, following are the constraints within which 62 * the sdp project operates. The sdpib driver which is the real driver 63 * (in terms of moving data) should not be loaded since it has dependency on 64 * ibcm and ibtl modules which will be loaded in the memory. This will consume 65 * precious memory and needs to be avoided. As a result the sdpib driver 66 * should fail its init() call to disallow loading on other modules. Due to 67 * this we do not get a chance to create a /dev/sdp entry in the device tree 68 * in the regular sdpib driver. During the boottime, this will cause a warning 69 * message when soconfig processes the entry for sdp in sock2path file . In 70 * order to avoid this a pseudo driver is introduced which creates an entry 71 * for /dev/sdp regardless of the hardware. When a socket call is made on the 72 * sdp subsystem, the call will end up in this driver, which then forwards 73 * this call to the real sdp driver. On a non-ib hardware system the call 74 * will fail 75 */ 76 77 #define SDP_NAME "sdp" 78 #define SDP_DEVDESC "SDP STREAMS driver" 79 #define SDP_DEVMINOR 0 80 81 static dev_info_t *sdp_dev_info; 82 83 ldi_ident_t sdp_li; 84 krwlock_t sdp_transport_lock; 85 ldi_handle_t sdp_transport_handle = NULL; 86 87 static int 88 sdp_gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 89 { 90 int ret; 91 92 if (cmd != DDI_ATTACH) 93 return (DDI_FAILURE); 94 95 sdp_dev_info = devi; 96 97 ret = ddi_create_minor_node(devi, SDP_NAME, S_IFCHR, 98 SDP_DEVMINOR, DDI_PSEUDO, 0); 99 if (ret != DDI_SUCCESS) { 100 return (ret); 101 } 102 return (DDI_SUCCESS); 103 } 104 105 static int 106 sdp_gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 107 { 108 if (cmd != DDI_DETACH) 109 return (DDI_FAILURE); 110 111 ASSERT(devi == sdp_dev_info); 112 113 ddi_remove_minor_node(devi, NULL); 114 115 return (DDI_SUCCESS); 116 } 117 118 /* open routine. */ 119 /*ARGSUSED*/ 120 static int 121 sdp_gen_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 122 { 123 qprocson(q); 124 qenable(q); 125 return (0); 126 } 127 128 /* open routine. */ 129 /*ARGSUSED*/ 130 static int 131 sdp_gen_close(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 132 { 133 qprocsoff(q); 134 return (0); 135 } 136 137 static int 138 sdp_open_sdpib_driver() 139 { 140 int ret = 0; 141 142 rw_enter(&sdp_transport_lock, RW_WRITER); 143 if (sdp_transport_handle != 0) { 144 /* 145 * Someone beat us to it. 146 */ 147 goto done; 148 } 149 150 if (ibt_hw_is_present() == 0) { 151 ret = ENODEV; 152 goto done; 153 } 154 155 if (sdp_li == NULL) { 156 ret = EPROTONOSUPPORT; 157 goto done; 158 } 159 160 ret = ldi_open_by_name("/devices/ib/sdpib@0:sdpib", 161 FREAD | FWRITE, kcred, &sdp_transport_handle, sdp_li); 162 if (ret != 0) { 163 ret = EPROTONOSUPPORT; 164 sdp_transport_handle = NULL; 165 goto done; 166 } 167 168 done: 169 rw_exit(&sdp_transport_lock); 170 return (ret); 171 } 172 173 174 static void 175 sdp_gen_ioctl(queue_t *q, mblk_t *mp) 176 { 177 struct iocblk *iocp; 178 int32_t enable = 0; 179 int ret; 180 boolean_t priv = B_TRUE; 181 182 /* LINTED */ 183 iocp = (struct iocblk *)mp->b_rptr; 184 switch (iocp->ioc_cmd) { 185 case SIOCSENABLESDP: 186 bcopy(mp->b_cont->b_rptr, &enable, sizeof (int)); 187 188 /* 189 * Check for root privs. 190 * if not net config privs - return state of system SDP 191 */ 192 if (secpolicy_net_config(CRED(), B_FALSE) != 0) { 193 priv = B_FALSE; 194 } 195 196 197 /* 198 * The sdpib driver is loaded if root enables sdp the 199 * first time (sdp_transport_handle is NULL). It is 200 * unloaded during the following first disable. At all 201 * other times for root as well as non-root users, the 202 * action of enabling/disabling sdp is simply acked. 203 */ 204 rw_enter(&sdp_transport_lock, RW_READER); 205 if ((enable == 1) && (sdp_transport_handle == NULL) && 206 (priv == B_TRUE)) { 207 /* Initialize sdpib transport driver */ 208 rw_exit(&sdp_transport_lock); 209 ret = sdp_open_sdpib_driver(); 210 rw_enter(&sdp_transport_lock, 211 RW_READER); 212 if (ret != 0) { 213 /* Transport failed to load */ 214 rw_exit(&sdp_transport_lock); 215 enable = 0; 216 goto done; 217 } 218 (void) sdp_ioctl(NULL, iocp->ioc_cmd, &enable, 219 CRED()); 220 } else if ((enable == 0) && 221 (sdp_transport_handle != NULL) && 222 (priv == B_TRUE)) { 223 (void) sdp_ioctl(NULL, iocp->ioc_cmd, &enable, 224 CRED()); 225 (void) ldi_close(sdp_transport_handle, 226 FNDELAY, kcred); 227 sdp_transport_handle = NULL; 228 } else { 229 ret = sdp_ioctl(NULL, iocp->ioc_cmd, &enable, 230 CRED()); 231 if (ret == EINVAL) 232 enable = 0; 233 } 234 rw_exit(&sdp_transport_lock); 235 236 done: 237 bcopy(&enable, mp->b_cont->b_rptr, sizeof (int)); 238 239 /* ACK the ioctl */ 240 mp->b_datap->db_type = M_IOCACK; 241 iocp->ioc_count = sizeof (int); 242 qreply(q, mp); 243 break; 244 default: 245 miocnak(q, mp, 0, ENOTSUP); 246 } 247 } 248 249 /* 250 * Received a put from sockfs. We only support ndd get/set 251 */ 252 static void 253 sdp_gen_wput(queue_t *q, mblk_t *mp) 254 { 255 switch (mp->b_datap->db_type) { 256 case M_IOCTL: 257 sdp_gen_ioctl(q, mp); 258 break; 259 case M_FLUSH: 260 *mp->b_rptr &= ~FLUSHW; 261 if (*mp->b_rptr & FLUSHR) 262 qreply(q, mp); 263 else 264 freemsg(mp); 265 break; 266 default: 267 freemsg(mp); 268 return; 269 } 270 } 271 272 static struct module_info info = { 273 0, "sdp", 1, INFPSZ, 65536, 1024 274 }; 275 276 static struct qinit rinit = { 277 NULL, (pfi_t)NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, NULL, 278 &info, NULL, NULL, NULL, STRUIOT_NONE 279 }; 280 281 static struct qinit winit = { 282 (pfi_t)sdp_gen_wput, NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, 283 NULL, &info, NULL, NULL, NULL, STRUIOT_NONE 284 }; 285 286 struct streamtab sdpinfo = { 287 &rinit, &winit, NULL, NULL 288 }; 289 290 DDI_DEFINE_STREAM_OPS(sdp_devops, nulldev, nulldev, sdp_gen_attach, 291 sdp_gen_detach, nodev, NULL, D_MP, &sdpinfo, ddi_quiesce_not_needed); 292 293 /* 294 * Module linkage information for the kernel. 295 */ 296 static struct modldrv modldrv = { 297 &mod_driverops, 298 SDP_DEVDESC, 299 &sdp_devops 300 }; 301 302 static struct modlinkage modlinkage = { 303 MODREV_1, 304 &modldrv, 305 NULL 306 }; 307 308 int 309 _init(void) 310 { 311 int ret; 312 313 ret = mod_install(&modlinkage); 314 if (ret != 0) 315 goto done; 316 ret = ldi_ident_from_mod(&modlinkage, &sdp_li); 317 if (ret != 0) 318 sdp_li = NULL; 319 done: 320 return (ret); 321 } 322 323 int 324 _fini(void) 325 { 326 int ret; 327 328 ret = mod_remove(&modlinkage); 329 if (ret != 0) { 330 return (ret); 331 } 332 333 ldi_ident_release(sdp_li); 334 return (0); 335 } 336 337 int 338 _info(struct modinfo *modinfop) 339 { 340 return (mod_info(&modlinkage, modinfop)); 341 } 342