1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/param.h> 30*0Sstevel@tonic-gate #include <sys/types.h> 31*0Sstevel@tonic-gate #include <sys/user.h> 32*0Sstevel@tonic-gate #include <sys/vfs.h> 33*0Sstevel@tonic-gate #include <sys/vnode.h> 34*0Sstevel@tonic-gate #include <sys/file.h> 35*0Sstevel@tonic-gate #include <sys/stream.h> 36*0Sstevel@tonic-gate #include <sys/stropts.h> 37*0Sstevel@tonic-gate #include <sys/strsubr.h> 38*0Sstevel@tonic-gate #include <sys/dlpi.h> 39*0Sstevel@tonic-gate #include <sys/vnode.h> 40*0Sstevel@tonic-gate #include <sys/socket.h> 41*0Sstevel@tonic-gate #include <sys/sockio.h> 42*0Sstevel@tonic-gate #include <sys/cmn_err.h> 43*0Sstevel@tonic-gate #include <net/if.h> 44*0Sstevel@tonic-gate #include <sys/sad.h> 45*0Sstevel@tonic-gate #include <sys/kstr.h> 46*0Sstevel@tonic-gate #include <sys/ddi.h> 47*0Sstevel@tonic-gate #include <sys/sunddi.h> 48*0Sstevel@tonic-gate #include <sys/sunldi.h> 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate #include <sys/cred.h> 51*0Sstevel@tonic-gate #include <sys/sysmacros.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #include <sys/modctl.h> 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate /* 56*0Sstevel@tonic-gate * Routines to allow strplumb() legitimate access 57*0Sstevel@tonic-gate * to the kernel. 58*0Sstevel@tonic-gate */ 59*0Sstevel@tonic-gate int 60*0Sstevel@tonic-gate kstr_open(major_t maj, minor_t min, vnode_t **vpp, int *fd) 61*0Sstevel@tonic-gate { 62*0Sstevel@tonic-gate vnode_t *vp; 63*0Sstevel@tonic-gate int error; 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate vp = makespecvp(makedevice(maj, min), VCHR); 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* 68*0Sstevel@tonic-gate * Fix for 4170365: only allocate file descriptor entry 69*0Sstevel@tonic-gate * if file descriptor is to be returned; otherwise VOP_OPEN. 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate if (fd != NULL) 72*0Sstevel@tonic-gate error = fassign(&vp, FREAD|FWRITE, fd); 73*0Sstevel@tonic-gate else 74*0Sstevel@tonic-gate error = VOP_OPEN(&vp, FREAD|FWRITE, CRED()); 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * Must set vpp after calling fassign()/VOP_OPEN() 78*0Sstevel@tonic-gate * since `vp' might change if it's a clone driver. 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate if (vpp != NULL) 81*0Sstevel@tonic-gate *vpp = vp; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate return (error); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate int 87*0Sstevel@tonic-gate kstr_plink(vnode_t *vp, int fd, int *mux_id) 88*0Sstevel@tonic-gate { 89*0Sstevel@tonic-gate int id; 90*0Sstevel@tonic-gate int error; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate if (error = strioctl(vp, I_PLINK, (intptr_t)fd, 0, K_TO_K, CRED(), &id)) 93*0Sstevel@tonic-gate return (error); 94*0Sstevel@tonic-gate if (mux_id) 95*0Sstevel@tonic-gate *mux_id = id; 96*0Sstevel@tonic-gate return (0); 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate int 100*0Sstevel@tonic-gate kstr_unplink(vnode_t *vp, int mux_id) 101*0Sstevel@tonic-gate { 102*0Sstevel@tonic-gate int rval; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate return (strioctl(vp, I_PUNLINK, (intptr_t)mux_id, 0, 105*0Sstevel@tonic-gate K_TO_K, CRED(), &rval)); 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate int 109*0Sstevel@tonic-gate kstr_push(vnode_t *vp, char *mod) 110*0Sstevel@tonic-gate { 111*0Sstevel@tonic-gate int rval; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate return (strioctl(vp, I_PUSH, (intptr_t)mod, 0, K_TO_K, CRED(), &rval)); 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate int 117*0Sstevel@tonic-gate kstr_pop(vnode_t *vp) 118*0Sstevel@tonic-gate { 119*0Sstevel@tonic-gate int rval; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate return (strioctl(vp, I_POP, 0, 0, K_TO_K, CRED(), &rval)); 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate int 125*0Sstevel@tonic-gate kstr_close(vnode_t *vp, int fd) 126*0Sstevel@tonic-gate { 127*0Sstevel@tonic-gate int ret; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if (vp == (vnode_t *)NULL && fd == -1) 130*0Sstevel@tonic-gate return (EINVAL); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate if (fd != -1) { 133*0Sstevel@tonic-gate if (closeandsetf(fd, NULL) == 0) { 134*0Sstevel@tonic-gate return (0); 135*0Sstevel@tonic-gate } else { 136*0Sstevel@tonic-gate return (EINVAL); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate } else { 139*0Sstevel@tonic-gate ret = VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED()); 140*0Sstevel@tonic-gate VN_RELE(vp); 141*0Sstevel@tonic-gate return (ret); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate int 146*0Sstevel@tonic-gate kstr_ioctl(struct vnode *vp, int cmd, intptr_t arg) 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate int rval; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate return (strioctl(vp, cmd, arg, 0, K_TO_K, CRED(), &rval)); 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate /* 154*0Sstevel@tonic-gate * Optionally send data (if smp set) and optionally receive data (if rmp is 155*0Sstevel@tonic-gate * set). If timeo is NULL the reception will sleep until a message is 156*0Sstevel@tonic-gate * received; otherwise the sleep is limited to the specified amount of time. 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate int 159*0Sstevel@tonic-gate kstr_msg(vnode_t *vp, mblk_t *smp, mblk_t **rmp, timestruc_t *timeo) 160*0Sstevel@tonic-gate { 161*0Sstevel@tonic-gate int error; 162*0Sstevel@tonic-gate clock_t timout; /* milliseconds */ 163*0Sstevel@tonic-gate uchar_t pri; 164*0Sstevel@tonic-gate int pflag; 165*0Sstevel@tonic-gate rval_t rval; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate if (rmp == NULL && timeo != NULL && 168*0Sstevel@tonic-gate (timeo->tv_sec != 0 || timeo->tv_nsec != 0)) 169*0Sstevel@tonic-gate return (EINVAL); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate if (smp == NULL && rmp == NULL) 172*0Sstevel@tonic-gate return (EINVAL); 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate if (smp != NULL) { 175*0Sstevel@tonic-gate /* Send message while honoring flow control */ 176*0Sstevel@tonic-gate (void) kstrputmsg(vp, smp, NULL, 0, 0, 177*0Sstevel@tonic-gate MSG_BAND | MSG_HOLDSIG | MSG_IGNERROR, 0); 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if (rmp == NULL) { 181*0Sstevel@tonic-gate /* No reply wanted by caller */ 182*0Sstevel@tonic-gate return (0); 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Convert from nanoseconds to milliseconds. 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate if (timeo != NULL) { 189*0Sstevel@tonic-gate timout = timeo->tv_sec * 1000 + timeo->tv_nsec / 1000000; 190*0Sstevel@tonic-gate if (timout > INT_MAX) 191*0Sstevel@tonic-gate return (EINVAL); 192*0Sstevel@tonic-gate } else 193*0Sstevel@tonic-gate timout = -1; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* Wait for timeout millseconds for a message */ 196*0Sstevel@tonic-gate pflag = MSG_ANY; 197*0Sstevel@tonic-gate pri = 0; 198*0Sstevel@tonic-gate *rmp = NULL; 199*0Sstevel@tonic-gate error = kstrgetmsg(vp, rmp, NULL, &pri, &pflag, timout, &rval); 200*0Sstevel@tonic-gate /* Callers use *rmp == NULL to determine that there was a timeout */ 201*0Sstevel@tonic-gate if (error == ETIME) 202*0Sstevel@tonic-gate error = 0; 203*0Sstevel@tonic-gate return (error); 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate #define SAD_ADM "/devices/pseudo/sad@0:admin" 207*0Sstevel@tonic-gate #define SAD_USR "/devices/pseudo/sad@0:user" 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * It is the callers responsibility to make sure that "mods" 211*0Sstevel@tonic-gate * conforms to what is required. We do not check it here. 212*0Sstevel@tonic-gate * 213*0Sstevel@tonic-gate * "maj", "min", and "lastmin" are value-result parameters. 214*0Sstevel@tonic-gate * for SET_AUTOPUSH, "anchor" should be set to the place in the stream 215*0Sstevel@tonic-gate * to put the anchor, or NULL if no anchor needs to be set. 216*0Sstevel@tonic-gate * for GET_AUTOPUSH, "anchor" should point to a uint_t to store the 217*0Sstevel@tonic-gate * position of the anchor at, or NULL if the caller is not interested. 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate int 220*0Sstevel@tonic-gate kstr_autopush(int op, major_t *maj, minor_t *min, minor_t *lastmin, 221*0Sstevel@tonic-gate uint_t *anchor, char *mods[]) 222*0Sstevel@tonic-gate { 223*0Sstevel@tonic-gate ldi_handle_t lh; 224*0Sstevel@tonic-gate ldi_ident_t li; 225*0Sstevel@tonic-gate struct strapush push; 226*0Sstevel@tonic-gate int i, error, rval; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate li = ldi_ident_from_anon(); 229*0Sstevel@tonic-gate if (op == SET_AUTOPUSH || op == CLR_AUTOPUSH) { 230*0Sstevel@tonic-gate error = ldi_open_by_name(SAD_ADM, FREAD|FWRITE, 231*0Sstevel@tonic-gate CRED(), &lh, li); 232*0Sstevel@tonic-gate if (error) { 233*0Sstevel@tonic-gate printf("kstr_autopush: open failed error %d\n", error); 234*0Sstevel@tonic-gate ldi_ident_release(li); 235*0Sstevel@tonic-gate return (error); 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate } else { 238*0Sstevel@tonic-gate error = ldi_open_by_name(SAD_USR, FREAD|FWRITE, 239*0Sstevel@tonic-gate CRED(), &lh, li); 240*0Sstevel@tonic-gate if (error) { 241*0Sstevel@tonic-gate printf("kstr_autopush: open failed error %d\n", error); 242*0Sstevel@tonic-gate ldi_ident_release(li); 243*0Sstevel@tonic-gate return (error); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate ldi_ident_release(li); 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate switch (op) { 249*0Sstevel@tonic-gate case GET_AUTOPUSH: 250*0Sstevel@tonic-gate /* Get autopush information */ 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate push.sap_major = *maj; 253*0Sstevel@tonic-gate push.sap_minor = *min; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate error = ldi_ioctl(lh, SAD_GAP, (intptr_t)&push, 256*0Sstevel@tonic-gate FKIOCTL, CRED(), &rval); 257*0Sstevel@tonic-gate if (error) { 258*0Sstevel@tonic-gate printf("kstr_autopush: ioctl failed, error %d\n", 259*0Sstevel@tonic-gate error); 260*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 261*0Sstevel@tonic-gate return (error); 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate switch (push.sap_cmd) { 264*0Sstevel@tonic-gate case SAP_ONE: 265*0Sstevel@tonic-gate *maj = push.sap_major; 266*0Sstevel@tonic-gate *min = push.sap_minor; 267*0Sstevel@tonic-gate *lastmin = 0; 268*0Sstevel@tonic-gate break; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate case SAP_RANGE: 271*0Sstevel@tonic-gate *maj = push.sap_major; 272*0Sstevel@tonic-gate *min = push.sap_minor; 273*0Sstevel@tonic-gate *lastmin = push.sap_lastminor; 274*0Sstevel@tonic-gate break; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate case SAP_ALL: 277*0Sstevel@tonic-gate *maj = push.sap_major; 278*0Sstevel@tonic-gate *min = (minor_t)-1; 279*0Sstevel@tonic-gate break; 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (anchor != NULL) 283*0Sstevel@tonic-gate *anchor = push.sap_anchor; 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate if (push.sap_npush > 1) { 286*0Sstevel@tonic-gate for (i = 0; i < push.sap_npush && 287*0Sstevel@tonic-gate mods[i] != NULL; i++) 288*0Sstevel@tonic-gate (void) strcpy(mods[i], push.sap_list[i]); 289*0Sstevel@tonic-gate mods[i] = NULL; 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 292*0Sstevel@tonic-gate return (0); 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate case CLR_AUTOPUSH: 295*0Sstevel@tonic-gate /* Remove autopush information */ 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate push.sap_cmd = SAP_CLEAR; 298*0Sstevel@tonic-gate push.sap_minor = *min; 299*0Sstevel@tonic-gate push.sap_major = *maj; 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate error = ldi_ioctl(lh, SAD_SAP, (intptr_t)&push, 302*0Sstevel@tonic-gate FKIOCTL, CRED(), &rval); 303*0Sstevel@tonic-gate if (error) { 304*0Sstevel@tonic-gate printf("kstr_autopush: ioctl failed, error %d\n", 305*0Sstevel@tonic-gate error); 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 308*0Sstevel@tonic-gate return (error); 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate case SET_AUTOPUSH: 311*0Sstevel@tonic-gate /* Set autopush information */ 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate if (*min == (minor_t)-1) { 314*0Sstevel@tonic-gate push.sap_cmd = SAP_ALL; 315*0Sstevel@tonic-gate } else if (*lastmin == 0) { 316*0Sstevel@tonic-gate push.sap_cmd = SAP_ONE; 317*0Sstevel@tonic-gate } else { 318*0Sstevel@tonic-gate push.sap_cmd = SAP_RANGE; 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate if (anchor != NULL) 322*0Sstevel@tonic-gate push.sap_anchor = *anchor; 323*0Sstevel@tonic-gate else 324*0Sstevel@tonic-gate push.sap_anchor = 0; 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate push.sap_minor = *min; 327*0Sstevel@tonic-gate push.sap_major = *maj; 328*0Sstevel@tonic-gate if (lastmin) 329*0Sstevel@tonic-gate push.sap_lastminor = *lastmin; 330*0Sstevel@tonic-gate else 331*0Sstevel@tonic-gate push.sap_lastminor = 0; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* pain */ 334*0Sstevel@tonic-gate for (i = 0; i < MAXAPUSH && mods[i] != (char *)NULL; i++) { 335*0Sstevel@tonic-gate (void) strcpy(push.sap_list[i], mods[i]); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate push.sap_npush = i; 338*0Sstevel@tonic-gate push.sap_list[i][0] = '\0'; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate error = ldi_ioctl(lh, SAD_SAP, (intptr_t)&push, 341*0Sstevel@tonic-gate FKIOCTL, CRED(), &rval); 342*0Sstevel@tonic-gate if (error) { 343*0Sstevel@tonic-gate printf("kstr_autopush: ioctl failed, error %d\n", 344*0Sstevel@tonic-gate error); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 347*0Sstevel@tonic-gate return (error); 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate default: 350*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 351*0Sstevel@tonic-gate return (EINVAL); 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate } 354