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