uipc_syscalls.c revision 1.8 1 /* $NetBSD: uipc_syscalls.c,v 1.8 1994/06/29 06:33:41 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94
36 */
37
38 #include <sys/param.h>
39 #include <sys/filedesc.h>
40 #include <sys/proc.h>
41 #include <sys/file.h>
42 #include <sys/buf.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #ifdef KTRACE
49 #include <sys/ktrace.h>
50 #endif
51
52 /*
53 * System call interface to the socket abstraction.
54 */
55 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
56 #define COMPAT_OLDSOCK
57 #endif
58
59 extern struct fileops socketops;
60
61 struct socket_args {
62 int domain;
63 int type;
64 int protocol;
65 };
66
67 int
68 socket(p, uap, retval)
69 struct proc *p;
70 register struct socket_args *uap;
71 int *retval;
72 {
73 struct filedesc *fdp = p->p_fd;
74 struct socket *so;
75 struct file *fp;
76 int fd, error;
77
78 if (error = falloc(p, &fp, &fd))
79 return (error);
80 fp->f_flag = FREAD|FWRITE;
81 fp->f_type = DTYPE_SOCKET;
82 fp->f_ops = &socketops;
83 if (error = socreate(uap->domain, &so, uap->type, uap->protocol)) {
84 fdp->fd_ofiles[fd] = 0;
85 ffree(fp);
86 } else {
87 fp->f_data = (caddr_t)so;
88 *retval = fd;
89 }
90 return (error);
91 }
92
93 struct bind_args {
94 int s;
95 caddr_t name;
96 int namelen;
97 };
98
99 /* ARGSUSED */
100 int
101 bind(p, uap, retval)
102 struct proc *p;
103 register struct bind_args *uap;
104 int *retval;
105 {
106 struct file *fp;
107 struct mbuf *nam;
108 int error;
109
110 if (error = getsock(p->p_fd, uap->s, &fp))
111 return (error);
112 if (error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME))
113 return (error);
114 error = sobind((struct socket *)fp->f_data, nam);
115 m_freem(nam);
116 return (error);
117 }
118
119 struct listen_args {
120 int s;
121 int backlog;
122 };
123
124 /* ARGSUSED */
125 int
126 listen(p, uap, retval)
127 struct proc *p;
128 register struct listen_args *uap;
129 int *retval;
130 {
131 struct file *fp;
132 int error;
133
134 if (error = getsock(p->p_fd, uap->s, &fp))
135 return (error);
136 return (solisten((struct socket *)fp->f_data, uap->backlog));
137 }
138
139 struct accept_args {
140 int s;
141 caddr_t name;
142 int *anamelen;
143 #ifdef COMPAT_OLDSOCK
144 int compat_43; /* pseudo */
145 #endif
146 };
147
148 #ifdef COMPAT_OLDSOCK
149 int
150 accept(p, uap, retval)
151 struct proc *p;
152 struct accept_args *uap;
153 int *retval;
154 {
155
156 uap->compat_43 = 0;
157 return (accept1(p, uap, retval));
158 }
159
160 int
161 oaccept(p, uap, retval)
162 struct proc *p;
163 struct accept_args *uap;
164 int *retval;
165 {
166
167 uap->compat_43 = 1;
168 return (accept1(p, uap, retval));
169 }
170 #else /* COMPAT_OLDSOCK */
171
172 #define accept1 accept
173 #endif
174
175 int
176 accept1(p, uap, retval)
177 struct proc *p;
178 register struct accept_args *uap;
179 int *retval;
180 {
181 struct file *fp;
182 struct mbuf *nam;
183 int namelen, error, s;
184 register struct socket *so;
185
186 if (uap->name && (error = copyin((caddr_t)uap->anamelen,
187 (caddr_t)&namelen, sizeof (namelen))))
188 return (error);
189 if (error = getsock(p->p_fd, uap->s, &fp))
190 return (error);
191 s = splnet();
192 so = (struct socket *)fp->f_data;
193 if ((so->so_options & SO_ACCEPTCONN) == 0) {
194 splx(s);
195 return (EINVAL);
196 }
197 if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
198 splx(s);
199 return (EWOULDBLOCK);
200 }
201 while (so->so_qlen == 0 && so->so_error == 0) {
202 if (so->so_state & SS_CANTRCVMORE) {
203 so->so_error = ECONNABORTED;
204 break;
205 }
206 if (error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
207 netcon, 0)) {
208 splx(s);
209 return (error);
210 }
211 }
212 if (so->so_error) {
213 error = so->so_error;
214 so->so_error = 0;
215 splx(s);
216 return (error);
217 }
218 if (error = falloc(p, &fp, retval)) {
219 splx(s);
220 return (error);
221 }
222 { struct socket *aso = so->so_q;
223 if (soqremque(aso, 1) == 0)
224 panic("accept");
225 so = aso;
226 }
227 fp->f_type = DTYPE_SOCKET;
228 fp->f_flag = FREAD|FWRITE;
229 fp->f_ops = &socketops;
230 fp->f_data = (caddr_t)so;
231 nam = m_get(M_WAIT, MT_SONAME);
232 (void) soaccept(so, nam);
233 if (uap->name) {
234 #ifdef COMPAT_OLDSOCK
235 if (uap->compat_43)
236 mtod(nam, struct osockaddr *)->sa_family =
237 mtod(nam, struct sockaddr *)->sa_family;
238 #endif
239 if (namelen > nam->m_len)
240 namelen = nam->m_len;
241 /* SHOULD COPY OUT A CHAIN HERE */
242 if ((error = copyout(mtod(nam, caddr_t), (caddr_t)uap->name,
243 (u_int)namelen)) == 0)
244 error = copyout((caddr_t)&namelen,
245 (caddr_t)uap->anamelen, sizeof (*uap->anamelen));
246 }
247 m_freem(nam);
248 splx(s);
249 return (error);
250 }
251
252 struct connect_args {
253 int s;
254 caddr_t name;
255 int namelen;
256 };
257
258 /* ARGSUSED */
259 int
260 connect(p, uap, retval)
261 struct proc *p;
262 register struct connect_args *uap;
263 int *retval;
264 {
265 struct file *fp;
266 register struct socket *so;
267 struct mbuf *nam;
268 int error, s;
269
270 if (error = getsock(p->p_fd, uap->s, &fp))
271 return (error);
272 so = (struct socket *)fp->f_data;
273 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
274 return (EALREADY);
275 if (error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME))
276 return (error);
277 error = soconnect(so, nam);
278 if (error)
279 goto bad;
280 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
281 m_freem(nam);
282 return (EINPROGRESS);
283 }
284 s = splnet();
285 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
286 if (error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
287 netcon, 0))
288 break;
289 if (error == 0) {
290 error = so->so_error;
291 so->so_error = 0;
292 }
293 splx(s);
294 bad:
295 so->so_state &= ~SS_ISCONNECTING;
296 m_freem(nam);
297 if (error == ERESTART)
298 error = EINTR;
299 return (error);
300 }
301
302 struct socketpair_args {
303 int domain;
304 int type;
305 int protocol;
306 int *rsv;
307 };
308
309 int
310 socketpair(p, uap, retval)
311 struct proc *p;
312 register struct socketpair_args *uap;
313 int retval[];
314 {
315 register struct filedesc *fdp = p->p_fd;
316 struct file *fp1, *fp2;
317 struct socket *so1, *so2;
318 int fd, error, sv[2];
319
320 if (error = socreate(uap->domain, &so1, uap->type, uap->protocol))
321 return (error);
322 if (error = socreate(uap->domain, &so2, uap->type, uap->protocol))
323 goto free1;
324 if (error = falloc(p, &fp1, &fd))
325 goto free2;
326 sv[0] = fd;
327 fp1->f_flag = FREAD|FWRITE;
328 fp1->f_type = DTYPE_SOCKET;
329 fp1->f_ops = &socketops;
330 fp1->f_data = (caddr_t)so1;
331 if (error = falloc(p, &fp2, &fd))
332 goto free3;
333 fp2->f_flag = FREAD|FWRITE;
334 fp2->f_type = DTYPE_SOCKET;
335 fp2->f_ops = &socketops;
336 fp2->f_data = (caddr_t)so2;
337 sv[1] = fd;
338 if (error = soconnect2(so1, so2))
339 goto free4;
340 if (uap->type == SOCK_DGRAM) {
341 /*
342 * Datagram socket connection is asymmetric.
343 */
344 if (error = soconnect2(so2, so1))
345 goto free4;
346 }
347 error = copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int));
348 retval[0] = sv[0]; /* XXX ??? */
349 retval[1] = sv[1]; /* XXX ??? */
350 return (error);
351 free4:
352 ffree(fp2);
353 fdp->fd_ofiles[sv[1]] = 0;
354 free3:
355 ffree(fp1);
356 fdp->fd_ofiles[sv[0]] = 0;
357 free2:
358 (void)soclose(so2);
359 free1:
360 (void)soclose(so1);
361 return (error);
362 }
363
364 struct sendto_args {
365 int s;
366 caddr_t buf;
367 size_t len;
368 int flags;
369 caddr_t to;
370 int tolen;
371 };
372
373 int
374 sendto(p, uap, retval)
375 struct proc *p;
376 register struct sendto_args *uap;
377 int *retval;
378 {
379 struct msghdr msg;
380 struct iovec aiov;
381
382 msg.msg_name = uap->to;
383 msg.msg_namelen = uap->tolen;
384 msg.msg_iov = &aiov;
385 msg.msg_iovlen = 1;
386 msg.msg_control = 0;
387 #ifdef COMPAT_OLDSOCK
388 msg.msg_flags = 0;
389 #endif
390 aiov.iov_base = uap->buf;
391 aiov.iov_len = uap->len;
392 return (sendit(p, uap->s, &msg, uap->flags, retval));
393 }
394
395 #ifdef COMPAT_OLDSOCK
396 struct osend_args {
397 int s;
398 caddr_t buf;
399 int len;
400 int flags;
401 };
402
403 int
404 osend(p, uap, retval)
405 struct proc *p;
406 register struct osend_args *uap;
407 int *retval;
408 {
409 struct msghdr msg;
410 struct iovec aiov;
411
412 msg.msg_name = 0;
413 msg.msg_namelen = 0;
414 msg.msg_iov = &aiov;
415 msg.msg_iovlen = 1;
416 aiov.iov_base = uap->buf;
417 aiov.iov_len = uap->len;
418 msg.msg_control = 0;
419 msg.msg_flags = 0;
420 return (sendit(p, uap->s, &msg, uap->flags, retval));
421 }
422
423 #define MSG_COMPAT 0x8000
424 struct osendmsg_args {
425 int s;
426 caddr_t msg;
427 int flags;
428 };
429
430 int
431 osendmsg(p, uap, retval)
432 struct proc *p;
433 register struct osendmsg_args *uap;
434 int *retval;
435 {
436 struct msghdr msg;
437 struct iovec aiov[UIO_SMALLIOV], *iov;
438 int error;
439
440 if (error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr)))
441 return (error);
442 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
443 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
444 return (EMSGSIZE);
445 MALLOC(iov, struct iovec *,
446 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
447 M_WAITOK);
448 } else
449 iov = aiov;
450 if (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
451 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
452 goto done;
453 msg.msg_flags = MSG_COMPAT;
454 msg.msg_iov = iov;
455 error = sendit(p, uap->s, &msg, uap->flags, retval);
456 done:
457 if (iov != aiov)
458 FREE(iov, M_IOV);
459 return (error);
460 }
461 #endif
462
463 struct sendmsg_args {
464 int s;
465 caddr_t msg;
466 int flags;
467 };
468
469 int
470 sendmsg(p, uap, retval)
471 struct proc *p;
472 register struct sendmsg_args *uap;
473 int *retval;
474 {
475 struct msghdr msg;
476 struct iovec aiov[UIO_SMALLIOV], *iov;
477 int error;
478
479 if (error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg)))
480 return (error);
481 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
482 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
483 return (EMSGSIZE);
484 MALLOC(iov, struct iovec *,
485 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
486 M_WAITOK);
487 } else
488 iov = aiov;
489 if (msg.msg_iovlen &&
490 (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
491 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
492 goto done;
493 msg.msg_iov = iov;
494 #ifdef COMPAT_OLDSOCK
495 msg.msg_flags = 0;
496 #endif
497 error = sendit(p, uap->s, &msg, uap->flags, retval);
498 done:
499 if (iov != aiov)
500 FREE(iov, M_IOV);
501 return (error);
502 }
503
504 int
505 sendit(p, s, mp, flags, retsize)
506 register struct proc *p;
507 int s;
508 register struct msghdr *mp;
509 int flags, *retsize;
510 {
511 struct file *fp;
512 struct uio auio;
513 register struct iovec *iov;
514 register int i;
515 struct mbuf *to, *control;
516 int len, error;
517 #ifdef KTRACE
518 struct iovec *ktriov = NULL;
519 #endif
520
521 if (error = getsock(p->p_fd, s, &fp))
522 return (error);
523 auio.uio_iov = mp->msg_iov;
524 auio.uio_iovcnt = mp->msg_iovlen;
525 auio.uio_segflg = UIO_USERSPACE;
526 auio.uio_rw = UIO_WRITE;
527 auio.uio_procp = p;
528 auio.uio_offset = 0; /* XXX */
529 auio.uio_resid = 0;
530 iov = mp->msg_iov;
531 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
532 if (iov->iov_len < 0)
533 return (EINVAL);
534 if ((auio.uio_resid += iov->iov_len) < 0)
535 return (EINVAL);
536 }
537 if (mp->msg_name) {
538 if (error = sockargs(&to, mp->msg_name, mp->msg_namelen,
539 MT_SONAME))
540 return (error);
541 } else
542 to = 0;
543 if (mp->msg_control) {
544 if (mp->msg_controllen < sizeof(struct cmsghdr)
545 #ifdef COMPAT_OLDSOCK
546 && mp->msg_flags != MSG_COMPAT
547 #endif
548 ) {
549 error = EINVAL;
550 goto bad;
551 }
552 if (error = sockargs(&control, mp->msg_control,
553 mp->msg_controllen, MT_CONTROL))
554 goto bad;
555 #ifdef COMPAT_OLDSOCK
556 if (mp->msg_flags == MSG_COMPAT) {
557 register struct cmsghdr *cm;
558
559 M_PREPEND(control, sizeof(*cm), M_WAIT);
560 if (control == 0) {
561 error = ENOBUFS;
562 goto bad;
563 } else {
564 cm = mtod(control, struct cmsghdr *);
565 cm->cmsg_len = control->m_len;
566 cm->cmsg_level = SOL_SOCKET;
567 cm->cmsg_type = SCM_RIGHTS;
568 }
569 }
570 #endif
571 } else
572 control = 0;
573 #ifdef KTRACE
574 if (KTRPOINT(p, KTR_GENIO)) {
575 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
576
577 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
578 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
579 }
580 #endif
581 len = auio.uio_resid;
582 if (error = sosend((struct socket *)fp->f_data, to, &auio,
583 (struct mbuf *)0, control, flags)) {
584 if (auio.uio_resid != len && (error == ERESTART ||
585 error == EINTR || error == EWOULDBLOCK))
586 error = 0;
587 if (error == EPIPE)
588 psignal(p, SIGPIPE);
589 }
590 if (error == 0)
591 *retsize = len - auio.uio_resid;
592 #ifdef KTRACE
593 if (ktriov != NULL) {
594 if (error == 0)
595 ktrgenio(p->p_tracep, s, UIO_WRITE,
596 ktriov, *retsize, error);
597 FREE(ktriov, M_TEMP);
598 }
599 #endif
600 bad:
601 if (to)
602 m_freem(to);
603 return (error);
604 }
605
606 struct recvfrom_args {
607 int s;
608 caddr_t buf;
609 size_t len;
610 int flags;
611 caddr_t from;
612 int *fromlenaddr;
613 };
614
615 #ifdef COMPAT_OLDSOCK
616 int
617 orecvfrom(p, uap, retval)
618 struct proc *p;
619 struct recvfrom_args *uap;
620 int *retval;
621 {
622
623 uap->flags |= MSG_COMPAT;
624 return (recvfrom(p, uap, retval));
625 }
626 #endif
627
628 int
629 recvfrom(p, uap, retval)
630 struct proc *p;
631 register struct recvfrom_args *uap;
632 int *retval;
633 {
634 struct msghdr msg;
635 struct iovec aiov;
636 int error;
637
638 if (uap->fromlenaddr) {
639 if (error = copyin((caddr_t)uap->fromlenaddr,
640 (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen)))
641 return (error);
642 } else
643 msg.msg_namelen = 0;
644 msg.msg_name = uap->from;
645 msg.msg_iov = &aiov;
646 msg.msg_iovlen = 1;
647 aiov.iov_base = uap->buf;
648 aiov.iov_len = uap->len;
649 msg.msg_control = 0;
650 msg.msg_flags = uap->flags;
651 return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval));
652 }
653
654 #ifdef COMPAT_OLDSOCK
655 struct orecv_args {
656 int s;
657 caddr_t buf;
658 int len;
659 int flags;
660 };
661
662 int
663 orecv(p, uap, retval)
664 struct proc *p;
665 register struct orecv_args *uap;
666 int *retval;
667 {
668 struct msghdr msg;
669 struct iovec aiov;
670
671 msg.msg_name = 0;
672 msg.msg_namelen = 0;
673 msg.msg_iov = &aiov;
674 msg.msg_iovlen = 1;
675 aiov.iov_base = uap->buf;
676 aiov.iov_len = uap->len;
677 msg.msg_control = 0;
678 msg.msg_flags = uap->flags;
679 return (recvit(p, uap->s, &msg, (caddr_t)0, retval));
680 }
681
682 /*
683 * Old recvmsg. This code takes advantage of the fact that the old msghdr
684 * overlays the new one, missing only the flags, and with the (old) access
685 * rights where the control fields are now.
686 */
687 struct orecvmsg_args {
688 int s;
689 struct omsghdr *msg;
690 int flags;
691 };
692
693 int
694 orecvmsg(p, uap, retval)
695 struct proc *p;
696 register struct orecvmsg_args *uap;
697 int *retval;
698 {
699 struct msghdr msg;
700 struct iovec aiov[UIO_SMALLIOV], *iov;
701 int error;
702
703 if (error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
704 sizeof (struct omsghdr)))
705 return (error);
706 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
707 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
708 return (EMSGSIZE);
709 MALLOC(iov, struct iovec *,
710 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
711 M_WAITOK);
712 } else
713 iov = aiov;
714 msg.msg_flags = uap->flags | MSG_COMPAT;
715 if (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
716 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
717 goto done;
718 msg.msg_iov = iov;
719 error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval);
720
721 if (msg.msg_controllen && error == 0)
722 error = copyout((caddr_t)&msg.msg_controllen,
723 (caddr_t)&uap->msg->msg_accrightslen, sizeof (int));
724 done:
725 if (iov != aiov)
726 FREE(iov, M_IOV);
727 return (error);
728 }
729 #endif
730
731 struct recvmsg_args {
732 int s;
733 struct msghdr *msg;
734 int flags;
735 };
736
737 int
738 recvmsg(p, uap, retval)
739 struct proc *p;
740 register struct recvmsg_args *uap;
741 int *retval;
742 {
743 struct msghdr msg;
744 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
745 register int error;
746
747 if (error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg)))
748 return (error);
749 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
750 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
751 return (EMSGSIZE);
752 MALLOC(iov, struct iovec *,
753 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
754 M_WAITOK);
755 } else
756 iov = aiov;
757 #ifdef COMPAT_OLDSOCK
758 msg.msg_flags = uap->flags &~ MSG_COMPAT;
759 #else
760 msg.msg_flags = uap->flags;
761 #endif
762 uiov = msg.msg_iov;
763 msg.msg_iov = iov;
764 if (error = copyin((caddr_t)uiov, (caddr_t)iov,
765 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
766 goto done;
767 if ((error = recvit(p, uap->s, &msg, (caddr_t)0, retval)) == 0) {
768 msg.msg_iov = uiov;
769 error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg));
770 }
771 done:
772 if (iov != aiov)
773 FREE(iov, M_IOV);
774 return (error);
775 }
776
777 int
778 recvit(p, s, mp, namelenp, retsize)
779 register struct proc *p;
780 int s;
781 register struct msghdr *mp;
782 caddr_t namelenp;
783 int *retsize;
784 {
785 struct file *fp;
786 struct uio auio;
787 register struct iovec *iov;
788 register int i;
789 int len, error;
790 struct mbuf *from = 0, *control = 0;
791 #ifdef KTRACE
792 struct iovec *ktriov = NULL;
793 #endif
794
795 if (error = getsock(p->p_fd, s, &fp))
796 return (error);
797 auio.uio_iov = mp->msg_iov;
798 auio.uio_iovcnt = mp->msg_iovlen;
799 auio.uio_segflg = UIO_USERSPACE;
800 auio.uio_rw = UIO_READ;
801 auio.uio_procp = p;
802 auio.uio_offset = 0; /* XXX */
803 auio.uio_resid = 0;
804 iov = mp->msg_iov;
805 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
806 if (iov->iov_len < 0)
807 return (EINVAL);
808 if ((auio.uio_resid += iov->iov_len) < 0)
809 return (EINVAL);
810 }
811 #ifdef KTRACE
812 if (KTRPOINT(p, KTR_GENIO)) {
813 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
814
815 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
816 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
817 }
818 #endif
819 len = auio.uio_resid;
820 if (error = soreceive((struct socket *)fp->f_data, &from, &auio,
821 (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
822 &mp->msg_flags)) {
823 if (auio.uio_resid != len && (error == ERESTART ||
824 error == EINTR || error == EWOULDBLOCK))
825 error = 0;
826 }
827 #ifdef KTRACE
828 if (ktriov != NULL) {
829 if (error == 0)
830 ktrgenio(p->p_tracep, s, UIO_READ,
831 ktriov, len - auio.uio_resid, error);
832 FREE(ktriov, M_TEMP);
833 }
834 #endif
835 if (error)
836 goto out;
837 *retsize = len - auio.uio_resid;
838 if (mp->msg_name) {
839 len = mp->msg_namelen;
840 if (len <= 0 || from == 0)
841 len = 0;
842 else {
843 #ifdef COMPAT_OLDSOCK
844 if (mp->msg_flags & MSG_COMPAT)
845 mtod(from, struct osockaddr *)->sa_family =
846 mtod(from, struct sockaddr *)->sa_family;
847 #endif
848 if (len > from->m_len)
849 len = from->m_len;
850 /* else if len < from->m_len ??? */
851 if (error = copyout(mtod(from, caddr_t),
852 (caddr_t)mp->msg_name, (unsigned)len))
853 goto out;
854 }
855 mp->msg_namelen = len;
856 if (namelenp &&
857 (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
858 #ifdef COMPAT_OLDSOCK
859 if (mp->msg_flags & MSG_COMPAT)
860 error = 0; /* old recvfrom didn't check */
861 else
862 #endif
863 goto out;
864 }
865 }
866 if (mp->msg_control) {
867 #ifdef COMPAT_OLDSOCK
868 /*
869 * We assume that old recvmsg calls won't receive access
870 * rights and other control info, esp. as control info
871 * is always optional and those options didn't exist in 4.3.
872 * If we receive rights, trim the cmsghdr; anything else
873 * is tossed.
874 */
875 if (control && mp->msg_flags & MSG_COMPAT) {
876 if (mtod(control, struct cmsghdr *)->cmsg_level !=
877 SOL_SOCKET ||
878 mtod(control, struct cmsghdr *)->cmsg_type !=
879 SCM_RIGHTS) {
880 mp->msg_controllen = 0;
881 goto out;
882 }
883 control->m_len -= sizeof (struct cmsghdr);
884 control->m_data += sizeof (struct cmsghdr);
885 }
886 #endif
887 len = mp->msg_controllen;
888 if (len <= 0 || control == 0)
889 len = 0;
890 else {
891 if (len >= control->m_len)
892 len = control->m_len;
893 else
894 mp->msg_flags |= MSG_CTRUNC;
895 error = copyout((caddr_t)mtod(control, caddr_t),
896 (caddr_t)mp->msg_control, (unsigned)len);
897 }
898 mp->msg_controllen = len;
899 }
900 out:
901 if (from)
902 m_freem(from);
903 if (control)
904 m_freem(control);
905 return (error);
906 }
907
908 struct shutdown_args {
909 int s;
910 int how;
911 };
912
913 /* ARGSUSED */
914 int
915 shutdown(p, uap, retval)
916 struct proc *p;
917 register struct shutdown_args *uap;
918 int *retval;
919 {
920 struct file *fp;
921 int error;
922
923 if (error = getsock(p->p_fd, uap->s, &fp))
924 return (error);
925 return (soshutdown((struct socket *)fp->f_data, uap->how));
926 }
927
928 struct setsockopt_args {
929 int s;
930 int level;
931 int name;
932 caddr_t val;
933 int valsize;
934 };
935
936 /* ARGSUSED */
937 int
938 setsockopt(p, uap, retval)
939 struct proc *p;
940 register struct setsockopt_args *uap;
941 int *retval;
942 {
943 struct file *fp;
944 struct mbuf *m = NULL;
945 int error;
946
947 if (error = getsock(p->p_fd, uap->s, &fp))
948 return (error);
949 if (uap->valsize > MLEN)
950 return (EINVAL);
951 if (uap->val) {
952 m = m_get(M_WAIT, MT_SOOPTS);
953 if (m == NULL)
954 return (ENOBUFS);
955 if (error = copyin(uap->val, mtod(m, caddr_t),
956 (u_int)uap->valsize)) {
957 (void) m_free(m);
958 return (error);
959 }
960 m->m_len = uap->valsize;
961 }
962 return (sosetopt((struct socket *)fp->f_data, uap->level,
963 uap->name, m));
964 }
965
966 struct getsockopt_args {
967 int s;
968 int level;
969 int name;
970 caddr_t val;
971 int *avalsize;
972 };
973
974 /* ARGSUSED */
975 int
976 getsockopt(p, uap, retval)
977 struct proc *p;
978 register struct getsockopt_args *uap;
979 int *retval;
980 {
981 struct file *fp;
982 struct mbuf *m = NULL;
983 int valsize, error;
984
985 if (error = getsock(p->p_fd, uap->s, &fp))
986 return (error);
987 if (uap->val) {
988 if (error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
989 sizeof (valsize)))
990 return (error);
991 } else
992 valsize = 0;
993 if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
994 uap->name, &m)) == 0 && uap->val && valsize && m != NULL) {
995 if (valsize > m->m_len)
996 valsize = m->m_len;
997 error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize);
998 if (error == 0)
999 error = copyout((caddr_t)&valsize,
1000 (caddr_t)uap->avalsize, sizeof (valsize));
1001 }
1002 if (m != NULL)
1003 (void) m_free(m);
1004 return (error);
1005 }
1006
1007 /* ARGSUSED */
1008 int
1009 pipe(p, uap, retval)
1010 struct proc *p;
1011 struct args *uap;
1012 int retval[];
1013 {
1014 register struct filedesc *fdp = p->p_fd;
1015 struct file *rf, *wf;
1016 struct socket *rso, *wso;
1017 int fd, error;
1018
1019 if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0))
1020 return (error);
1021 if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0))
1022 goto free1;
1023 if (error = falloc(p, &rf, &fd))
1024 goto free2;
1025 retval[0] = fd;
1026 rf->f_flag = FREAD;
1027 rf->f_type = DTYPE_SOCKET;
1028 rf->f_ops = &socketops;
1029 rf->f_data = (caddr_t)rso;
1030 if (error = falloc(p, &wf, &fd))
1031 goto free3;
1032 wf->f_flag = FWRITE;
1033 wf->f_type = DTYPE_SOCKET;
1034 wf->f_ops = &socketops;
1035 wf->f_data = (caddr_t)wso;
1036 retval[1] = fd;
1037 if (error = unp_connect2(wso, rso))
1038 goto free4;
1039 return (0);
1040 free4:
1041 ffree(wf);
1042 fdp->fd_ofiles[retval[1]] = 0;
1043 free3:
1044 ffree(rf);
1045 fdp->fd_ofiles[retval[0]] = 0;
1046 free2:
1047 (void)soclose(wso);
1048 free1:
1049 (void)soclose(rso);
1050 return (error);
1051 }
1052
1053 /*
1054 * Get socket name.
1055 */
1056 struct getsockname_args {
1057 int fdes;
1058 caddr_t asa;
1059 int *alen;
1060 #ifdef COMPAT_OLDSOCK
1061 int compat_43; /* pseudo */
1062 #endif
1063 };
1064
1065 #ifdef COMPAT_OLDSOCK
1066 int
1067 getsockname(p, uap, retval)
1068 struct proc *p;
1069 struct getsockname_args *uap;
1070 int *retval;
1071 {
1072
1073 uap->compat_43 = 0;
1074 return (getsockname1(p, uap, retval));
1075 }
1076
1077 int
1078 ogetsockname(p, uap, retval)
1079 struct proc *p;
1080 struct getsockname_args *uap;
1081 int *retval;
1082 {
1083
1084 uap->compat_43 = 1;
1085 return (getsockname1(p, uap, retval));
1086 }
1087 #else /* COMPAT_OLDSOCK */
1088
1089 #define getsockname1 getsockname
1090 #endif
1091
1092 /* ARGSUSED */
1093 int
1094 getsockname1(p, uap, retval)
1095 struct proc *p;
1096 register struct getsockname_args *uap;
1097 int *retval;
1098 {
1099 struct file *fp;
1100 register struct socket *so;
1101 struct mbuf *m;
1102 int len, error;
1103
1104 if (error = getsock(p->p_fd, uap->fdes, &fp))
1105 return (error);
1106 if (error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)))
1107 return (error);
1108 so = (struct socket *)fp->f_data;
1109 m = m_getclr(M_WAIT, MT_SONAME);
1110 if (m == NULL)
1111 return (ENOBUFS);
1112 if (error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0))
1113 goto bad;
1114 if (len > m->m_len)
1115 len = m->m_len;
1116 #ifdef COMPAT_OLDSOCK
1117 if (uap->compat_43)
1118 mtod(m, struct osockaddr *)->sa_family =
1119 mtod(m, struct sockaddr *)->sa_family;
1120 #endif
1121 error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1122 if (error == 0)
1123 error = copyout((caddr_t)&len, (caddr_t)uap->alen,
1124 sizeof (len));
1125 bad:
1126 m_freem(m);
1127 return (error);
1128 }
1129
1130 /*
1131 * Get name of peer for connected socket.
1132 */
1133 struct getpeername_args {
1134 int fdes;
1135 caddr_t asa;
1136 int *alen;
1137 #ifdef COMPAT_OLDSOCK
1138 int compat_43; /* pseudo */
1139 #endif
1140 };
1141
1142 #ifdef COMPAT_OLDSOCK
1143 int
1144 getpeername(p, uap, retval)
1145 struct proc *p;
1146 struct getpeername_args *uap;
1147 int *retval;
1148 {
1149
1150 uap->compat_43 = 0;
1151 return (getpeername1(p, uap, retval));
1152 }
1153
1154 int
1155 ogetpeername(p, uap, retval)
1156 struct proc *p;
1157 struct getpeername_args *uap;
1158 int *retval;
1159 {
1160
1161 uap->compat_43 = 1;
1162 return (getpeername1(p, uap, retval));
1163 }
1164 #else /* COMPAT_OLDSOCK */
1165
1166 #define getpeername1 getpeername
1167 #endif
1168
1169 /* ARGSUSED */
1170 int
1171 getpeername1(p, uap, retval)
1172 struct proc *p;
1173 register struct getpeername_args *uap;
1174 int *retval;
1175 {
1176 struct file *fp;
1177 register struct socket *so;
1178 struct mbuf *m;
1179 int len, error;
1180
1181 if (error = getsock(p->p_fd, uap->fdes, &fp))
1182 return (error);
1183 so = (struct socket *)fp->f_data;
1184 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1185 return (ENOTCONN);
1186 if (error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)))
1187 return (error);
1188 m = m_getclr(M_WAIT, MT_SONAME);
1189 if (m == NULL)
1190 return (ENOBUFS);
1191 if (error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0))
1192 goto bad;
1193 if (len > m->m_len)
1194 len = m->m_len;
1195 #ifdef COMPAT_OLDSOCK
1196 if (uap->compat_43)
1197 mtod(m, struct osockaddr *)->sa_family =
1198 mtod(m, struct sockaddr *)->sa_family;
1199 #endif
1200 if (error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len))
1201 goto bad;
1202 error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
1203 bad:
1204 m_freem(m);
1205 return (error);
1206 }
1207
1208 int
1209 sockargs(mp, buf, buflen, type)
1210 struct mbuf **mp;
1211 caddr_t buf;
1212 int buflen, type;
1213 {
1214 register struct sockaddr *sa;
1215 register struct mbuf *m;
1216 int error;
1217
1218 if ((u_int)buflen > MLEN) {
1219 #ifdef COMPAT_OLDSOCK
1220 if (type == MT_SONAME && (u_int)buflen <= 112)
1221 buflen = MLEN; /* unix domain compat. hack */
1222 else
1223 #endif
1224 return (EINVAL);
1225 }
1226 m = m_get(M_WAIT, type);
1227 if (m == NULL)
1228 return (ENOBUFS);
1229 m->m_len = buflen;
1230 error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1231 if (error) {
1232 (void) m_free(m);
1233 return (error);
1234 }
1235 *mp = m;
1236 if (type == MT_SONAME) {
1237 sa = mtod(m, struct sockaddr *);
1238
1239 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1240 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1241 sa->sa_family = sa->sa_len;
1242 #endif
1243 sa->sa_len = buflen;
1244 }
1245 return (0);
1246 }
1247
1248 int
1249 getsock(fdp, fdes, fpp)
1250 struct filedesc *fdp;
1251 int fdes;
1252 struct file **fpp;
1253 {
1254 register struct file *fp;
1255
1256 if ((unsigned)fdes >= fdp->fd_nfiles ||
1257 (fp = fdp->fd_ofiles[fdes]) == NULL)
1258 return (EBADF);
1259 if (fp->f_type != DTYPE_SOCKET)
1260 return (ENOTSOCK);
1261 *fpp = fp;
1262 return (0);
1263 }
1264