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