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