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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <sys/types.h> 34 #include <sys/sysmacros.h> 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/errno.h> 38 #include <sys/vnode.h> 39 #include <sys/file.h> 40 #include <sys/proc.h> 41 #include <sys/stropts.h> 42 #include <sys/stream.h> 43 #include <sys/strsubr.h> 44 #include <sys/fs/fifonode.h> 45 #include <sys/socket.h> 46 #include <sys/socketvar.h> 47 #include <sys/debug.h> 48 49 /* 50 * STREAMS system calls. 51 */ 52 53 int getmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *flagsp); 54 int putmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int flags); 55 int getpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *prip, 56 int *flagsp); 57 int putpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int pri, 58 int flags); 59 60 static int msgio(int fdes, struct strbuf *ctl, struct strbuf *data, int *rval, 61 int mode, unsigned char *prip, int *flagsp); 62 63 int 64 getmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *flagsp) 65 { 66 int error; 67 int localflags; 68 int realflags = 0; 69 unsigned char pri = 0; 70 int rv = 0; 71 72 /* 73 * Convert between old flags (localflags) and new flags (realflags). 74 */ 75 if (copyin(flagsp, &localflags, sizeof (*flagsp))) 76 return (set_errno(EFAULT)); 77 switch (localflags) { 78 case 0: 79 realflags = MSG_ANY; 80 break; 81 82 case RS_HIPRI: 83 realflags = MSG_HIPRI; 84 break; 85 86 default: 87 return (set_errno(EINVAL)); 88 } 89 90 if ((error = msgio(fdes, ctl, data, &rv, FREAD, &pri, 91 &realflags)) == 0) { 92 /* 93 * massage realflags based on localflags. 94 */ 95 if (realflags == MSG_HIPRI) 96 localflags = RS_HIPRI; 97 else 98 localflags = 0; 99 if (copyout(&localflags, flagsp, sizeof (*flagsp))) 100 error = EFAULT; 101 } 102 if (error != 0) 103 return (set_errno(error)); 104 return (rv); 105 } 106 107 int 108 putmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int flags) 109 { 110 unsigned char pri = 0; 111 int realflags; 112 int error; 113 int rv = 0; 114 115 switch (flags) { 116 case RS_HIPRI: 117 realflags = MSG_HIPRI; 118 break; 119 case (RS_HIPRI|MSG_XPG4): 120 realflags = MSG_HIPRI|MSG_XPG4; 121 break; 122 case MSG_XPG4: 123 realflags = MSG_BAND|MSG_XPG4; 124 break; 125 case 0: 126 realflags = MSG_BAND; 127 break; 128 129 default: 130 return (set_errno(EINVAL)); 131 } 132 error = msgio(fdes, ctl, data, &rv, FWRITE, &pri, &realflags); 133 if (error != 0) 134 return (set_errno(error)); 135 return (rv); 136 } 137 138 139 int 140 getpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *prip, 141 int *flagsp) 142 { 143 int error; 144 int flags; 145 int intpri; 146 unsigned char pri; 147 int rv = 0; 148 149 if (copyin(flagsp, &flags, sizeof (flags))) 150 return (set_errno(EFAULT)); 151 if (copyin(prip, &intpri, sizeof (intpri))) 152 return (set_errno(EFAULT)); 153 if ((intpri > 255) || (intpri < 0)) 154 return (set_errno(EINVAL)); 155 pri = (unsigned char)intpri; 156 error = msgio(fdes, ctl, data, &rv, FREAD, &pri, &flags); 157 if (error != 0) 158 return (set_errno(error)); 159 if (copyout(&flags, flagsp, sizeof (flags))) 160 return (set_errno(EFAULT)); 161 intpri = (int)pri; 162 if (copyout(&intpri, prip, sizeof (intpri))) 163 return (set_errno(EFAULT)); 164 return (rv); 165 } 166 167 int 168 putpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int intpri, 169 int flags) 170 { 171 unsigned char pri; 172 int rv = 0; 173 int error; 174 175 if ((intpri > 255) || (intpri < 0)) 176 return (set_errno(EINVAL)); 177 pri = (unsigned char)intpri; 178 error = msgio(fdes, ctl, data, &rv, FWRITE, &pri, &flags); 179 if (error != 0) 180 return (set_errno(error)); 181 return (rv); 182 } 183 184 /* 185 * Common code for getmsg and putmsg calls: check permissions, 186 * copy in args, do preliminary setup, and switch to 187 * appropriate stream routine. 188 */ 189 static int 190 msgio(int fdes, struct strbuf *ctl, struct strbuf *data, int *rval, 191 int mode, unsigned char *prip, int *flagsp) 192 { 193 file_t *fp; 194 vnode_t *vp; 195 struct strbuf msgctl, msgdata; 196 int error; 197 int flag; 198 klwp_t *lwp = ttolwp(curthread); 199 rval_t rv; 200 201 if ((fp = getf(fdes)) == NULL) 202 return (EBADF); 203 if ((fp->f_flag & mode) == 0) { 204 releasef(fdes); 205 return (EBADF); 206 } 207 vp = fp->f_vnode; 208 if (vp->v_type == VFIFO) { 209 if (vp->v_stream) { 210 /* 211 * must use sd_vnode, could be named pipe 212 */ 213 (void) fifo_vfastoff(vp->v_stream->sd_vnode); 214 } else { 215 releasef(fdes); 216 return (ENOSTR); 217 } 218 } else if ((vp->v_type != VCHR && vp->v_type != VSOCK) || 219 vp->v_stream == NULL) { 220 releasef(fdes); 221 return (ENOSTR); 222 } 223 if ((ctl != NULL) && 224 copyin(ctl, &msgctl, sizeof (struct strbuf))) { 225 releasef(fdes); 226 return (EFAULT); 227 } 228 if ((data != NULL) && 229 copyin(data, &msgdata, sizeof (struct strbuf))) { 230 releasef(fdes); 231 return (EFAULT); 232 } 233 234 if (mode == FREAD) { 235 if (ctl == NULL) 236 msgctl.maxlen = -1; 237 if (data == NULL) 238 msgdata.maxlen = -1; 239 flag = fp->f_flag; 240 rv.r_val1 = 0; 241 if (vp->v_type == VSOCK) { 242 error = sock_getmsg(vp, &msgctl, &msgdata, prip, 243 flagsp, flag, &rv); 244 } else { 245 error = strgetmsg(vp, &msgctl, &msgdata, prip, 246 flagsp, flag, &rv); 247 } 248 *rval = rv.r_val1; 249 if (error != 0) { 250 releasef(fdes); 251 return (error); 252 } 253 if (lwp != NULL) 254 lwp->lwp_ru.msgrcv++; 255 if (((ctl != NULL) && 256 copyout(&msgctl, ctl, sizeof (struct strbuf))) || 257 ((data != NULL) && 258 copyout(&msgdata, data, sizeof (struct strbuf)))) { 259 releasef(fdes); 260 return (EFAULT); 261 } 262 releasef(fdes); 263 return (0); 264 } 265 266 /* 267 * FWRITE case 268 */ 269 if (ctl == NULL) 270 msgctl.len = -1; 271 if (data == NULL) 272 msgdata.len = -1; 273 flag = fp->f_flag; 274 if (vp->v_type == VSOCK) { 275 error = sock_putmsg(vp, &msgctl, &msgdata, *prip, *flagsp, 276 flag); 277 } else { 278 error = strputmsg(vp, &msgctl, &msgdata, *prip, *flagsp, flag); 279 } 280 releasef(fdes); 281 if (error == 0 && lwp != NULL) 282 lwp->lwp_ru.msgsnd++; 283 return (error); 284 } 285 286 287 #if defined(_LP64) && defined(_SYSCALL32) 288 289 static int msgio32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, 290 int *rval, int mode, unsigned char *prip, int *flagsp); 291 292 int 293 getmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t *flagsp) 294 { 295 int error; 296 int32_t localflags; 297 int realflags = 0; 298 unsigned char pri = 0; 299 int rv = 0; 300 301 /* 302 * Convert between old flags (localflags) and new flags (realflags). 303 */ 304 if (copyin(flagsp, &localflags, sizeof (*flagsp))) 305 return (set_errno(EFAULT)); 306 switch (localflags) { 307 case 0: 308 realflags = MSG_ANY; 309 break; 310 311 case RS_HIPRI: 312 realflags = MSG_HIPRI; 313 break; 314 315 default: 316 return (set_errno(EINVAL)); 317 } 318 319 if ((error = msgio32(fdes, ctl, data, &rv, FREAD, &pri, 320 &realflags)) == 0) { 321 /* 322 * massage realflags based on localflags. 323 */ 324 if (realflags == MSG_HIPRI) 325 localflags = RS_HIPRI; 326 else 327 localflags = 0; 328 if (copyout(&localflags, flagsp, sizeof (*flagsp))) 329 error = EFAULT; 330 } 331 if (error != 0) 332 return (set_errno(error)); 333 return (rv); 334 } 335 336 int 337 putmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t flags) 338 { 339 unsigned char pri = 0; 340 int realflags; 341 int error; 342 int rv = 0; 343 344 switch (flags) { 345 case RS_HIPRI: 346 realflags = MSG_HIPRI; 347 break; 348 case (RS_HIPRI|MSG_XPG4): 349 realflags = MSG_HIPRI|MSG_XPG4; 350 break; 351 case MSG_XPG4: 352 realflags = MSG_BAND|MSG_XPG4; 353 break; 354 case 0: 355 realflags = MSG_BAND; 356 break; 357 358 default: 359 return (set_errno(EINVAL)); 360 } 361 error = msgio32(fdes, ctl, data, &rv, FWRITE, &pri, &realflags); 362 if (error != 0) 363 return (set_errno(error)); 364 return (rv); 365 } 366 367 368 int 369 getpmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t *prip, 370 int32_t *flagsp) 371 { 372 int error; 373 int32_t flags; 374 int32_t intpri; 375 unsigned char pri; 376 int rv = 0; 377 378 if (copyin(flagsp, &flags, sizeof (*flagsp))) 379 return (set_errno(EFAULT)); 380 if (copyin(prip, &intpri, sizeof (intpri))) 381 return (set_errno(EFAULT)); 382 if ((intpri > 255) || (intpri < 0)) 383 return (set_errno(EINVAL)); 384 pri = (unsigned char)intpri; 385 error = msgio32(fdes, ctl, data, &rv, FREAD, &pri, &flags); 386 if (error != 0) 387 return (set_errno(error)); 388 if (copyout(&flags, flagsp, sizeof (flags))) 389 return (set_errno(EFAULT)); 390 intpri = (int)pri; 391 if (copyout(&intpri, prip, sizeof (intpri))) 392 return (set_errno(EFAULT)); 393 return (rv); 394 } 395 396 int 397 putpmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t intpri, 398 int32_t flags) 399 { 400 unsigned char pri; 401 int rv = 0; 402 int error; 403 404 if ((intpri > 255) || (intpri < 0)) 405 return (set_errno(EINVAL)); 406 pri = (unsigned char)intpri; 407 error = msgio32(fdes, ctl, data, &rv, FWRITE, &pri, &flags); 408 if (error != 0) 409 return (set_errno(error)); 410 return (rv); 411 } 412 413 /* 414 * Common code for getmsg and putmsg calls: check permissions, 415 * copy in args, do preliminary setup, and switch to 416 * appropriate stream routine. 417 */ 418 static int 419 msgio32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int *rval, 420 int mode, unsigned char *prip, int *flagsp) 421 { 422 file_t *fp; 423 vnode_t *vp; 424 struct strbuf32 msgctl32, msgdata32; 425 struct strbuf msgctl, msgdata; 426 int error; 427 int flag; 428 klwp_t *lwp = ttolwp(curthread); 429 rval_t rv; 430 431 if ((fp = getf(fdes)) == NULL) 432 return (EBADF); 433 if ((fp->f_flag & mode) == 0) { 434 releasef(fdes); 435 return (EBADF); 436 } 437 vp = fp->f_vnode; 438 if (vp->v_type == VFIFO) { 439 if (vp->v_stream) { 440 /* 441 * must use sd_vnode, could be named pipe 442 */ 443 (void) fifo_vfastoff(vp->v_stream->sd_vnode); 444 } else { 445 releasef(fdes); 446 return (ENOSTR); 447 } 448 } else if ((vp->v_type != VCHR && vp->v_type != VSOCK) || 449 vp->v_stream == NULL) { 450 releasef(fdes); 451 return (ENOSTR); 452 } 453 if (ctl != NULL) { 454 if (copyin(ctl, &msgctl32, sizeof (msgctl32))) { 455 releasef(fdes); 456 return (EFAULT); 457 } 458 msgctl.len = msgctl32.len; 459 msgctl.maxlen = msgctl32.maxlen; 460 msgctl.buf = (caddr_t)(uintptr_t)msgctl32.buf; 461 } 462 if (data != NULL) { 463 if (copyin(data, &msgdata32, sizeof (msgdata32))) { 464 releasef(fdes); 465 return (EFAULT); 466 } 467 msgdata.len = msgdata32.len; 468 msgdata.maxlen = msgdata32.maxlen; 469 msgdata.buf = (caddr_t)(uintptr_t)msgdata32.buf; 470 } 471 472 if (mode == FREAD) { 473 if (ctl == NULL) 474 msgctl.maxlen = -1; 475 if (data == NULL) 476 msgdata.maxlen = -1; 477 flag = fp->f_flag; 478 rv.r_val1 = 0; 479 if (vp->v_type == VSOCK) { 480 error = sock_getmsg(vp, &msgctl, &msgdata, prip, 481 flagsp, flag, &rv); 482 } else { 483 error = strgetmsg(vp, &msgctl, &msgdata, prip, 484 flagsp, flag, &rv); 485 } 486 *rval = rv.r_val1; 487 if (error != 0) { 488 releasef(fdes); 489 return (error); 490 } 491 if (lwp != NULL) 492 lwp->lwp_ru.msgrcv++; 493 if (ctl != NULL) { 494 /* XX64 - range check */ 495 msgctl32.len = msgctl.len; 496 msgctl32.maxlen = msgctl.maxlen; 497 msgctl32.buf = (caddr32_t)(uintptr_t)msgctl.buf; 498 if (copyout(&msgctl32, ctl, sizeof (msgctl32))) { 499 releasef(fdes); 500 return (EFAULT); 501 } 502 } 503 if (data != NULL) { 504 /* XX64 - range check */ 505 msgdata32.len = msgdata.len; 506 msgdata32.maxlen = msgdata.maxlen; 507 msgdata32.buf = (caddr32_t)(uintptr_t)msgdata.buf; 508 if (copyout(&msgdata32, data, sizeof (msgdata32))) { 509 releasef(fdes); 510 return (EFAULT); 511 } 512 } 513 releasef(fdes); 514 return (0); 515 } 516 517 /* 518 * FWRITE case 519 */ 520 if (ctl == NULL) 521 msgctl.len = -1; 522 if (data == NULL) 523 msgdata.len = -1; 524 flag = fp->f_flag; 525 if (vp->v_type == VSOCK) { 526 error = sock_putmsg(vp, &msgctl, &msgdata, *prip, *flagsp, 527 flag); 528 } else { 529 error = strputmsg(vp, &msgctl, &msgdata, *prip, *flagsp, flag); 530 } 531 releasef(fdes); 532 if (error == 0 && lwp != NULL) 533 lwp->lwp_ru.msgsnd++; 534 return (error); 535 } 536 537 #endif /* _LP64 && _SYSCALL32 */ 538