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