1 /* $OpenBSD: uipc_syscalls.c,v 1.68 2008/05/23 15:51:12 thib 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, p);
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 size_t len;
454 int error;
455 #ifdef KTRACE
456 struct iovec *ktriov = NULL;
457 #endif
458
459 to = NULL;
460
461 if ((error = getsock(p->p_fd, s, &fp)) != 0)
462 return (error);
463 auio.uio_iov = mp->msg_iov;
464 auio.uio_iovcnt = mp->msg_iovlen;
465 auio.uio_segflg = UIO_USERSPACE;
466 auio.uio_rw = UIO_WRITE;
467 auio.uio_procp = p;
468 auio.uio_offset = 0; /* XXX */
469 auio.uio_resid = 0;
470 iov = mp->msg_iov;
471 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
472 /* Don't allow sum > SSIZE_MAX */
473 if (iov->iov_len > SSIZE_MAX ||
474 (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
475 error = EINVAL;
476 goto bad;
477 }
478 }
479 if (mp->msg_name) {
480 error = sockargs(&to, mp->msg_name, mp->msg_namelen,
481 MT_SONAME);
482 if (error)
483 goto bad;
484 }
485 if (mp->msg_control) {
486 if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))
487 #ifdef COMPAT_OLDSOCK
488 && mp->msg_flags != MSG_COMPAT
489 #endif
490 ) {
491 error = EINVAL;
492 goto bad;
493 }
494 error = sockargs(&control, mp->msg_control,
495 mp->msg_controllen, MT_CONTROL);
496 if (error)
497 goto bad;
498 #ifdef COMPAT_OLDSOCK
499 if (mp->msg_flags == MSG_COMPAT) {
500 struct cmsghdr *cm;
501
502 M_PREPEND(control, sizeof(*cm), M_WAIT);
503 cm = mtod(control, struct cmsghdr *);
504 cm->cmsg_len = control->m_len;
505 cm->cmsg_level = SOL_SOCKET;
506 cm->cmsg_type = SCM_RIGHTS;
507 }
508 #endif
509 } else
510 control = 0;
511 #ifdef KTRACE
512 if (KTRPOINT(p, KTR_GENIO)) {
513 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
514
515 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
516 bcopy(auio.uio_iov, ktriov, iovlen);
517 }
518 #endif
519 len = auio.uio_resid;
520 error = sosend(fp->f_data, to, &auio, NULL, control, flags);
521 if (error) {
522 if (auio.uio_resid != len && (error == ERESTART ||
523 error == EINTR || error == EWOULDBLOCK))
524 error = 0;
525 if (error == EPIPE)
526 psignal(p, SIGPIPE);
527 }
528 if (error == 0) {
529 *retsize = len - auio.uio_resid;
530 fp->f_wxfer++;
531 fp->f_wbytes += *retsize;
532 }
533 #ifdef KTRACE
534 if (ktriov != NULL) {
535 if (error == 0)
536 ktrgenio(p, s, UIO_WRITE, ktriov, *retsize, error);
537 free(ktriov, M_TEMP);
538 }
539 #endif
540 bad:
541 FRELE(fp);
542 if (to)
543 m_freem(to);
544 return (error);
545 }
546
547 int
548 sys_recvfrom(struct proc *p, void *v, register_t *retval)
549 {
550 struct sys_recvfrom_args /* {
551 syscallarg(int) s;
552 syscallarg(void *) buf;
553 syscallarg(size_t) len;
554 syscallarg(int) flags;
555 syscallarg(struct sockaddr *) from;
556 syscallarg(socklen_t *) fromlenaddr;
557 } */ *uap = v;
558 struct msghdr msg;
559 struct iovec aiov;
560 int error;
561
562 if (SCARG(uap, fromlenaddr)) {
563 error = copyin(SCARG(uap, fromlenaddr),
564 &msg.msg_namelen, sizeof (msg.msg_namelen));
565 if (error)
566 return (error);
567 } else
568 msg.msg_namelen = 0;
569 msg.msg_name = (caddr_t)SCARG(uap, from);
570 msg.msg_iov = &aiov;
571 msg.msg_iovlen = 1;
572 aiov.iov_base = SCARG(uap, buf);
573 aiov.iov_len = SCARG(uap, len);
574 msg.msg_control = 0;
575 msg.msg_flags = SCARG(uap, flags);
576 return (recvit(p, SCARG(uap, s), &msg,
577 (caddr_t)SCARG(uap, fromlenaddr), retval));
578 }
579
580 int
581 sys_recvmsg(struct proc *p, void *v, register_t *retval)
582 {
583 struct sys_recvmsg_args /* {
584 syscallarg(int) s;
585 syscallarg(struct msghdr *) msg;
586 syscallarg(int) flags;
587 } */ *uap = v;
588 struct msghdr msg;
589 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
590 int error;
591
592 error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
593 if (error)
594 return (error);
595 if (msg.msg_iovlen > IOV_MAX)
596 return (EMSGSIZE);
597 if (msg.msg_iovlen > UIO_SMALLIOV)
598 iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
599 M_IOV, M_WAITOK);
600 else
601 iov = aiov;
602 #ifdef COMPAT_OLDSOCK
603 msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
604 #else
605 msg.msg_flags = SCARG(uap, flags);
606 #endif
607 if (msg.msg_iovlen > 0) {
608 error = copyin(msg.msg_iov, iov,
609 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
610 if (error)
611 goto done;
612 }
613 uiov = msg.msg_iov;
614 msg.msg_iov = iov;
615 if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
616 msg.msg_iov = uiov;
617 error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
618 }
619 done:
620 if (iov != aiov)
621 free(iov, M_IOV);
622 return (error);
623 }
624
625 int
626 recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp,
627 register_t *retsize)
628 {
629 struct file *fp;
630 struct uio auio;
631 struct iovec *iov;
632 int i;
633 size_t len;
634 int error;
635 struct mbuf *from = NULL, *control = NULL;
636 #ifdef KTRACE
637 struct iovec *ktriov = NULL;
638 #endif
639
640 if ((error = getsock(p->p_fd, s, &fp)) != 0)
641 return (error);
642 auio.uio_iov = mp->msg_iov;
643 auio.uio_iovcnt = mp->msg_iovlen;
644 auio.uio_segflg = UIO_USERSPACE;
645 auio.uio_rw = UIO_READ;
646 auio.uio_procp = p;
647 auio.uio_offset = 0; /* XXX */
648 auio.uio_resid = 0;
649 iov = mp->msg_iov;
650 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
651 /* Don't allow sum > SSIZE_MAX */
652 if (iov->iov_len > SSIZE_MAX ||
653 (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
654 error = EINVAL;
655 goto out;
656 }
657 }
658 #ifdef KTRACE
659 if (KTRPOINT(p, KTR_GENIO)) {
660 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
661
662 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
663 bcopy(auio.uio_iov, ktriov, iovlen);
664 }
665 #endif
666 len = auio.uio_resid;
667 error = soreceive(fp->f_data, &from, &auio, NULL,
668 mp->msg_control ? &control : NULL,
669 &mp->msg_flags);
670 if (error) {
671 if (auio.uio_resid != len && (error == ERESTART ||
672 error == EINTR || error == EWOULDBLOCK))
673 error = 0;
674 }
675 #ifdef KTRACE
676 if (ktriov != NULL) {
677 if (error == 0)
678 ktrgenio(p, s, UIO_READ,
679 ktriov, len - auio.uio_resid, error);
680 free(ktriov, M_TEMP);
681 }
682 #endif
683 if (error)
684 goto out;
685 *retsize = len - auio.uio_resid;
686 if (mp->msg_name) {
687 socklen_t alen;
688
689 if (from == NULL)
690 alen = 0;
691 else {
692 /* save sa_len before it is destroyed by MSG_COMPAT */
693 alen = mp->msg_namelen;
694 if (alen > from->m_len)
695 alen = from->m_len;
696 /* else if alen < from->m_len ??? */
697 #ifdef COMPAT_OLDSOCK
698 if (mp->msg_flags & MSG_COMPAT)
699 mtod(from, struct osockaddr *)->sa_family =
700 mtod(from, struct sockaddr *)->sa_family;
701 #endif
702 error = copyout(mtod(from, caddr_t), mp->msg_name, alen);
703 if (error)
704 goto out;
705 }
706 mp->msg_namelen = alen;
707 if (namelenp &&
708 (error = copyout(&alen, namelenp, sizeof(alen)))) {
709 #ifdef COMPAT_OLDSOCK
710 if (mp->msg_flags & MSG_COMPAT)
711 error = 0; /* old recvfrom didn't check */
712 else
713 #endif
714 goto out;
715 }
716 }
717 if (mp->msg_control) {
718 #ifdef COMPAT_OLDSOCK
719 /*
720 * We assume that old recvmsg calls won't receive access
721 * rights and other control info, esp. as control info
722 * is always optional and those options didn't exist in 4.3.
723 * If we receive rights, trim the cmsghdr; anything else
724 * is tossed.
725 */
726 if (control && mp->msg_flags & MSG_COMPAT) {
727 if (mtod(control, struct cmsghdr *)->cmsg_level !=
728 SOL_SOCKET ||
729 mtod(control, struct cmsghdr *)->cmsg_type !=
730 SCM_RIGHTS) {
731 mp->msg_controllen = 0;
732 goto out;
733 }
734 control->m_len -= sizeof (struct cmsghdr);
735 control->m_data += sizeof (struct cmsghdr);
736 }
737 #endif
738 len = mp->msg_controllen;
739 if (len <= 0 || control == NULL)
740 len = 0;
741 else {
742 struct mbuf *m = control;
743 caddr_t p = mp->msg_control;
744
745 do {
746 i = m->m_len;
747 if (len < i) {
748 mp->msg_flags |= MSG_CTRUNC;
749 i = len;
750 }
751 error = copyout(mtod(m, caddr_t), p,
752 (unsigned)i);
753 if (m->m_next)
754 i = ALIGN(i);
755 p += i;
756 len -= i;
757 if (error != 0 || len <= 0)
758 break;
759 } while ((m = m->m_next) != NULL);
760 len = p - (caddr_t)mp->msg_control;
761 }
762 mp->msg_controllen = len;
763 }
764 if (!error) {
765 fp->f_rxfer++;
766 fp->f_rbytes += *retsize;
767 }
768 out:
769 FRELE(fp);
770 if (from)
771 m_freem(from);
772 if (control)
773 m_freem(control);
774 return (error);
775 }
776
777 /* ARGSUSED */
778 int
779 sys_shutdown(struct proc *p, void *v, register_t *retval)
780 {
781 struct sys_shutdown_args /* {
782 syscallarg(int) s;
783 syscallarg(int) how;
784 } */ *uap = v;
785 struct file *fp;
786 int error;
787
788 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
789 return (error);
790 error = soshutdown(fp->f_data, SCARG(uap, how));
791 FRELE(fp);
792 return (error);
793 }
794
795 /* ARGSUSED */
796 int
797 sys_setsockopt(struct proc *p, void *v, register_t *retval)
798 {
799 struct sys_setsockopt_args /* {
800 syscallarg(int) s;
801 syscallarg(int) level;
802 syscallarg(int) name;
803 syscallarg(const void *) val;
804 syscallarg(socklen_t) valsize;
805 } */ *uap = v;
806 struct file *fp;
807 struct mbuf *m = NULL;
808 int error;
809
810 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
811 return (error);
812 if (SCARG(uap, valsize) > MCLBYTES) {
813 error = EINVAL;
814 goto bad;
815 }
816 if (SCARG(uap, val)) {
817 m = m_get(M_WAIT, MT_SOOPTS);
818 if (SCARG(uap, valsize) > MLEN) {
819 MCLGET(m, M_DONTWAIT);
820 if ((m->m_flags & M_EXT) == 0) {
821 error = ENOBUFS;
822 goto bad;
823 }
824 }
825 if (m == NULL) {
826 error = ENOBUFS;
827 goto bad;
828 }
829 error = copyin(SCARG(uap, val), mtod(m, caddr_t),
830 SCARG(uap, valsize));
831 if (error) {
832 goto bad;
833 }
834 m->m_len = SCARG(uap, valsize);
835 }
836 error = sosetopt(fp->f_data, SCARG(uap, level),
837 SCARG(uap, name), m);
838 m = NULL;
839 bad:
840 if (m)
841 m_freem(m);
842 FRELE(fp);
843 return (error);
844 }
845
846 /* ARGSUSED */
847 int
848 sys_getsockopt(struct proc *p, void *v, register_t *retval)
849 {
850 struct sys_getsockopt_args /* {
851 syscallarg(int) s;
852 syscallarg(int) level;
853 syscallarg(int) name;
854 syscallarg(void *) val;
855 syscallarg(socklen_t *) avalsize;
856 } */ *uap = v;
857 struct file *fp;
858 struct mbuf *m = NULL;
859 socklen_t valsize;
860 int error;
861
862 if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
863 return (error);
864 if (SCARG(uap, val)) {
865 error = copyin(SCARG(uap, avalsize),
866 &valsize, sizeof (valsize));
867 if (error)
868 goto out;
869 } else
870 valsize = 0;
871 if ((error = sogetopt(fp->f_data, SCARG(uap, level),
872 SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
873 m != NULL) {
874 if (valsize > m->m_len)
875 valsize = m->m_len;
876 error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
877 if (error == 0)
878 error = copyout(&valsize,
879 SCARG(uap, avalsize), sizeof (valsize));
880 }
881 out:
882 FRELE(fp);
883 if (m != NULL)
884 (void)m_free(m);
885 return (error);
886 }
887
888 int
889 sys_pipe(struct proc *p, void *v, register_t *retval)
890 {
891 struct sys_pipe_args /* {
892 syscallarg(int *) fdp;
893 } */ *uap = v;
894 int error, fds[2];
895 register_t rval[2];
896
897 if ((error = sys_opipe(p, v, rval)) != 0)
898 return (error);
899
900 fds[0] = rval[0];
901 fds[1] = rval[1];
902 error = copyout(fds, SCARG(uap, fdp), 2 * sizeof (int));
903 if (error) {
904 fdplock(p->p_fd);
905 fdrelease(p, fds[0]);
906 fdrelease(p, fds[1]);
907 fdpunlock(p->p_fd);
908 }
909 return (error);
910 }
911
912 /*
913 * Get socket name.
914 */
915 /* ARGSUSED */
916 int
917 sys_getsockname(struct proc *p, void *v, register_t *retval)
918 {
919 struct sys_getsockname_args /* {
920 syscallarg(int) fdes;
921 syscallarg(struct sockaddr *) asa;
922 syscallarg(socklen_t *) alen;
923 } */ *uap = v;
924 struct file *fp;
925 struct socket *so;
926 struct mbuf *m = NULL;
927 socklen_t len;
928 int error;
929
930 if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
931 return (error);
932 error = copyin(SCARG(uap, alen), &len, sizeof (len));
933 if (error)
934 goto bad;
935 so = fp->f_data;
936 m = m_getclr(M_WAIT, MT_SONAME);
937 error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, p);
938 if (error)
939 goto bad;
940 if (len > m->m_len)
941 len = m->m_len;
942 error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
943 if (error == 0)
944 error = copyout(&len, SCARG(uap, alen), sizeof (len));
945 bad:
946 FRELE(fp);
947 if (m)
948 m_freem(m);
949 return (error);
950 }
951
952 /*
953 * Get name of peer for connected socket.
954 */
955 /* ARGSUSED */
956 int
957 sys_getpeername(struct proc *p, void *v, register_t *retval)
958 {
959 struct sys_getpeername_args /* {
960 syscallarg(int) fdes;
961 syscallarg(struct sockaddr *) asa;
962 syscallarg(socklen_t *) alen;
963 } */ *uap = v;
964 struct file *fp;
965 struct socket *so;
966 struct mbuf *m = NULL;
967 socklen_t len;
968 int error;
969
970 if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
971 return (error);
972 so = fp->f_data;
973 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
974 FRELE(fp);
975 return (ENOTCONN);
976 }
977 error = copyin(SCARG(uap, alen), &len, sizeof (len));
978 if (error)
979 goto bad;
980 m = m_getclr(M_WAIT, MT_SONAME);
981 error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, p);
982 if (error)
983 goto bad;
984 if (len > m->m_len)
985 len = m->m_len;
986 error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
987 if (error == 0)
988 error = copyout(&len, SCARG(uap, alen), sizeof (len));
989 bad:
990 FRELE(fp);
991 m_freem(m);
992 return (error);
993 }
994
995 /*
996 * Get eid of peer for connected socket.
997 */
998 /* ARGSUSED */
999 int
1000 sys_getpeereid(struct proc *p, void *v, register_t *retval)
1001 {
1002 struct sys_getpeereid_args /* {
1003 syscallarg(int) fdes;
1004 syscallarg(uid_t *) euid;
1005 syscallarg(gid_t *) egid;
1006 } */ *uap = v;
1007 struct file *fp;
1008 struct socket *so;
1009 struct mbuf *m = NULL;
1010 struct unpcbid *id;
1011 int error;
1012
1013 if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
1014 return (error);
1015 so = fp->f_data;
1016 if (so->so_proto != pffindtype(AF_LOCAL, SOCK_STREAM)) {
1017 FRELE(fp);
1018 return (EOPNOTSUPP);
1019 }
1020 m = m_getclr(M_WAIT, MT_SONAME);
1021 if (m == NULL) {
1022 error = ENOBUFS;
1023 goto bad;
1024 }
1025 error = (*so->so_proto->pr_usrreq)(so, PRU_PEEREID, 0, m, 0, p);
1026 if (!error && m->m_len != sizeof(struct unpcbid))
1027 error = EOPNOTSUPP;
1028 if (error)
1029 goto bad;
1030 id = mtod(m, struct unpcbid *);
1031 error = copyout(&(id->unp_euid), SCARG(uap, euid), sizeof(uid_t));
1032 if (error == 0)
1033 error = copyout(&(id->unp_egid), SCARG(uap, egid), sizeof(gid_t));
1034 bad:
1035 FRELE(fp);
1036 m_freem(m);
1037 return (error);
1038 }
1039
1040 int
1041 sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
1042 {
1043 struct sockaddr *sa;
1044 struct mbuf *m;
1045 int error;
1046
1047 /*
1048 * We can't allow socket names > UCHAR_MAX in length, since that
1049 * will overflow sa_len. Also, control data more than MCLBYTES in
1050 * length is just too much.
1051 */
1052 if (buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES))
1053 return (EINVAL);
1054
1055 /* Allocate an mbuf to hold the arguments. */
1056 m = m_get(M_WAIT, type);
1057 if ((u_int)buflen > MLEN) {
1058 MCLGET(m, M_WAITOK);
1059 if ((m->m_flags & M_EXT) == 0) {
1060 m_free(m);
1061 return ENOBUFS;
1062 }
1063 }
1064 m->m_len = buflen;
1065 error = copyin(buf, mtod(m, caddr_t), buflen);
1066 if (error) {
1067 (void) m_free(m);
1068 return (error);
1069 }
1070 *mp = m;
1071 if (type == MT_SONAME) {
1072 sa = mtod(m, struct sockaddr *);
1073 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1074 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1075 sa->sa_family = sa->sa_len;
1076 #endif
1077 sa->sa_len = buflen;
1078 }
1079 return (0);
1080 }
1081
1082 int
1083 getsock(struct filedesc *fdp, int fdes, struct file **fpp)
1084 {
1085 struct file *fp;
1086
1087 if ((fp = fd_getfile(fdp, fdes)) == NULL)
1088 return (EBADF);
1089 if (fp->f_type != DTYPE_SOCKET)
1090 return (ENOTSOCK);
1091 *fpp = fp;
1092 FREF(fp);
1093
1094 return (0);
1095 }
Cache object: 5e4f6c32e3225d8ff80157b4f682a4a9
|