Annotation of sys/kern/uipc_syscalls.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uipc_syscalls.c,v 1.66 2006/10/23 07:13:56 henning Exp $ */
2: /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1982, 1986, 1989, 1990, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the University nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: *
32: * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94
33: */
34:
35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/filedesc.h>
38: #include <sys/proc.h>
39: #include <sys/file.h>
40: #include <sys/buf.h>
41: #include <sys/malloc.h>
42: #include <sys/event.h>
43: #include <sys/mbuf.h>
44: #include <sys/protosw.h>
45: #include <sys/socket.h>
46: #include <sys/socketvar.h>
47: #include <sys/signalvar.h>
48: #include <sys/unpcb.h>
49: #include <sys/un.h>
50: #ifdef KTRACE
51: #include <sys/ktrace.h>
52: #endif
53:
54: #include <sys/mount.h>
55: #include <sys/syscallargs.h>
56:
57: /*
58: * System call interface to the socket abstraction.
59: */
60: extern struct fileops socketops;
61:
62: int
63: sys_socket(struct proc *p, void *v, register_t *retval)
64: {
65: struct sys_socket_args /* {
66: syscallarg(int) domain;
67: syscallarg(int) type;
68: syscallarg(int) protocol;
69: } */ *uap = v;
70: struct filedesc *fdp = p->p_fd;
71: struct socket *so;
72: struct file *fp;
73: int fd, error;
74:
75: fdplock(fdp);
76:
77: if ((error = falloc(p, &fp, &fd)) != 0)
78: goto out;
79: fp->f_flag = FREAD|FWRITE;
80: fp->f_type = DTYPE_SOCKET;
81: fp->f_ops = &socketops;
82: error = socreate(SCARG(uap, domain), &so, SCARG(uap, type),
83: SCARG(uap, protocol));
84: if (error) {
85: fdremove(fdp, fd);
86: closef(fp, p);
87: } else {
88: fp->f_data = so;
89: FILE_SET_MATURE(fp);
90: *retval = fd;
91: }
92: out:
93: fdpunlock(fdp);
94: return (error);
95: }
96:
97: /* ARGSUSED */
98: int
99: sys_bind(struct proc *p, void *v, register_t *retval)
100: {
101: struct sys_bind_args /* {
102: syscallarg(int) s;
103: syscallarg(const struct sockaddr *) name;
104: syscallarg(socklen_t) namelen;
105: } */ *uap = v;
106: struct file *fp;
107: struct mbuf *nam;
108: int error;
109:
110: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
111: return (error);
112: error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
113: MT_SONAME);
114: if (error == 0) {
115: error = sobind(fp->f_data, nam);
116: m_freem(nam);
117: }
118: FRELE(fp);
119: return (error);
120: }
121:
122: /* ARGSUSED */
123: int
124: sys_listen(struct proc *p, void *v, register_t *retval)
125: {
126: struct sys_listen_args /* {
127: syscallarg(int) s;
128: syscallarg(int) backlog;
129: } */ *uap = v;
130: struct file *fp;
131: int error;
132:
133: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
134: return (error);
135: error = solisten(fp->f_data, SCARG(uap, backlog));
136: FRELE(fp);
137: return (error);
138: }
139:
140: int
141: sys_accept(struct proc *p, void *v, register_t *retval)
142: {
143: struct sys_accept_args /* {
144: syscallarg(int) s;
145: syscallarg(struct sockaddr *) name;
146: syscallarg(socklen_t *) anamelen;
147: } */ *uap = v;
148: struct file *fp, *headfp;
149: struct mbuf *nam;
150: socklen_t namelen;
151: int error, s, tmpfd;
152: struct socket *head, *so;
153: int nflag;
154:
155: if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen),
156: &namelen, sizeof (namelen))))
157: return (error);
158: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
159: return (error);
160: headfp = fp;
161: s = splsoftnet();
162: head = fp->f_data;
163: if ((head->so_options & SO_ACCEPTCONN) == 0) {
164: error = EINVAL;
165: goto bad;
166: }
167: if ((head->so_state & SS_NBIO) && head->so_qlen == 0) {
168: if (head->so_state & SS_CANTRCVMORE)
169: error = ECONNABORTED;
170: else
171: error = EWOULDBLOCK;
172: goto bad;
173: }
174: while (head->so_qlen == 0 && head->so_error == 0) {
175: if (head->so_state & SS_CANTRCVMORE) {
176: head->so_error = ECONNABORTED;
177: break;
178: }
179: error = tsleep(&head->so_timeo, PSOCK | PCATCH, netcon, 0);
180: if (error) {
181: goto bad;
182: }
183: }
184: if (head->so_error) {
185: error = head->so_error;
186: head->so_error = 0;
187: goto bad;
188: }
189:
190: /*
191: * At this point we know that there is at least one connection
192: * ready to be accepted. Remove it from the queue prior to
193: * allocating the file descriptor for it since falloc() may
194: * block allowing another process to accept the connection
195: * instead.
196: */
197: so = TAILQ_FIRST(&head->so_q);
198: if (soqremque(so, 1) == 0)
199: panic("accept");
200:
201: /* Take note if socket was non-blocking. */
202: nflag = (fp->f_flag & FNONBLOCK);
203:
204: fdplock(p->p_fd);
205: if ((error = falloc(p, &fp, &tmpfd)) != 0) {
206: /*
207: * Probably ran out of file descriptors. Put the
208: * unaccepted connection back onto the queue and
209: * do another wakeup so some other process might
210: * have a chance at it.
211: */
212: so->so_head = head;
213: head->so_qlen++;
214: so->so_onq = &head->so_q;
215: TAILQ_INSERT_HEAD(so->so_onq, so, so_qe);
216: wakeup_one(&head->so_timeo);
217: goto bad;
218: }
219: *retval = tmpfd;
220:
221: /* connection has been removed from the listen queue */
222: KNOTE(&head->so_rcv.sb_sel.si_note, 0);
223:
224: fp->f_type = DTYPE_SOCKET;
225: fp->f_flag = FREAD | FWRITE | nflag;
226: fp->f_ops = &socketops;
227: fp->f_data = so;
228: nam = m_get(M_WAIT, MT_SONAME);
229: error = soaccept(so, nam);
230: if (!error && SCARG(uap, name)) {
231: if (namelen > nam->m_len)
232: namelen = nam->m_len;
233: /* SHOULD COPY OUT A CHAIN HERE */
234: if ((error = copyout(mtod(nam, caddr_t),
235: SCARG(uap, name), namelen)) == 0)
236: error = copyout(&namelen, SCARG(uap, anamelen),
237: sizeof (*SCARG(uap, anamelen)));
238: }
239: /* if an error occurred, free the file descriptor */
240: if (error) {
241: fdremove(p->p_fd, tmpfd);
242: closef(fp, p);
243: } else {
244: FILE_SET_MATURE(fp);
245: }
246: m_freem(nam);
247: bad:
248: fdpunlock(p->p_fd);
249: splx(s);
250: FRELE(headfp);
251: return (error);
252: }
253:
254: /* ARGSUSED */
255: int
256: sys_connect(struct proc *p, void *v, register_t *retval)
257: {
258: struct sys_connect_args /* {
259: syscallarg(int) s;
260: syscallarg(const struct sockaddr *) name;
261: syscallarg(socklen_t) namelen;
262: } */ *uap = v;
263: struct file *fp;
264: struct socket *so;
265: struct mbuf *nam = NULL;
266: int error, s;
267:
268: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
269: return (error);
270: so = fp->f_data;
271: if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
272: FRELE(fp);
273: return (EALREADY);
274: }
275: error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
276: MT_SONAME);
277: if (error)
278: goto bad;
279: error = soconnect(so, nam);
280: if (error)
281: goto bad;
282: if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
283: FRELE(fp);
284: m_freem(nam);
285: return (EINPROGRESS);
286: }
287: s = splsoftnet();
288: while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
289: error = tsleep(&so->so_timeo, PSOCK | PCATCH,
290: netcon, 0);
291: if (error)
292: break;
293: }
294: if (error == 0) {
295: error = so->so_error;
296: so->so_error = 0;
297: }
298: splx(s);
299: bad:
300: so->so_state &= ~SS_ISCONNECTING;
301: FRELE(fp);
302: if (nam)
303: m_freem(nam);
304: if (error == ERESTART)
305: error = EINTR;
306: return (error);
307: }
308:
309: int
310: sys_socketpair(struct proc *p, void *v, register_t *retval)
311: {
312: struct sys_socketpair_args /* {
313: syscallarg(int) domain;
314: syscallarg(int) type;
315: syscallarg(int) protocol;
316: syscallarg(int *) rsv;
317: } */ *uap = v;
318: struct filedesc *fdp = p->p_fd;
319: struct file *fp1, *fp2;
320: struct socket *so1, *so2;
321: int fd, error, sv[2];
322:
323: error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type),
324: SCARG(uap, protocol));
325: if (error)
326: return (error);
327: error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type),
328: SCARG(uap, protocol));
329: if (error)
330: goto free1;
331:
332: fdplock(fdp);
333: if ((error = falloc(p, &fp1, &fd)) != 0)
334: goto free2;
335: sv[0] = fd;
336: fp1->f_flag = FREAD|FWRITE;
337: fp1->f_type = DTYPE_SOCKET;
338: fp1->f_ops = &socketops;
339: fp1->f_data = so1;
340: if ((error = falloc(p, &fp2, &fd)) != 0)
341: goto free3;
342: fp2->f_flag = FREAD|FWRITE;
343: fp2->f_type = DTYPE_SOCKET;
344: fp2->f_ops = &socketops;
345: fp2->f_data = so2;
346: sv[1] = fd;
347: if ((error = soconnect2(so1, so2)) != 0)
348: goto free4;
349: if (SCARG(uap, type) == SOCK_DGRAM) {
350: /*
351: * Datagram socket connection is asymmetric.
352: */
353: if ((error = soconnect2(so2, so1)) != 0)
354: goto free4;
355: }
356: error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int));
357: if (error == 0) {
358: FILE_SET_MATURE(fp1);
359: FILE_SET_MATURE(fp2);
360: fdpunlock(fdp);
361: return (0);
362: }
363: free4:
364: fdremove(fdp, sv[1]);
365: closef(fp2, p);
366: so2 = NULL;
367: free3:
368: fdremove(fdp, sv[0]);
369: closef(fp1, p);
370: so1 = NULL;
371: free2:
372: if (so2 != NULL)
373: (void)soclose(so2);
374: fdpunlock(fdp);
375: free1:
376: if (so1 != NULL)
377: (void)soclose(so1);
378: return (error);
379: }
380:
381: int
382: sys_sendto(struct proc *p, void *v, register_t *retval)
383: {
384: struct sys_sendto_args /* {
385: syscallarg(int) s;
386: syscallarg(const void *) buf;
387: syscallarg(size_t) len;
388: syscallarg(int) flags;
389: syscallarg(const struct sockaddr *) to;
390: syscallarg(socklen_t) tolen;
391: } */ *uap = v;
392: struct msghdr msg;
393: struct iovec aiov;
394:
395: msg.msg_name = (caddr_t)SCARG(uap, to);
396: msg.msg_namelen = SCARG(uap, tolen);
397: msg.msg_iov = &aiov;
398: msg.msg_iovlen = 1;
399: msg.msg_control = 0;
400: #ifdef COMPAT_OLDSOCK
401: msg.msg_flags = 0;
402: #endif
403: aiov.iov_base = (char *)SCARG(uap, buf);
404: aiov.iov_len = SCARG(uap, len);
405: return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
406: }
407:
408: int
409: sys_sendmsg(struct proc *p, void *v, register_t *retval)
410: {
411: struct sys_sendmsg_args /* {
412: syscallarg(int) s;
413: syscallarg(const struct msghdr *) msg;
414: syscallarg(int) flags;
415: } */ *uap = v;
416: struct msghdr msg;
417: struct iovec aiov[UIO_SMALLIOV], *iov;
418: int error;
419:
420: error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
421: if (error)
422: return (error);
423: if (msg.msg_iovlen > IOV_MAX)
424: return (EMSGSIZE);
425: if (msg.msg_iovlen > UIO_SMALLIOV)
426: iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
427: M_IOV, M_WAITOK);
428: else
429: iov = aiov;
430: if (msg.msg_iovlen &&
431: (error = copyin(msg.msg_iov, iov,
432: (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
433: goto done;
434: msg.msg_iov = iov;
435: #ifdef COMPAT_OLDSOCK
436: msg.msg_flags = 0;
437: #endif
438: error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
439: done:
440: if (iov != aiov)
441: free(iov, M_IOV);
442: return (error);
443: }
444:
445: int
446: sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
447: {
448: struct file *fp;
449: struct uio auio;
450: struct iovec *iov;
451: int i;
452: struct mbuf *to, *control;
453: int len, error;
454: #ifdef KTRACE
455: struct iovec *ktriov = NULL;
456: #endif
457:
458: to = NULL;
459:
460: if ((error = getsock(p->p_fd, s, &fp)) != 0)
461: return (error);
462: auio.uio_iov = mp->msg_iov;
463: auio.uio_iovcnt = mp->msg_iovlen;
464: auio.uio_segflg = UIO_USERSPACE;
465: auio.uio_rw = UIO_WRITE;
466: auio.uio_procp = p;
467: auio.uio_offset = 0; /* XXX */
468: auio.uio_resid = 0;
469: iov = mp->msg_iov;
470: for (i = 0; i < mp->msg_iovlen; i++, iov++) {
471: /* Don't allow sum > SSIZE_MAX */
472: if (iov->iov_len > SSIZE_MAX ||
473: (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
474: error = EINVAL;
475: goto bad;
476: }
477: }
478: if (mp->msg_name) {
479: error = sockargs(&to, mp->msg_name, mp->msg_namelen,
480: MT_SONAME);
481: if (error)
482: goto bad;
483: }
484: if (mp->msg_control) {
485: if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))
486: #ifdef COMPAT_OLDSOCK
487: && mp->msg_flags != MSG_COMPAT
488: #endif
489: ) {
490: error = EINVAL;
491: goto bad;
492: }
493: error = sockargs(&control, mp->msg_control,
494: mp->msg_controllen, MT_CONTROL);
495: if (error)
496: goto bad;
497: #ifdef COMPAT_OLDSOCK
498: if (mp->msg_flags == MSG_COMPAT) {
499: struct cmsghdr *cm;
500:
501: M_PREPEND(control, sizeof(*cm), M_WAIT);
502: cm = mtod(control, struct cmsghdr *);
503: cm->cmsg_len = control->m_len;
504: cm->cmsg_level = SOL_SOCKET;
505: cm->cmsg_type = SCM_RIGHTS;
506: }
507: #endif
508: } else
509: control = 0;
510: #ifdef KTRACE
511: if (KTRPOINT(p, KTR_GENIO)) {
512: int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
513:
514: ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
515: bcopy(auio.uio_iov, ktriov, iovlen);
516: }
517: #endif
518: len = auio.uio_resid;
519: error = sosend(fp->f_data, to, &auio, NULL, control, flags);
520: if (error) {
521: if (auio.uio_resid != len && (error == ERESTART ||
522: error == EINTR || error == EWOULDBLOCK))
523: error = 0;
524: if (error == EPIPE)
525: psignal(p, SIGPIPE);
526: }
527: if (error == 0) {
528: *retsize = len - auio.uio_resid;
529: fp->f_wxfer++;
530: fp->f_wbytes += *retsize;
531: }
532: #ifdef KTRACE
533: if (ktriov != NULL) {
534: if (error == 0)
535: ktrgenio(p, s, UIO_WRITE, ktriov, *retsize, error);
536: free(ktriov, M_TEMP);
537: }
538: #endif
539: bad:
540: FRELE(fp);
541: if (to)
542: m_freem(to);
543: return (error);
544: }
545:
546: int
547: sys_recvfrom(struct proc *p, void *v, register_t *retval)
548: {
549: struct sys_recvfrom_args /* {
550: syscallarg(int) s;
551: syscallarg(void *) buf;
552: syscallarg(size_t) len;
553: syscallarg(int) flags;
554: syscallarg(struct sockaddr *) from;
555: syscallarg(socklen_t *) fromlenaddr;
556: } */ *uap = v;
557: struct msghdr msg;
558: struct iovec aiov;
559: int error;
560:
561: if (SCARG(uap, fromlenaddr)) {
562: error = copyin(SCARG(uap, fromlenaddr),
563: &msg.msg_namelen, sizeof (msg.msg_namelen));
564: if (error)
565: return (error);
566: } else
567: msg.msg_namelen = 0;
568: msg.msg_name = (caddr_t)SCARG(uap, from);
569: msg.msg_iov = &aiov;
570: msg.msg_iovlen = 1;
571: aiov.iov_base = SCARG(uap, buf);
572: aiov.iov_len = SCARG(uap, len);
573: msg.msg_control = 0;
574: msg.msg_flags = SCARG(uap, flags);
575: return (recvit(p, SCARG(uap, s), &msg,
576: (caddr_t)SCARG(uap, fromlenaddr), retval));
577: }
578:
579: int
580: sys_recvmsg(struct proc *p, void *v, register_t *retval)
581: {
582: struct sys_recvmsg_args /* {
583: syscallarg(int) s;
584: syscallarg(struct msghdr *) msg;
585: syscallarg(int) flags;
586: } */ *uap = v;
587: struct msghdr msg;
588: struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
589: int error;
590:
591: error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
592: if (error)
593: return (error);
594: if (msg.msg_iovlen > IOV_MAX)
595: return (EMSGSIZE);
596: if (msg.msg_iovlen > UIO_SMALLIOV)
597: iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
598: M_IOV, M_WAITOK);
599: else
600: iov = aiov;
601: #ifdef COMPAT_OLDSOCK
602: msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
603: #else
604: msg.msg_flags = SCARG(uap, flags);
605: #endif
606: if (msg.msg_iovlen > 0) {
607: error = copyin(msg.msg_iov, iov,
608: (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
609: if (error)
610: goto done;
611: }
612: uiov = msg.msg_iov;
613: msg.msg_iov = iov;
614: if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
615: msg.msg_iov = uiov;
616: error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
617: }
618: done:
619: if (iov != aiov)
620: free(iov, M_IOV);
621: return (error);
622: }
623:
624: int
625: recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp,
626: register_t *retsize)
627: {
628: struct file *fp;
629: struct uio auio;
630: struct iovec *iov;
631: int i;
632: size_t len;
633: int error;
634: struct mbuf *from = NULL, *control = NULL;
635: #ifdef KTRACE
636: struct iovec *ktriov = NULL;
637: #endif
638:
639: if ((error = getsock(p->p_fd, s, &fp)) != 0)
640: return (error);
641: auio.uio_iov = mp->msg_iov;
642: auio.uio_iovcnt = mp->msg_iovlen;
643: auio.uio_segflg = UIO_USERSPACE;
644: auio.uio_rw = UIO_READ;
645: auio.uio_procp = p;
646: auio.uio_offset = 0; /* XXX */
647: auio.uio_resid = 0;
648: iov = mp->msg_iov;
649: for (i = 0; i < mp->msg_iovlen; i++, iov++) {
650: /* Don't allow sum > SSIZE_MAX */
651: if (iov->iov_len > SSIZE_MAX ||
652: (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
653: error = EINVAL;
654: goto out;
655: }
656: }
657: #ifdef KTRACE
658: if (KTRPOINT(p, KTR_GENIO)) {
659: int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
660:
661: ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
662: bcopy(auio.uio_iov, ktriov, iovlen);
663: }
664: #endif
665: len = auio.uio_resid;
666: error = soreceive(fp->f_data, &from, &auio, NULL,
667: mp->msg_control ? &control : NULL,
668: &mp->msg_flags);
669: if (error) {
670: if (auio.uio_resid != len && (error == ERESTART ||
671: error == EINTR || error == EWOULDBLOCK))
672: error = 0;
673: }
674: #ifdef KTRACE
675: if (ktriov != NULL) {
676: if (error == 0)
677: ktrgenio(p, s, UIO_READ,
678: ktriov, len - auio.uio_resid, error);
679: free(ktriov, M_TEMP);
680: }
681: #endif
682: if (error)
683: goto out;
684: *retsize = len - auio.uio_resid;
685: if (mp->msg_name) {
686: socklen_t alen;
687:
688: if (from == NULL)
689: alen = 0;
690: else {
691: /* save sa_len before it is destroyed by MSG_COMPAT */
692: alen = mp->msg_namelen;
693: if (alen > from->m_len)
694: alen = from->m_len;
695: /* else if alen < from->m_len ??? */
696: #ifdef COMPAT_OLDSOCK
697: if (mp->msg_flags & MSG_COMPAT)
698: mtod(from, struct osockaddr *)->sa_family =
699: mtod(from, struct sockaddr *)->sa_family;
700: #endif
701: error = copyout(mtod(from, caddr_t), mp->msg_name, alen);
702: if (error)
703: goto out;
704: }
705: mp->msg_namelen = alen;
706: if (namelenp &&
707: (error = copyout(&alen, namelenp, sizeof(alen)))) {
708: #ifdef COMPAT_OLDSOCK
709: if (mp->msg_flags & MSG_COMPAT)
710: error = 0; /* old recvfrom didn't check */
711: else
712: #endif
713: goto out;
714: }
715: }
716: if (mp->msg_control) {
717: #ifdef COMPAT_OLDSOCK
718: /*
719: * We assume that old recvmsg calls won't receive access
720: * rights and other control info, esp. as control info
721: * is always optional and those options didn't exist in 4.3.
722: * If we receive rights, trim the cmsghdr; anything else
723: * is tossed.
724: */
725: if (control && mp->msg_flags & MSG_COMPAT) {
726: if (mtod(control, struct cmsghdr *)->cmsg_level !=
727: SOL_SOCKET ||
728: mtod(control, struct cmsghdr *)->cmsg_type !=
729: SCM_RIGHTS) {
730: mp->msg_controllen = 0;
731: goto out;
732: }
733: control->m_len -= sizeof (struct cmsghdr);
734: control->m_data += sizeof (struct cmsghdr);
735: }
736: #endif
737: len = mp->msg_controllen;
738: if (len <= 0 || control == NULL)
739: len = 0;
740: else {
741: struct mbuf *m = control;
742: caddr_t p = mp->msg_control;
743:
744: do {
745: i = m->m_len;
746: if (len < i) {
747: mp->msg_flags |= MSG_CTRUNC;
748: i = len;
749: }
750: error = copyout(mtod(m, caddr_t), p,
751: (unsigned)i);
752: if (m->m_next)
753: i = ALIGN(i);
754: p += i;
755: len -= i;
756: if (error != 0 || len <= 0)
757: break;
758: } while ((m = m->m_next) != NULL);
759: len = p - (caddr_t)mp->msg_control;
760: }
761: mp->msg_controllen = len;
762: }
763: if (!error) {
764: fp->f_rxfer++;
765: fp->f_rbytes += *retsize;
766: }
767: out:
768: FRELE(fp);
769: if (from)
770: m_freem(from);
771: if (control)
772: m_freem(control);
773: return (error);
774: }
775:
776: /* ARGSUSED */
777: int
778: sys_shutdown(struct proc *p, void *v, register_t *retval)
779: {
780: struct sys_shutdown_args /* {
781: syscallarg(int) s;
782: syscallarg(int) how;
783: } */ *uap = v;
784: struct file *fp;
785: int error;
786:
787: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
788: return (error);
789: error = soshutdown(fp->f_data, SCARG(uap, how));
790: FRELE(fp);
791: return (error);
792: }
793:
794: /* ARGSUSED */
795: int
796: sys_setsockopt(struct proc *p, void *v, register_t *retval)
797: {
798: struct sys_setsockopt_args /* {
799: syscallarg(int) s;
800: syscallarg(int) level;
801: syscallarg(int) name;
802: syscallarg(const void *) val;
803: syscallarg(socklen_t) valsize;
804: } */ *uap = v;
805: struct file *fp;
806: struct mbuf *m = NULL;
807: int error;
808:
809: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
810: return (error);
811: if (SCARG(uap, valsize) > MCLBYTES) {
812: error = EINVAL;
813: goto bad;
814: }
815: if (SCARG(uap, val)) {
816: m = m_get(M_WAIT, MT_SOOPTS);
817: if (SCARG(uap, valsize) > MLEN) {
818: MCLGET(m, M_DONTWAIT);
819: if ((m->m_flags & M_EXT) == 0) {
820: error = ENOBUFS;
821: goto bad;
822: }
823: }
824: if (m == NULL) {
825: error = ENOBUFS;
826: goto bad;
827: }
828: error = copyin(SCARG(uap, val), mtod(m, caddr_t),
829: SCARG(uap, valsize));
830: if (error) {
831: goto bad;
832: }
833: m->m_len = SCARG(uap, valsize);
834: }
835: error = sosetopt(fp->f_data, SCARG(uap, level),
836: SCARG(uap, name), m);
837: m = NULL;
838: bad:
839: if (m)
840: m_freem(m);
841: FRELE(fp);
842: return (error);
843: }
844:
845: /* ARGSUSED */
846: int
847: sys_getsockopt(struct proc *p, void *v, register_t *retval)
848: {
849: struct sys_getsockopt_args /* {
850: syscallarg(int) s;
851: syscallarg(int) level;
852: syscallarg(int) name;
853: syscallarg(void *) val;
854: syscallarg(socklen_t *) avalsize;
855: } */ *uap = v;
856: struct file *fp;
857: struct mbuf *m = NULL;
858: socklen_t valsize;
859: int error;
860:
861: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
862: return (error);
863: if (SCARG(uap, val)) {
864: error = copyin(SCARG(uap, avalsize),
865: &valsize, sizeof (valsize));
866: if (error)
867: goto out;
868: } else
869: valsize = 0;
870: if ((error = sogetopt(fp->f_data, SCARG(uap, level),
871: SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
872: m != NULL) {
873: if (valsize > m->m_len)
874: valsize = m->m_len;
875: error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
876: if (error == 0)
877: error = copyout(&valsize,
878: SCARG(uap, avalsize), sizeof (valsize));
879: }
880: out:
881: FRELE(fp);
882: if (m != NULL)
883: (void)m_free(m);
884: return (error);
885: }
886:
887: int
888: sys_pipe(struct proc *p, void *v, register_t *retval)
889: {
890: struct sys_pipe_args /* {
891: syscallarg(int *) fdp;
892: } */ *uap = v;
893: int error, fds[2];
894: register_t rval[2];
895:
896: if ((error = sys_opipe(p, v, rval)) != 0)
897: return (error);
898:
899: fds[0] = rval[0];
900: fds[1] = rval[1];
901: error = copyout(fds, SCARG(uap, fdp), 2 * sizeof (int));
902: if (error) {
903: fdplock(p->p_fd);
904: fdrelease(p, fds[0]);
905: fdrelease(p, fds[1]);
906: fdpunlock(p->p_fd);
907: }
908: return (error);
909: }
910:
911: /*
912: * Get socket name.
913: */
914: /* ARGSUSED */
915: int
916: sys_getsockname(struct proc *p, void *v, register_t *retval)
917: {
918: struct sys_getsockname_args /* {
919: syscallarg(int) fdes;
920: syscallarg(struct sockaddr *) asa;
921: syscallarg(socklen_t *) alen;
922: } */ *uap = v;
923: struct file *fp;
924: struct socket *so;
925: struct mbuf *m = NULL;
926: socklen_t len;
927: int error;
928:
929: if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
930: return (error);
931: error = copyin(SCARG(uap, alen), &len, sizeof (len));
932: if (error)
933: goto bad;
934: so = fp->f_data;
935: m = m_getclr(M_WAIT, MT_SONAME);
936: error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
937: if (error)
938: goto bad;
939: if (len > m->m_len)
940: len = m->m_len;
941: error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
942: if (error == 0)
943: error = copyout(&len, SCARG(uap, alen), sizeof (len));
944: bad:
945: FRELE(fp);
946: if (m)
947: m_freem(m);
948: return (error);
949: }
950:
951: /*
952: * Get name of peer for connected socket.
953: */
954: /* ARGSUSED */
955: int
956: sys_getpeername(struct proc *p, void *v, register_t *retval)
957: {
958: struct sys_getpeername_args /* {
959: syscallarg(int) fdes;
960: syscallarg(struct sockaddr *) asa;
961: syscallarg(socklen_t *) alen;
962: } */ *uap = v;
963: struct file *fp;
964: struct socket *so;
965: struct mbuf *m = NULL;
966: socklen_t len;
967: int error;
968:
969: if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
970: return (error);
971: so = fp->f_data;
972: if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
973: FRELE(fp);
974: return (ENOTCONN);
975: }
976: error = copyin(SCARG(uap, alen), &len, sizeof (len));
977: if (error)
978: goto bad;
979: m = m_getclr(M_WAIT, MT_SONAME);
980: error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0);
981: if (error)
982: goto bad;
983: if (len > m->m_len)
984: len = m->m_len;
985: error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
986: if (error == 0)
987: error = copyout(&len, SCARG(uap, alen), sizeof (len));
988: bad:
989: FRELE(fp);
990: m_freem(m);
991: return (error);
992: }
993:
994: /*
995: * Get eid of peer for connected socket.
996: */
997: /* ARGSUSED */
998: int
999: sys_getpeereid(struct proc *p, void *v, register_t *retval)
1000: {
1001: struct sys_getpeereid_args /* {
1002: syscallarg(int) fdes;
1003: syscallarg(uid_t *) euid;
1004: syscallarg(gid_t *) egid;
1005: } */ *uap = v;
1006: struct file *fp;
1007: struct socket *so;
1008: struct mbuf *m = NULL;
1009: struct unpcbid *id;
1010: int error;
1011:
1012: if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
1013: return (error);
1014: so = fp->f_data;
1015: if (so->so_proto != pffindtype(AF_LOCAL, SOCK_STREAM)) {
1016: FRELE(fp);
1017: return (EOPNOTSUPP);
1018: }
1019: m = m_getclr(M_WAIT, MT_SONAME);
1020: if (m == NULL) {
1021: error = ENOBUFS;
1022: goto bad;
1023: }
1024: error = (*so->so_proto->pr_usrreq)(so, PRU_PEEREID, 0, m, 0);
1025: if (!error && m->m_len != sizeof(struct unpcbid))
1026: error = EOPNOTSUPP;
1027: if (error)
1028: goto bad;
1029: id = mtod(m, struct unpcbid *);
1030: error = copyout(&(id->unp_euid), SCARG(uap, euid), sizeof(uid_t));
1031: if (error == 0)
1032: error = copyout(&(id->unp_egid), SCARG(uap, egid), sizeof(gid_t));
1033: bad:
1034: FRELE(fp);
1035: m_freem(m);
1036: return (error);
1037: }
1038:
1039: int
1040: sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
1041: {
1042: struct sockaddr *sa;
1043: struct mbuf *m;
1044: int error;
1045:
1046: /*
1047: * We can't allow socket names > UCHAR_MAX in length, since that
1048: * will overflow sa_len. Also, control data more than MCLBYTES in
1049: * length is just too much.
1050: */
1051: if (buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES))
1052: return (EINVAL);
1053:
1054: /* Allocate an mbuf to hold the arguments. */
1055: m = m_get(M_WAIT, type);
1056: if ((u_int)buflen > MLEN) {
1057: MCLGET(m, M_WAITOK);
1058: if ((m->m_flags & M_EXT) == 0) {
1059: m_free(m);
1060: return ENOBUFS;
1061: }
1062: }
1063: m->m_len = buflen;
1064: error = copyin(buf, mtod(m, caddr_t), buflen);
1065: if (error) {
1066: (void) m_free(m);
1067: return (error);
1068: }
1069: *mp = m;
1070: if (type == MT_SONAME) {
1071: sa = mtod(m, struct sockaddr *);
1072: #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1073: if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1074: sa->sa_family = sa->sa_len;
1075: #endif
1076: sa->sa_len = buflen;
1077: }
1078: return (0);
1079: }
1080:
1081: int
1082: getsock(struct filedesc *fdp, int fdes, struct file **fpp)
1083: {
1084: struct file *fp;
1085:
1086: if ((fp = fd_getfile(fdp, fdes)) == NULL)
1087: return (EBADF);
1088: if (fp->f_type != DTYPE_SOCKET)
1089: return (ENOTSOCK);
1090: *fpp = fp;
1091: FREF(fp);
1092:
1093: return (0);
1094: }
CVSweb