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