Home | History | Annotate | Download | only in syscall
      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