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
getmsg(int fdes,struct strbuf * ctl,struct strbuf * data,int * flagsp)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
putmsg(int fdes,struct strbuf * ctl,struct strbuf * data,int flags)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
getpmsg(int fdes,struct strbuf * ctl,struct strbuf * data,int * prip,int * flagsp)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
putpmsg(int fdes,struct strbuf * ctl,struct strbuf * data,int intpri,int flags)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
msgio(int fdes,struct strbuf * ctl,struct strbuf * data,int * rval,int mode,unsigned char * prip,int * flagsp)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
getmsg32(int fdes,struct strbuf32 * ctl,struct strbuf32 * data,int32_t * flagsp)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
putmsg32(int fdes,struct strbuf32 * ctl,struct strbuf32 * data,int32_t flags)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
getpmsg32(int fdes,struct strbuf32 * ctl,struct strbuf32 * data,int32_t * prip,int32_t * flagsp)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
putpmsg32(int fdes,struct strbuf32 * ctl,struct strbuf32 * data,int32_t intpri,int32_t flags)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
msgio32(int fdes,struct strbuf32 * ctl,struct strbuf32 * data,int * rval,int mode,unsigned char * prip,int * flagsp)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