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