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