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 2007 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/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 %I%" 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 default: 260 return; 261 } 262 } 263 264 static struct module_info info = { 265 0, "sdp", 1, INFPSZ, 65536, 1024 266 }; 267 268 static struct qinit rinit = { 269 NULL, (pfi_t)NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, NULL, 270 &info, NULL, NULL, NULL, STRUIOT_NONE 271 }; 272 273 static struct qinit winit = { 274 (pfi_t)sdp_gen_wput, NULL, (pfi_t)sdp_gen_open, (pfi_t)sdp_gen_close, 275 NULL, &info, NULL, NULL, NULL, STRUIOT_NONE 276 }; 277 278 struct streamtab sdpinfo = { 279 &rinit, &winit, NULL, NULL 280 }; 281 282 /* Stream operations */ 283 static struct streamtab sdp_streamtab = { 284 &rinit, /* read queue */ 285 &winit, /* write queue */ 286 }; 287 288 /* Character/block operations */ 289 static struct cb_ops sdp_cb_ops = { 290 nodev, /* open */ 291 nodev, /* close */ 292 nodev, /* strategy */ 293 nodev, /* print */ 294 nodev, /* dump */ 295 nodev, /* read */ 296 nodev, /* write */ 297 nodev, /* ioctl */ 298 nodev, /* devmap */ 299 nodev, /* mmap */ 300 nodev, /* segmap */ 301 nochpoll, /* chpoll */ 302 ddi_prop_op, /* prop_op (sun DDI-specific) */ 303 &sdp_streamtab, /* streams */ 304 D_MP, 305 CB_REV 306 }; 307 308 /* Driver operations */ 309 static struct dev_ops sdp_devops = { 310 DEVO_REV, /* struct rev */ 311 0, /* refcnt */ 312 nodev, /* getinfo */ 313 nulldev, /* identify */ 314 nulldev, /* probe */ 315 sdp_gen_attach, /* attach */ 316 sdp_gen_detach, /* detach */ 317 nodev, /* reset */ 318 &sdp_cb_ops, /* cb_ops */ 319 NULL, /* bus_ops */ 320 nodev /* power */ 321 }; 322 323 /* 324 * Module linkage information for the kernel. 325 */ 326 static struct modldrv modldrv = { 327 &mod_driverops, 328 SDP_DEVDESC, 329 &sdp_devops 330 }; 331 332 static struct modlinkage modlinkage = { 333 MODREV_1, 334 &modldrv, 335 NULL 336 }; 337 338 int 339 _init(void) 340 { 341 int ret; 342 343 ret = mod_install(&modlinkage); 344 if (ret != 0) 345 goto done; 346 ret = ldi_ident_from_mod(&modlinkage, &sdp_li); 347 if (ret != 0) 348 sdp_li = NULL; 349 done: 350 return (ret); 351 } 352 353 int 354 _fini(void) 355 { 356 int ret; 357 358 ret = mod_remove(&modlinkage); 359 if (ret != 0) { 360 return (ret); 361 } 362 363 ldi_ident_release(sdp_li); 364 return (0); 365 } 366 367 int 368 _info(struct modinfo *modinfop) 369 { 370 return (mod_info(&modlinkage, modinfop)); 371 } 372