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