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.26 1997/04/27 20:00:45 wollman 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 sockaddr *sa;
125 int error;
126
127 error = getsock(p->p_fd, uap->s, &fp);
128 if (error)
129 return (error);
130 error = getsockaddr(&sa, uap->name, uap->namelen);
131 if (error)
132 return (error);
133 error = sobind((struct socket *)fp->f_data, sa, p);
134 FREE(sa, M_SONAME);
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 sockaddr *sa;
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 sa = 0;
247 (void) soaccept(so, &sa);
248 if (sa == 0) {
249 namelen = 0;
250 if (uap->name)
251 goto gotnoname;
252 return 0;
253 }
254 if ((u_long)sa < 0xf0000000) {
255 panic("accept1 bad sa");
256 }
257 if (uap->name) {
258#ifdef COMPAT_OLDSOCK
259 if (compat)
260 ((struct osockaddr *)sa)->sa_family =
261 sa->sa_family;
262#endif
263 if (namelen > sa->sa_len)
264 namelen = sa->sa_len;
265 error = copyout(sa, (caddr_t)uap->name, (u_int)namelen);
266 if (!error)
267gotnoname:
268 error = copyout((caddr_t)&namelen,
269 (caddr_t)uap->anamelen, sizeof (*uap->anamelen));
270 }
271 FREE(sa, M_SONAME);
272 splx(s);
273 return (error);
274}
275
276int
277accept(p, uap, retval)
278 struct proc *p;
279 struct accept_args *uap;
280 int *retval;
281{
282
283 return (accept1(p, uap, retval, 0));
284}
285
286#ifdef COMPAT_OLDSOCK
287int
288oaccept(p, uap, retval)
289 struct proc *p;
290 struct accept_args *uap;
291 int *retval;
292{
293
294 return (accept1(p, uap, retval, 1));
295}
296#endif /* COMPAT_OLDSOCK */
297
298/* ARGSUSED */
299int
300connect(p, uap, retval)
301 struct proc *p;
302 register struct connect_args /* {
303 int s;
304 caddr_t name;
305 int namelen;
306 } */ *uap;
307 int *retval;
308{
309 struct file *fp;
310 register struct socket *so;
311 struct sockaddr *sa;
312 int error, s;
313
314 error = getsock(p->p_fd, uap->s, &fp);
315 if (error)
316 return (error);
317 so = (struct socket *)fp->f_data;
318 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
319 return (EALREADY);
320 error = getsockaddr(&sa, uap->name, uap->namelen);
321 if (error)
322 return (error);
323 error = soconnect(so, sa, p);
324 if (error)
325 goto bad;
326 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
327 FREE(sa, M_SONAME);
328 return (EINPROGRESS);
329 }
330 s = splnet();
331 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
332 error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
333 "connec", 0);
334 if (error)
335 break;
336 }
337 if (error == 0) {
338 error = so->so_error;
339 so->so_error = 0;
340 }
341 splx(s);
342bad:
343 so->so_state &= ~SS_ISCONNECTING;
344 FREE(sa, M_SONAME);
345 if (error == ERESTART)
346 error = EINTR;
347 return (error);
348}
349
350int
351socketpair(p, uap, retval)
352 struct proc *p;
353 register struct socketpair_args /* {
354 int domain;
355 int type;
356 int protocol;
357 int *rsv;
358 } */ *uap;
359 int retval[];
360{
361 register struct filedesc *fdp = p->p_fd;
362 struct file *fp1, *fp2;
363 struct socket *so1, *so2;
364 int fd, error, sv[2];
365
366 error = socreate(uap->domain, &so1, uap->type, uap->protocol, p);
367 if (error)
368 return (error);
369 error = socreate(uap->domain, &so2, uap->type, uap->protocol, p);
370 if (error)
371 goto free1;
372 error = falloc(p, &fp1, &fd);
373 if (error)
374 goto free2;
375 sv[0] = fd;
376 fp1->f_flag = FREAD|FWRITE;
377 fp1->f_type = DTYPE_SOCKET;
378 fp1->f_ops = &socketops;
379 fp1->f_data = (caddr_t)so1;
380 error = falloc(p, &fp2, &fd);
381 if (error)
382 goto free3;
383 fp2->f_flag = FREAD|FWRITE;
384 fp2->f_type = DTYPE_SOCKET;
385 fp2->f_ops = &socketops;
386 fp2->f_data = (caddr_t)so2;
387 sv[1] = fd;
388 error = soconnect2(so1, so2);
389 if (error)
390 goto free4;
391 if (uap->type == SOCK_DGRAM) {
392 /*
393 * Datagram socket connection is asymmetric.
394 */
395 error = soconnect2(so2, so1);
396 if (error)
397 goto free4;
398 }
399 error = copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int));
400#if 0 /* old pipe(2) syscall compatability, unused these days */
401 retval[0] = sv[0]; /* XXX ??? */
402 retval[1] = sv[1]; /* XXX ??? */
403#endif
404 return (error);
405free4:
406 ffree(fp2);
407 fdp->fd_ofiles[sv[1]] = 0;
408free3:
409 ffree(fp1);
410 fdp->fd_ofiles[sv[0]] = 0;
411free2:
412 (void)soclose(so2);
413free1:
414 (void)soclose(so1);
415 return (error);
416}
417
418int
419sendit(p, s, mp, flags, retsize)
420 register struct proc *p;
421 int s;
422 register struct msghdr *mp;
423 int flags, *retsize;
424{
425 struct file *fp;
426 struct uio auio;
427 register struct iovec *iov;
428 register int i;
429 struct mbuf *control;
430 struct sockaddr *to;
431 int len, error;
432 struct socket *so;
433#ifdef KTRACE
434 struct iovec *ktriov = NULL;
435#endif
436
437 error = getsock(p->p_fd, s, &fp);
438 if (error)
439 return (error);
440 auio.uio_iov = mp->msg_iov;
441 auio.uio_iovcnt = mp->msg_iovlen;
442 auio.uio_segflg = UIO_USERSPACE;
443 auio.uio_rw = UIO_WRITE;
444 auio.uio_procp = p;
445 auio.uio_offset = 0; /* XXX */
446 auio.uio_resid = 0;
447 iov = mp->msg_iov;
448 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
449 if ((auio.uio_resid += iov->iov_len) < 0)
450 return (EINVAL);
451 }
452 if (mp->msg_name) {
453 error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
454 if (error)
455 return (error);
456 } else
457 to = 0;
458 if (mp->msg_control) {
459 if (mp->msg_controllen < sizeof(struct cmsghdr)
460#ifdef COMPAT_OLDSOCK
461 && mp->msg_flags != MSG_COMPAT
462#endif
463 ) {
464 error = EINVAL;
465 goto bad;
466 }
467 error = sockargs(&control, mp->msg_control,
468 mp->msg_controllen, MT_CONTROL);
469 if (error)
470 goto bad;
471#ifdef COMPAT_OLDSOCK
472 if (mp->msg_flags == MSG_COMPAT) {
473 register struct cmsghdr *cm;
474
475 M_PREPEND(control, sizeof(*cm), M_WAIT);
476 if (control == 0) {
477 error = ENOBUFS;
478 goto bad;
479 } else {
480 cm = mtod(control, struct cmsghdr *);
481 cm->cmsg_len = control->m_len;
482 cm->cmsg_level = SOL_SOCKET;
483 cm->cmsg_type = SCM_RIGHTS;
484 }
485 }
486#endif
487 } else
488 control = 0;
489#ifdef KTRACE
490 if (KTRPOINT(p, KTR_GENIO)) {
491 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
492
493 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
494 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
495 }
496#endif
497 len = auio.uio_resid;
498 so = (struct socket *)fp->f_data;
499 error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control,
500 flags, p);
501 if (error) {
502 if (auio.uio_resid != len && (error == ERESTART ||
503 error == EINTR || error == EWOULDBLOCK))
504 error = 0;
505 if (error == EPIPE)
506 psignal(p, SIGPIPE);
507 }
508 if (error == 0)
509 *retsize = len - auio.uio_resid;
510#ifdef KTRACE
511 if (ktriov != NULL) {
512 if (error == 0)
513 ktrgenio(p->p_tracep, s, UIO_WRITE,
514 ktriov, *retsize, error);
515 FREE(ktriov, M_TEMP);
516 }
517#endif
518bad:
519 if (to)
520 FREE(to, M_SONAME);
521 return (error);
522}
523
524int
525sendto(p, uap, retval)
526 struct proc *p;
527 register struct sendto_args /* {
528 int s;
529 caddr_t buf;
530 size_t len;
531 int flags;
532 caddr_t to;
533 int tolen;
534 } */ *uap;
535 int *retval;
536{
537 struct msghdr msg;
538 struct iovec aiov;
539
540 msg.msg_name = uap->to;
541 msg.msg_namelen = uap->tolen;
542 msg.msg_iov = &aiov;
543 msg.msg_iovlen = 1;
544 msg.msg_control = 0;
545#ifdef COMPAT_OLDSOCK
546 msg.msg_flags = 0;
547#endif
548 aiov.iov_base = uap->buf;
549 aiov.iov_len = uap->len;
550 return (sendit(p, uap->s, &msg, uap->flags, retval));
551}
552
553#ifdef COMPAT_OLDSOCK
554int
555osend(p, uap, retval)
556 struct proc *p;
557 register struct osend_args /* {
558 int s;
559 caddr_t buf;
560 int len;
561 int flags;
562 } */ *uap;
563 int *retval;
564{
565 struct msghdr msg;
566 struct iovec aiov;
567
568 msg.msg_name = 0;
569 msg.msg_namelen = 0;
570 msg.msg_iov = &aiov;
571 msg.msg_iovlen = 1;
572 aiov.iov_base = uap->buf;
573 aiov.iov_len = uap->len;
574 msg.msg_control = 0;
575 msg.msg_flags = 0;
576 return (sendit(p, uap->s, &msg, uap->flags, retval));
577}
578
579int
580osendmsg(p, uap, retval)
581 struct proc *p;
582 register struct osendmsg_args /* {
583 int s;
584 caddr_t msg;
585 int flags;
586 } */ *uap;
587 int *retval;
588{
589 struct msghdr msg;
590 struct iovec aiov[UIO_SMALLIOV], *iov;
591 int error;
592
593 error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr));
594 if (error)
595 return (error);
596 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
597 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
598 return (EMSGSIZE);
599 MALLOC(iov, struct iovec *,
600 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
601 M_WAITOK);
602 } else
603 iov = aiov;
604 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
605 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
606 if (error)
607 goto done;
608 msg.msg_flags = MSG_COMPAT;
609 msg.msg_iov = iov;
610 error = sendit(p, uap->s, &msg, uap->flags, retval);
611done:
612 if (iov != aiov)
613 FREE(iov, M_IOV);
614 return (error);
615}
616#endif
617
618int
619sendmsg(p, uap, retval)
620 struct proc *p;
621 register struct sendmsg_args /* {
622 int s;
623 caddr_t msg;
624 int flags;
625 } */ *uap;
626 int *retval;
627{
628 struct msghdr msg;
629 struct iovec aiov[UIO_SMALLIOV], *iov;
630 int error;
631
632 error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
633 if (error)
634 return (error);
635 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
636 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
637 return (EMSGSIZE);
638 MALLOC(iov, struct iovec *,
639 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
640 M_WAITOK);
641 } else
642 iov = aiov;
643 if (msg.msg_iovlen &&
644 (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
645 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
646 goto done;
647 msg.msg_iov = iov;
648#ifdef COMPAT_OLDSOCK
649 msg.msg_flags = 0;
650#endif
651 error = sendit(p, uap->s, &msg, uap->flags, retval);
652done:
653 if (iov != aiov)
654 FREE(iov, M_IOV);
655 return (error);
656}
657
658int
659recvit(p, s, mp, namelenp, retsize)
660 register struct proc *p;
661 int s;
662 register struct msghdr *mp;
663 caddr_t namelenp;
664 int *retsize;
665{
666 struct file *fp;
667 struct uio auio;
668 register struct iovec *iov;
669 register int i;
670 int len, error;
671 struct mbuf *m, *control = 0;
672 caddr_t ctlbuf;
673 struct socket *so;
674 struct sockaddr *fromsa = 0;
675#ifdef KTRACE
676 struct iovec *ktriov = NULL;
677#endif
678
679 error = getsock(p->p_fd, s, &fp);
680 if (error)
681 return (error);
682 auio.uio_iov = mp->msg_iov;
683 auio.uio_iovcnt = mp->msg_iovlen;
684 auio.uio_segflg = UIO_USERSPACE;
685 auio.uio_rw = UIO_READ;
686 auio.uio_procp = p;
687 auio.uio_offset = 0; /* XXX */
688 auio.uio_resid = 0;
689 iov = mp->msg_iov;
690 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
691 if ((auio.uio_resid += iov->iov_len) < 0)
692 return (EINVAL);
693 }
694#ifdef KTRACE
695 if (KTRPOINT(p, KTR_GENIO)) {
696 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
697
698 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
699 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
700 }
701#endif
702 len = auio.uio_resid;
703 so = (struct socket *)fp->f_data;
704 error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio,
705 (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
706 &mp->msg_flags);
707 if (error) {
708 if (auio.uio_resid != len && (error == ERESTART ||
709 error == EINTR || error == EWOULDBLOCK))
710 error = 0;
711 }
712#ifdef KTRACE
713 if (ktriov != NULL) {
714 if (error == 0)
715 ktrgenio(p->p_tracep, s, UIO_READ,
716 ktriov, len - auio.uio_resid, error);
717 FREE(ktriov, M_TEMP);
718 }
719#endif
720 if (error)
721 goto out;
722 *retsize = len - auio.uio_resid;
723 if (mp->msg_name) {
724 len = mp->msg_namelen;
725 if (len <= 0 || fromsa == 0)
726 len = 0;
727 else {
728#ifdef COMPAT_OLDSOCK
729 if (mp->msg_flags & MSG_COMPAT)
730 ((struct osockaddr *)fromsa)->sa_family =
731 fromsa->sa_family;
732#endif
733#ifndef MIN
734#define MIN(a,b) ((a)>(b)?(b):(a))
735#endif
736 len = MIN(len, fromsa->sa_len);
737 error = copyout(fromsa,
738 (caddr_t)mp->msg_name, (unsigned)len);
739 if (error)
740 goto out;
741 }
742 mp->msg_namelen = len;
743 if (namelenp &&
744 (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
745#ifdef COMPAT_OLDSOCK
746 if (mp->msg_flags & MSG_COMPAT)
747 error = 0; /* old recvfrom didn't check */
748 else
749#endif
750 goto out;
751 }
752 }
753 if (mp->msg_control) {
754#ifdef COMPAT_OLDSOCK
755 /*
756 * We assume that old recvmsg calls won't receive access
757 * rights and other control info, esp. as control info
758 * is always optional and those options didn't exist in 4.3.
759 * If we receive rights, trim the cmsghdr; anything else
760 * is tossed.
761 */
762 if (control && mp->msg_flags & MSG_COMPAT) {
763 if (mtod(control, struct cmsghdr *)->cmsg_level !=
764 SOL_SOCKET ||
765 mtod(control, struct cmsghdr *)->cmsg_type !=
766 SCM_RIGHTS) {
767 mp->msg_controllen = 0;
768 goto out;
769 }
770 control->m_len -= sizeof (struct cmsghdr);
771 control->m_data += sizeof (struct cmsghdr);
772 }
773#endif
774 len = mp->msg_controllen;
775 m = control;
776 mp->msg_controllen = 0;
777 ctlbuf = (caddr_t) mp->msg_control;
778
779 while (m && len > 0) {
780 unsigned int tocopy;
781
782 if (len >= m->m_len)
783 tocopy = m->m_len;
784 else {
785 mp->msg_flags |= MSG_CTRUNC;
786 tocopy = len;
787 }
788
789 if (error = copyout((caddr_t)mtod(m, caddr_t),
790 ctlbuf, tocopy))
791 goto out;
792
793 ctlbuf += tocopy;
794 len -= tocopy;
795 m = m->m_next;
796 }
797 mp->msg_controllen = ctlbuf - mp->msg_control;
798 }
799out:
800 if (fromsa)
801 FREE(fromsa, M_SONAME);
802 if (control)
803 m_freem(control);
804 return (error);
805}
806
807int
808recvfrom(p, uap, retval)
809 struct proc *p;
810 register struct recvfrom_args /* {
811 int s;
812 caddr_t buf;
813 size_t len;
814 int flags;
815 caddr_t from;
816 int *fromlenaddr;
817 } */ *uap;
818 int *retval;
819{
820 struct msghdr msg;
821 struct iovec aiov;
822 int error;
823
824 if (uap->fromlenaddr) {
825 error = copyin((caddr_t)uap->fromlenaddr,
826 (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen));
827 if (error)
828 return (error);
829 } else
830 msg.msg_namelen = 0;
831 msg.msg_name = uap->from;
832 msg.msg_iov = &aiov;
833 msg.msg_iovlen = 1;
834 aiov.iov_base = uap->buf;
835 aiov.iov_len = uap->len;
836 msg.msg_control = 0;
837 msg.msg_flags = uap->flags;
838 return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval));
839}
840
841#ifdef COMPAT_OLDSOCK
842int
843orecvfrom(p, uap, retval)
844 struct proc *p;
845 struct recvfrom_args *uap;
846 int *retval;
847{
848
849 uap->flags |= MSG_COMPAT;
850 return (recvfrom(p, uap, retval));
851}
852#endif
853
854
855#ifdef COMPAT_OLDSOCK
856int
857orecv(p, uap, retval)
858 struct proc *p;
859 register struct orecv_args /* {
860 int s;
861 caddr_t buf;
862 int len;
863 int flags;
864 } */ *uap;
865 int *retval;
866{
867 struct msghdr msg;
868 struct iovec aiov;
869
870 msg.msg_name = 0;
871 msg.msg_namelen = 0;
872 msg.msg_iov = &aiov;
873 msg.msg_iovlen = 1;
874 aiov.iov_base = uap->buf;
875 aiov.iov_len = uap->len;
876 msg.msg_control = 0;
877 msg.msg_flags = uap->flags;
878 return (recvit(p, uap->s, &msg, (caddr_t)0, retval));
879}
880
881/*
882 * Old recvmsg. This code takes advantage of the fact that the old msghdr
883 * overlays the new one, missing only the flags, and with the (old) access
884 * rights where the control fields are now.
885 */
886int
887orecvmsg(p, uap, retval)
888 struct proc *p;
889 register struct orecvmsg_args /* {
890 int s;
891 struct omsghdr *msg;
892 int flags;
893 } */ *uap;
894 int *retval;
895{
896 struct msghdr msg;
897 struct iovec aiov[UIO_SMALLIOV], *iov;
898 int error;
899
900 error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
901 sizeof (struct omsghdr));
902 if (error)
903 return (error);
904 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
905 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
906 return (EMSGSIZE);
907 MALLOC(iov, struct iovec *,
908 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
909 M_WAITOK);
910 } else
911 iov = aiov;
912 msg.msg_flags = uap->flags | MSG_COMPAT;
913 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
914 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
915 if (error)
916 goto done;
917 msg.msg_iov = iov;
918 error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval);
919
920 if (msg.msg_controllen && error == 0)
921 error = copyout((caddr_t)&msg.msg_controllen,
922 (caddr_t)&uap->msg->msg_accrightslen, sizeof (int));
923done:
924 if (iov != aiov)
925 FREE(iov, M_IOV);
926 return (error);
927}
928#endif
929
930int
931recvmsg(p, uap, retval)
932 struct proc *p;
933 register struct recvmsg_args /* {
934 int s;
935 struct msghdr *msg;
936 int flags;
937 } */ *uap;
938 int *retval;
939{
940 struct msghdr msg;
941 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
942 register int error;
943
944 error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg));
945 if (error)
946 return (error);
947 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
948 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
949 return (EMSGSIZE);
950 MALLOC(iov, struct iovec *,
951 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
952 M_WAITOK);
953 } else
954 iov = aiov;
955#ifdef COMPAT_OLDSOCK
956 msg.msg_flags = uap->flags &~ MSG_COMPAT;
957#else
958 msg.msg_flags = uap->flags;
959#endif
960 uiov = msg.msg_iov;
961 msg.msg_iov = iov;
962 error = copyin((caddr_t)uiov, (caddr_t)iov,
963 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
964 if (error)
965 goto done;
966 error = recvit(p, uap->s, &msg, (caddr_t)0, retval);
967 if (!error) {
968 msg.msg_iov = uiov;
969 error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg));
970 }
971done:
972 if (iov != aiov)
973 FREE(iov, M_IOV);
974 return (error);
975}
976
977/* ARGSUSED */
978int
979shutdown(p, uap, retval)
980 struct proc *p;
981 register struct shutdown_args /* {
982 int s;
983 int how;
984 } */ *uap;
985 int *retval;
986{
987 struct file *fp;
988 int error;
989
990 error = getsock(p->p_fd, uap->s, &fp);
991 if (error)
992 return (error);
993 return (soshutdown((struct socket *)fp->f_data, uap->how));
994}
995
996/* ARGSUSED */
997int
998setsockopt(p, uap, retval)
999 struct proc *p;
1000 register struct setsockopt_args /* {
1001 int s;
1002 int level;
1003 int name;
1004 caddr_t val;
1005 int valsize;
1006 } */ *uap;
1007 int *retval;
1008{
1009 struct file *fp;
1010 struct mbuf *m = NULL;
1011 int error;
1012
1013 error = getsock(p->p_fd, uap->s, &fp);
1014 if (error)
1015 return (error);
1016 if (uap->valsize > MLEN)
1017 return (EINVAL);
1018 if (uap->val) {
1019 m = m_get(M_WAIT, MT_SOOPTS);
1020 if (m == NULL)
1021 return (ENOBUFS);
1022 error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
1023 if (error) {
1024 (void) m_free(m);
1025 return (error);
1026 }
1027 m->m_len = uap->valsize;
1028 }
1029 return (sosetopt((struct socket *)fp->f_data, uap->level,
1030 uap->name, m, p));
1031}
1032
1033/* ARGSUSED */
1034int
1035getsockopt(p, uap, retval)
1036 struct proc *p;
1037 register struct getsockopt_args /* {
1038 int s;
1039 int level;
1040 int name;
1041 caddr_t val;
1042 int *avalsize;
1043 } */ *uap;
1044 int *retval;
1045{
1046 struct file *fp;
1047 struct mbuf *m = NULL, *m0;
1048 int op, i, valsize, error;
1049
1050 error = getsock(p->p_fd, uap->s, &fp);
1051 if (error)
1052 return (error);
1053 if (uap->val) {
1054 error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
1055 sizeof (valsize));
1056 if (error)
1057 return (error);
1058 } else
1059 valsize = 0;
1060 if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
1061 uap->name, &m, p)) == 0 && uap->val && valsize && m != NULL) {
1062 op = 0;
1063 while (m && !error && op < valsize) {
1064 i = min(m->m_len, (valsize - op));
1065 error = copyout(mtod(m, caddr_t), uap->val, (u_int)i);
1066 op += i;
1067 uap->val += i;
1068 m0 = m;
1069 MFREE(m0,m);
1070 }
1071 valsize = op;
1072 if (error == 0)
1073 error = copyout((caddr_t)&valsize,
1074 (caddr_t)uap->avalsize, sizeof (valsize));
1075 }
1076 if (m != NULL)
1077 (void) m_free(m);
1078 return (error);
1079}
1080
1081/*
1082 * Get socket name.
1083 */
1084/* ARGSUSED */
1085static int
1086getsockname1(p, uap, retval, compat)
1087 struct proc *p;
1088 register struct getsockname_args /* {
1089 int fdes;
1090 caddr_t asa;
1091 int *alen;
1092 } */ *uap;
1093 int *retval;
1094 int compat;
1095{
1096 struct file *fp;
1097 register struct socket *so;
1098 struct sockaddr *sa;
1099 int len, error;
1100
1101 error = getsock(p->p_fd, uap->fdes, &fp);
1102 if (error)
1103 return (error);
1104 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1105 if (error)
1106 return (error);
1107 so = (struct socket *)fp->f_data;
1108 sa = 0;
1109 error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
1110 if (error)
1111 goto bad;
1112 if (sa == 0) {
1113 len = 0;
1114 goto gotnothing;
1115 }
1116
1117 len = MIN(len, sa->sa_len);
1118#ifdef COMPAT_OLDSOCK
1119 if (compat)
1120 ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1121#endif
1122 error = copyout(sa, (caddr_t)uap->asa, (u_int)len);
1123 if (error == 0)
1124gotnothing:
1125 error = copyout((caddr_t)&len, (caddr_t)uap->alen,
1126 sizeof (len));
1127bad:
1128 if (sa)
1129 FREE(sa, M_SONAME);
1130 return (error);
1131}
1132
1133int
1134getsockname(p, uap, retval)
1135 struct proc *p;
1136 struct getsockname_args *uap;
1137 int *retval;
1138{
1139
1140 return (getsockname1(p, uap, retval, 0));
1141}
1142
1143#ifdef COMPAT_OLDSOCK
1144int
1145ogetsockname(p, uap, retval)
1146 struct proc *p;
1147 struct getsockname_args *uap;
1148 int *retval;
1149{
1150
1151 return (getsockname1(p, uap, retval, 1));
1152}
1153#endif /* COMPAT_OLDSOCK */
1154
1155/*
1156 * Get name of peer for connected socket.
1157 */
1158/* ARGSUSED */
1159static int
1160getpeername1(p, uap, retval, compat)
1161 struct proc *p;
1162 register struct getpeername_args /* {
1163 int fdes;
1164 caddr_t asa;
1165 int *alen;
1166 } */ *uap;
1167 int *retval;
1168 int compat;
1169{
1170 struct file *fp;
1171 register struct socket *so;
1172 struct sockaddr *sa;
1173 int len, error;
1174
1175 error = getsock(p->p_fd, uap->fdes, &fp);
1176 if (error)
1177 return (error);
1178 so = (struct socket *)fp->f_data;
1179 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1180 return (ENOTCONN);
1181 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1182 if (error)
1183 return (error);
1184 sa = 0;
1185 error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa);
1186 if (error)
1187 goto bad;
1188 if (sa == 0) {
1189 len = 0;
1190 goto gotnothing;
1191 }
1192 len = MIN(len, sa->sa_len);
1193#ifdef COMPAT_OLDSOCK
1194 if (compat)
1195 ((struct osockaddr *)sa)->sa_family =
1196 sa->sa_family;
1197#endif
1198 error = copyout(sa, (caddr_t)uap->asa, (u_int)len);
1199 if (error)
1200 goto bad;
1201gotnothing:
1202 error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
1203bad:
1204 if (sa) FREE(sa, M_SONAME);
1205 return (error);
1206}
1207
1208int
1209getpeername(p, uap, retval)
1210 struct proc *p;
1211 struct getpeername_args *uap;
1212 int *retval;
1213{
1214
1215 return (getpeername1(p, uap, retval, 0));
1216}
1217
1218#ifdef COMPAT_OLDSOCK
1219int
1220ogetpeername(p, uap, retval)
1221 struct proc *p;
1222 struct ogetpeername_args *uap;
1223 int *retval;
1224{
1225
1226 /* XXX uap should have type `getpeername_args *' to begin with. */
1227 return (getpeername1(p, (struct getpeername_args *)uap, retval, 1));
1228}
1229#endif /* COMPAT_OLDSOCK */
1230
1231int
1232sockargs(mp, buf, buflen, type)
1233 struct mbuf **mp;
1234 caddr_t buf;
1235 int buflen, type;
1236{
1237 register struct sockaddr *sa;
1238 register struct mbuf *m;
1239 int error;
1240
1241 if ((u_int)buflen > MLEN) {
1242#ifdef COMPAT_OLDSOCK
1243 if (type == MT_SONAME && (u_int)buflen <= 112)
1244 buflen = MLEN; /* unix domain compat. hack */
1245 else
1246#endif
1247 return (EINVAL);
1248 }
1249 m = m_get(M_WAIT, type);
1250 if (m == NULL)
1251 return (ENOBUFS);
1252 m->m_len = buflen;
1253 error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1254 if (error)
1255 (void) m_free(m);
1256 else {
1257 *mp = m;
1258 if (type == MT_SONAME) {
1259 sa = mtod(m, struct sockaddr *);
1260
1261#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1262 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1263 sa->sa_family = sa->sa_len;
1264#endif
1265 sa->sa_len = buflen;
1266 }
1267 }
1268 return (error);
1269}
1270
1271int
1272getsockaddr(namp, uaddr, len)
1273 struct sockaddr **namp;
1274 caddr_t uaddr;
1275 size_t len;
1276{
1277 struct sockaddr *sa;
1278 int error;
1279
1280 if (len > SOCK_MAXADDRLEN)
1281 return ENAMETOOLONG;
1282 MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK);
1283 error = copyin(uaddr, sa, len);
1284 if (error) {
1285 FREE(sa, M_SONAME);
1286 } else {
1287#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1288 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1289 sa->sa_family = sa->sa_len;
1290#endif
1291 sa->sa_len = len;
1292 *namp = sa;
1293 }
1294 return error;
1295}
1296
1297int
1298getsock(fdp, fdes, fpp)
1299 struct filedesc *fdp;
1300 int fdes;
1301 struct file **fpp;
1302{
1303 register struct file *fp;
1304
1305 if ((unsigned)fdes >= fdp->fd_nfiles ||
1306 (fp = fdp->fd_ofiles[fdes]) == NULL)
1307 return (EBADF);
1308 if (fp->f_type != DTYPE_SOCKET)
1309 return (ENOTSOCK);
1310 *fpp = fp;
1311 return (0);
1312}
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.26 1997/04/27 20:00:45 wollman 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 sockaddr *sa;
125 int error;
126
127 error = getsock(p->p_fd, uap->s, &fp);
128 if (error)
129 return (error);
130 error = getsockaddr(&sa, uap->name, uap->namelen);
131 if (error)
132 return (error);
133 error = sobind((struct socket *)fp->f_data, sa, p);
134 FREE(sa, M_SONAME);
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 sockaddr *sa;
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 sa = 0;
247 (void) soaccept(so, &sa);
248 if (sa == 0) {
249 namelen = 0;
250 if (uap->name)
251 goto gotnoname;
252 return 0;
253 }
254 if ((u_long)sa < 0xf0000000) {
255 panic("accept1 bad sa");
256 }
257 if (uap->name) {
258#ifdef COMPAT_OLDSOCK
259 if (compat)
260 ((struct osockaddr *)sa)->sa_family =
261 sa->sa_family;
262#endif
263 if (namelen > sa->sa_len)
264 namelen = sa->sa_len;
265 error = copyout(sa, (caddr_t)uap->name, (u_int)namelen);
266 if (!error)
267gotnoname:
268 error = copyout((caddr_t)&namelen,
269 (caddr_t)uap->anamelen, sizeof (*uap->anamelen));
270 }
271 FREE(sa, M_SONAME);
272 splx(s);
273 return (error);
274}
275
276int
277accept(p, uap, retval)
278 struct proc *p;
279 struct accept_args *uap;
280 int *retval;
281{
282
283 return (accept1(p, uap, retval, 0));
284}
285
286#ifdef COMPAT_OLDSOCK
287int
288oaccept(p, uap, retval)
289 struct proc *p;
290 struct accept_args *uap;
291 int *retval;
292{
293
294 return (accept1(p, uap, retval, 1));
295}
296#endif /* COMPAT_OLDSOCK */
297
298/* ARGSUSED */
299int
300connect(p, uap, retval)
301 struct proc *p;
302 register struct connect_args /* {
303 int s;
304 caddr_t name;
305 int namelen;
306 } */ *uap;
307 int *retval;
308{
309 struct file *fp;
310 register struct socket *so;
311 struct sockaddr *sa;
312 int error, s;
313
314 error = getsock(p->p_fd, uap->s, &fp);
315 if (error)
316 return (error);
317 so = (struct socket *)fp->f_data;
318 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
319 return (EALREADY);
320 error = getsockaddr(&sa, uap->name, uap->namelen);
321 if (error)
322 return (error);
323 error = soconnect(so, sa, p);
324 if (error)
325 goto bad;
326 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
327 FREE(sa, M_SONAME);
328 return (EINPROGRESS);
329 }
330 s = splnet();
331 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
332 error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
333 "connec", 0);
334 if (error)
335 break;
336 }
337 if (error == 0) {
338 error = so->so_error;
339 so->so_error = 0;
340 }
341 splx(s);
342bad:
343 so->so_state &= ~SS_ISCONNECTING;
344 FREE(sa, M_SONAME);
345 if (error == ERESTART)
346 error = EINTR;
347 return (error);
348}
349
350int
351socketpair(p, uap, retval)
352 struct proc *p;
353 register struct socketpair_args /* {
354 int domain;
355 int type;
356 int protocol;
357 int *rsv;
358 } */ *uap;
359 int retval[];
360{
361 register struct filedesc *fdp = p->p_fd;
362 struct file *fp1, *fp2;
363 struct socket *so1, *so2;
364 int fd, error, sv[2];
365
366 error = socreate(uap->domain, &so1, uap->type, uap->protocol, p);
367 if (error)
368 return (error);
369 error = socreate(uap->domain, &so2, uap->type, uap->protocol, p);
370 if (error)
371 goto free1;
372 error = falloc(p, &fp1, &fd);
373 if (error)
374 goto free2;
375 sv[0] = fd;
376 fp1->f_flag = FREAD|FWRITE;
377 fp1->f_type = DTYPE_SOCKET;
378 fp1->f_ops = &socketops;
379 fp1->f_data = (caddr_t)so1;
380 error = falloc(p, &fp2, &fd);
381 if (error)
382 goto free3;
383 fp2->f_flag = FREAD|FWRITE;
384 fp2->f_type = DTYPE_SOCKET;
385 fp2->f_ops = &socketops;
386 fp2->f_data = (caddr_t)so2;
387 sv[1] = fd;
388 error = soconnect2(so1, so2);
389 if (error)
390 goto free4;
391 if (uap->type == SOCK_DGRAM) {
392 /*
393 * Datagram socket connection is asymmetric.
394 */
395 error = soconnect2(so2, so1);
396 if (error)
397 goto free4;
398 }
399 error = copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int));
400#if 0 /* old pipe(2) syscall compatability, unused these days */
401 retval[0] = sv[0]; /* XXX ??? */
402 retval[1] = sv[1]; /* XXX ??? */
403#endif
404 return (error);
405free4:
406 ffree(fp2);
407 fdp->fd_ofiles[sv[1]] = 0;
408free3:
409 ffree(fp1);
410 fdp->fd_ofiles[sv[0]] = 0;
411free2:
412 (void)soclose(so2);
413free1:
414 (void)soclose(so1);
415 return (error);
416}
417
418int
419sendit(p, s, mp, flags, retsize)
420 register struct proc *p;
421 int s;
422 register struct msghdr *mp;
423 int flags, *retsize;
424{
425 struct file *fp;
426 struct uio auio;
427 register struct iovec *iov;
428 register int i;
429 struct mbuf *control;
430 struct sockaddr *to;
431 int len, error;
432 struct socket *so;
433#ifdef KTRACE
434 struct iovec *ktriov = NULL;
435#endif
436
437 error = getsock(p->p_fd, s, &fp);
438 if (error)
439 return (error);
440 auio.uio_iov = mp->msg_iov;
441 auio.uio_iovcnt = mp->msg_iovlen;
442 auio.uio_segflg = UIO_USERSPACE;
443 auio.uio_rw = UIO_WRITE;
444 auio.uio_procp = p;
445 auio.uio_offset = 0; /* XXX */
446 auio.uio_resid = 0;
447 iov = mp->msg_iov;
448 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
449 if ((auio.uio_resid += iov->iov_len) < 0)
450 return (EINVAL);
451 }
452 if (mp->msg_name) {
453 error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
454 if (error)
455 return (error);
456 } else
457 to = 0;
458 if (mp->msg_control) {
459 if (mp->msg_controllen < sizeof(struct cmsghdr)
460#ifdef COMPAT_OLDSOCK
461 && mp->msg_flags != MSG_COMPAT
462#endif
463 ) {
464 error = EINVAL;
465 goto bad;
466 }
467 error = sockargs(&control, mp->msg_control,
468 mp->msg_controllen, MT_CONTROL);
469 if (error)
470 goto bad;
471#ifdef COMPAT_OLDSOCK
472 if (mp->msg_flags == MSG_COMPAT) {
473 register struct cmsghdr *cm;
474
475 M_PREPEND(control, sizeof(*cm), M_WAIT);
476 if (control == 0) {
477 error = ENOBUFS;
478 goto bad;
479 } else {
480 cm = mtod(control, struct cmsghdr *);
481 cm->cmsg_len = control->m_len;
482 cm->cmsg_level = SOL_SOCKET;
483 cm->cmsg_type = SCM_RIGHTS;
484 }
485 }
486#endif
487 } else
488 control = 0;
489#ifdef KTRACE
490 if (KTRPOINT(p, KTR_GENIO)) {
491 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
492
493 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
494 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
495 }
496#endif
497 len = auio.uio_resid;
498 so = (struct socket *)fp->f_data;
499 error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control,
500 flags, p);
501 if (error) {
502 if (auio.uio_resid != len && (error == ERESTART ||
503 error == EINTR || error == EWOULDBLOCK))
504 error = 0;
505 if (error == EPIPE)
506 psignal(p, SIGPIPE);
507 }
508 if (error == 0)
509 *retsize = len - auio.uio_resid;
510#ifdef KTRACE
511 if (ktriov != NULL) {
512 if (error == 0)
513 ktrgenio(p->p_tracep, s, UIO_WRITE,
514 ktriov, *retsize, error);
515 FREE(ktriov, M_TEMP);
516 }
517#endif
518bad:
519 if (to)
520 FREE(to, M_SONAME);
521 return (error);
522}
523
524int
525sendto(p, uap, retval)
526 struct proc *p;
527 register struct sendto_args /* {
528 int s;
529 caddr_t buf;
530 size_t len;
531 int flags;
532 caddr_t to;
533 int tolen;
534 } */ *uap;
535 int *retval;
536{
537 struct msghdr msg;
538 struct iovec aiov;
539
540 msg.msg_name = uap->to;
541 msg.msg_namelen = uap->tolen;
542 msg.msg_iov = &aiov;
543 msg.msg_iovlen = 1;
544 msg.msg_control = 0;
545#ifdef COMPAT_OLDSOCK
546 msg.msg_flags = 0;
547#endif
548 aiov.iov_base = uap->buf;
549 aiov.iov_len = uap->len;
550 return (sendit(p, uap->s, &msg, uap->flags, retval));
551}
552
553#ifdef COMPAT_OLDSOCK
554int
555osend(p, uap, retval)
556 struct proc *p;
557 register struct osend_args /* {
558 int s;
559 caddr_t buf;
560 int len;
561 int flags;
562 } */ *uap;
563 int *retval;
564{
565 struct msghdr msg;
566 struct iovec aiov;
567
568 msg.msg_name = 0;
569 msg.msg_namelen = 0;
570 msg.msg_iov = &aiov;
571 msg.msg_iovlen = 1;
572 aiov.iov_base = uap->buf;
573 aiov.iov_len = uap->len;
574 msg.msg_control = 0;
575 msg.msg_flags = 0;
576 return (sendit(p, uap->s, &msg, uap->flags, retval));
577}
578
579int
580osendmsg(p, uap, retval)
581 struct proc *p;
582 register struct osendmsg_args /* {
583 int s;
584 caddr_t msg;
585 int flags;
586 } */ *uap;
587 int *retval;
588{
589 struct msghdr msg;
590 struct iovec aiov[UIO_SMALLIOV], *iov;
591 int error;
592
593 error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr));
594 if (error)
595 return (error);
596 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
597 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
598 return (EMSGSIZE);
599 MALLOC(iov, struct iovec *,
600 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
601 M_WAITOK);
602 } else
603 iov = aiov;
604 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
605 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
606 if (error)
607 goto done;
608 msg.msg_flags = MSG_COMPAT;
609 msg.msg_iov = iov;
610 error = sendit(p, uap->s, &msg, uap->flags, retval);
611done:
612 if (iov != aiov)
613 FREE(iov, M_IOV);
614 return (error);
615}
616#endif
617
618int
619sendmsg(p, uap, retval)
620 struct proc *p;
621 register struct sendmsg_args /* {
622 int s;
623 caddr_t msg;
624 int flags;
625 } */ *uap;
626 int *retval;
627{
628 struct msghdr msg;
629 struct iovec aiov[UIO_SMALLIOV], *iov;
630 int error;
631
632 error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
633 if (error)
634 return (error);
635 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
636 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
637 return (EMSGSIZE);
638 MALLOC(iov, struct iovec *,
639 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
640 M_WAITOK);
641 } else
642 iov = aiov;
643 if (msg.msg_iovlen &&
644 (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
645 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
646 goto done;
647 msg.msg_iov = iov;
648#ifdef COMPAT_OLDSOCK
649 msg.msg_flags = 0;
650#endif
651 error = sendit(p, uap->s, &msg, uap->flags, retval);
652done:
653 if (iov != aiov)
654 FREE(iov, M_IOV);
655 return (error);
656}
657
658int
659recvit(p, s, mp, namelenp, retsize)
660 register struct proc *p;
661 int s;
662 register struct msghdr *mp;
663 caddr_t namelenp;
664 int *retsize;
665{
666 struct file *fp;
667 struct uio auio;
668 register struct iovec *iov;
669 register int i;
670 int len, error;
671 struct mbuf *m, *control = 0;
672 caddr_t ctlbuf;
673 struct socket *so;
674 struct sockaddr *fromsa = 0;
675#ifdef KTRACE
676 struct iovec *ktriov = NULL;
677#endif
678
679 error = getsock(p->p_fd, s, &fp);
680 if (error)
681 return (error);
682 auio.uio_iov = mp->msg_iov;
683 auio.uio_iovcnt = mp->msg_iovlen;
684 auio.uio_segflg = UIO_USERSPACE;
685 auio.uio_rw = UIO_READ;
686 auio.uio_procp = p;
687 auio.uio_offset = 0; /* XXX */
688 auio.uio_resid = 0;
689 iov = mp->msg_iov;
690 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
691 if ((auio.uio_resid += iov->iov_len) < 0)
692 return (EINVAL);
693 }
694#ifdef KTRACE
695 if (KTRPOINT(p, KTR_GENIO)) {
696 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
697
698 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
699 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
700 }
701#endif
702 len = auio.uio_resid;
703 so = (struct socket *)fp->f_data;
704 error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio,
705 (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
706 &mp->msg_flags);
707 if (error) {
708 if (auio.uio_resid != len && (error == ERESTART ||
709 error == EINTR || error == EWOULDBLOCK))
710 error = 0;
711 }
712#ifdef KTRACE
713 if (ktriov != NULL) {
714 if (error == 0)
715 ktrgenio(p->p_tracep, s, UIO_READ,
716 ktriov, len - auio.uio_resid, error);
717 FREE(ktriov, M_TEMP);
718 }
719#endif
720 if (error)
721 goto out;
722 *retsize = len - auio.uio_resid;
723 if (mp->msg_name) {
724 len = mp->msg_namelen;
725 if (len <= 0 || fromsa == 0)
726 len = 0;
727 else {
728#ifdef COMPAT_OLDSOCK
729 if (mp->msg_flags & MSG_COMPAT)
730 ((struct osockaddr *)fromsa)->sa_family =
731 fromsa->sa_family;
732#endif
733#ifndef MIN
734#define MIN(a,b) ((a)>(b)?(b):(a))
735#endif
736 len = MIN(len, fromsa->sa_len);
737 error = copyout(fromsa,
738 (caddr_t)mp->msg_name, (unsigned)len);
739 if (error)
740 goto out;
741 }
742 mp->msg_namelen = len;
743 if (namelenp &&
744 (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
745#ifdef COMPAT_OLDSOCK
746 if (mp->msg_flags & MSG_COMPAT)
747 error = 0; /* old recvfrom didn't check */
748 else
749#endif
750 goto out;
751 }
752 }
753 if (mp->msg_control) {
754#ifdef COMPAT_OLDSOCK
755 /*
756 * We assume that old recvmsg calls won't receive access
757 * rights and other control info, esp. as control info
758 * is always optional and those options didn't exist in 4.3.
759 * If we receive rights, trim the cmsghdr; anything else
760 * is tossed.
761 */
762 if (control && mp->msg_flags & MSG_COMPAT) {
763 if (mtod(control, struct cmsghdr *)->cmsg_level !=
764 SOL_SOCKET ||
765 mtod(control, struct cmsghdr *)->cmsg_type !=
766 SCM_RIGHTS) {
767 mp->msg_controllen = 0;
768 goto out;
769 }
770 control->m_len -= sizeof (struct cmsghdr);
771 control->m_data += sizeof (struct cmsghdr);
772 }
773#endif
774 len = mp->msg_controllen;
775 m = control;
776 mp->msg_controllen = 0;
777 ctlbuf = (caddr_t) mp->msg_control;
778
779 while (m && len > 0) {
780 unsigned int tocopy;
781
782 if (len >= m->m_len)
783 tocopy = m->m_len;
784 else {
785 mp->msg_flags |= MSG_CTRUNC;
786 tocopy = len;
787 }
788
789 if (error = copyout((caddr_t)mtod(m, caddr_t),
790 ctlbuf, tocopy))
791 goto out;
792
793 ctlbuf += tocopy;
794 len -= tocopy;
795 m = m->m_next;
796 }
797 mp->msg_controllen = ctlbuf - mp->msg_control;
798 }
799out:
800 if (fromsa)
801 FREE(fromsa, M_SONAME);
802 if (control)
803 m_freem(control);
804 return (error);
805}
806
807int
808recvfrom(p, uap, retval)
809 struct proc *p;
810 register struct recvfrom_args /* {
811 int s;
812 caddr_t buf;
813 size_t len;
814 int flags;
815 caddr_t from;
816 int *fromlenaddr;
817 } */ *uap;
818 int *retval;
819{
820 struct msghdr msg;
821 struct iovec aiov;
822 int error;
823
824 if (uap->fromlenaddr) {
825 error = copyin((caddr_t)uap->fromlenaddr,
826 (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen));
827 if (error)
828 return (error);
829 } else
830 msg.msg_namelen = 0;
831 msg.msg_name = uap->from;
832 msg.msg_iov = &aiov;
833 msg.msg_iovlen = 1;
834 aiov.iov_base = uap->buf;
835 aiov.iov_len = uap->len;
836 msg.msg_control = 0;
837 msg.msg_flags = uap->flags;
838 return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval));
839}
840
841#ifdef COMPAT_OLDSOCK
842int
843orecvfrom(p, uap, retval)
844 struct proc *p;
845 struct recvfrom_args *uap;
846 int *retval;
847{
848
849 uap->flags |= MSG_COMPAT;
850 return (recvfrom(p, uap, retval));
851}
852#endif
853
854
855#ifdef COMPAT_OLDSOCK
856int
857orecv(p, uap, retval)
858 struct proc *p;
859 register struct orecv_args /* {
860 int s;
861 caddr_t buf;
862 int len;
863 int flags;
864 } */ *uap;
865 int *retval;
866{
867 struct msghdr msg;
868 struct iovec aiov;
869
870 msg.msg_name = 0;
871 msg.msg_namelen = 0;
872 msg.msg_iov = &aiov;
873 msg.msg_iovlen = 1;
874 aiov.iov_base = uap->buf;
875 aiov.iov_len = uap->len;
876 msg.msg_control = 0;
877 msg.msg_flags = uap->flags;
878 return (recvit(p, uap->s, &msg, (caddr_t)0, retval));
879}
880
881/*
882 * Old recvmsg. This code takes advantage of the fact that the old msghdr
883 * overlays the new one, missing only the flags, and with the (old) access
884 * rights where the control fields are now.
885 */
886int
887orecvmsg(p, uap, retval)
888 struct proc *p;
889 register struct orecvmsg_args /* {
890 int s;
891 struct omsghdr *msg;
892 int flags;
893 } */ *uap;
894 int *retval;
895{
896 struct msghdr msg;
897 struct iovec aiov[UIO_SMALLIOV], *iov;
898 int error;
899
900 error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
901 sizeof (struct omsghdr));
902 if (error)
903 return (error);
904 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
905 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
906 return (EMSGSIZE);
907 MALLOC(iov, struct iovec *,
908 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
909 M_WAITOK);
910 } else
911 iov = aiov;
912 msg.msg_flags = uap->flags | MSG_COMPAT;
913 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
914 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
915 if (error)
916 goto done;
917 msg.msg_iov = iov;
918 error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval);
919
920 if (msg.msg_controllen && error == 0)
921 error = copyout((caddr_t)&msg.msg_controllen,
922 (caddr_t)&uap->msg->msg_accrightslen, sizeof (int));
923done:
924 if (iov != aiov)
925 FREE(iov, M_IOV);
926 return (error);
927}
928#endif
929
930int
931recvmsg(p, uap, retval)
932 struct proc *p;
933 register struct recvmsg_args /* {
934 int s;
935 struct msghdr *msg;
936 int flags;
937 } */ *uap;
938 int *retval;
939{
940 struct msghdr msg;
941 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
942 register int error;
943
944 error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg));
945 if (error)
946 return (error);
947 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
948 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
949 return (EMSGSIZE);
950 MALLOC(iov, struct iovec *,
951 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
952 M_WAITOK);
953 } else
954 iov = aiov;
955#ifdef COMPAT_OLDSOCK
956 msg.msg_flags = uap->flags &~ MSG_COMPAT;
957#else
958 msg.msg_flags = uap->flags;
959#endif
960 uiov = msg.msg_iov;
961 msg.msg_iov = iov;
962 error = copyin((caddr_t)uiov, (caddr_t)iov,
963 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
964 if (error)
965 goto done;
966 error = recvit(p, uap->s, &msg, (caddr_t)0, retval);
967 if (!error) {
968 msg.msg_iov = uiov;
969 error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg));
970 }
971done:
972 if (iov != aiov)
973 FREE(iov, M_IOV);
974 return (error);
975}
976
977/* ARGSUSED */
978int
979shutdown(p, uap, retval)
980 struct proc *p;
981 register struct shutdown_args /* {
982 int s;
983 int how;
984 } */ *uap;
985 int *retval;
986{
987 struct file *fp;
988 int error;
989
990 error = getsock(p->p_fd, uap->s, &fp);
991 if (error)
992 return (error);
993 return (soshutdown((struct socket *)fp->f_data, uap->how));
994}
995
996/* ARGSUSED */
997int
998setsockopt(p, uap, retval)
999 struct proc *p;
1000 register struct setsockopt_args /* {
1001 int s;
1002 int level;
1003 int name;
1004 caddr_t val;
1005 int valsize;
1006 } */ *uap;
1007 int *retval;
1008{
1009 struct file *fp;
1010 struct mbuf *m = NULL;
1011 int error;
1012
1013 error = getsock(p->p_fd, uap->s, &fp);
1014 if (error)
1015 return (error);
1016 if (uap->valsize > MLEN)
1017 return (EINVAL);
1018 if (uap->val) {
1019 m = m_get(M_WAIT, MT_SOOPTS);
1020 if (m == NULL)
1021 return (ENOBUFS);
1022 error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
1023 if (error) {
1024 (void) m_free(m);
1025 return (error);
1026 }
1027 m->m_len = uap->valsize;
1028 }
1029 return (sosetopt((struct socket *)fp->f_data, uap->level,
1030 uap->name, m, p));
1031}
1032
1033/* ARGSUSED */
1034int
1035getsockopt(p, uap, retval)
1036 struct proc *p;
1037 register struct getsockopt_args /* {
1038 int s;
1039 int level;
1040 int name;
1041 caddr_t val;
1042 int *avalsize;
1043 } */ *uap;
1044 int *retval;
1045{
1046 struct file *fp;
1047 struct mbuf *m = NULL, *m0;
1048 int op, i, valsize, error;
1049
1050 error = getsock(p->p_fd, uap->s, &fp);
1051 if (error)
1052 return (error);
1053 if (uap->val) {
1054 error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
1055 sizeof (valsize));
1056 if (error)
1057 return (error);
1058 } else
1059 valsize = 0;
1060 if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
1061 uap->name, &m, p)) == 0 && uap->val && valsize && m != NULL) {
1062 op = 0;
1063 while (m && !error && op < valsize) {
1064 i = min(m->m_len, (valsize - op));
1065 error = copyout(mtod(m, caddr_t), uap->val, (u_int)i);
1066 op += i;
1067 uap->val += i;
1068 m0 = m;
1069 MFREE(m0,m);
1070 }
1071 valsize = op;
1072 if (error == 0)
1073 error = copyout((caddr_t)&valsize,
1074 (caddr_t)uap->avalsize, sizeof (valsize));
1075 }
1076 if (m != NULL)
1077 (void) m_free(m);
1078 return (error);
1079}
1080
1081/*
1082 * Get socket name.
1083 */
1084/* ARGSUSED */
1085static int
1086getsockname1(p, uap, retval, compat)
1087 struct proc *p;
1088 register struct getsockname_args /* {
1089 int fdes;
1090 caddr_t asa;
1091 int *alen;
1092 } */ *uap;
1093 int *retval;
1094 int compat;
1095{
1096 struct file *fp;
1097 register struct socket *so;
1098 struct sockaddr *sa;
1099 int len, error;
1100
1101 error = getsock(p->p_fd, uap->fdes, &fp);
1102 if (error)
1103 return (error);
1104 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1105 if (error)
1106 return (error);
1107 so = (struct socket *)fp->f_data;
1108 sa = 0;
1109 error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
1110 if (error)
1111 goto bad;
1112 if (sa == 0) {
1113 len = 0;
1114 goto gotnothing;
1115 }
1116
1117 len = MIN(len, sa->sa_len);
1118#ifdef COMPAT_OLDSOCK
1119 if (compat)
1120 ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1121#endif
1122 error = copyout(sa, (caddr_t)uap->asa, (u_int)len);
1123 if (error == 0)
1124gotnothing:
1125 error = copyout((caddr_t)&len, (caddr_t)uap->alen,
1126 sizeof (len));
1127bad:
1128 if (sa)
1129 FREE(sa, M_SONAME);
1130 return (error);
1131}
1132
1133int
1134getsockname(p, uap, retval)
1135 struct proc *p;
1136 struct getsockname_args *uap;
1137 int *retval;
1138{
1139
1140 return (getsockname1(p, uap, retval, 0));
1141}
1142
1143#ifdef COMPAT_OLDSOCK
1144int
1145ogetsockname(p, uap, retval)
1146 struct proc *p;
1147 struct getsockname_args *uap;
1148 int *retval;
1149{
1150
1151 return (getsockname1(p, uap, retval, 1));
1152}
1153#endif /* COMPAT_OLDSOCK */
1154
1155/*
1156 * Get name of peer for connected socket.
1157 */
1158/* ARGSUSED */
1159static int
1160getpeername1(p, uap, retval, compat)
1161 struct proc *p;
1162 register struct getpeername_args /* {
1163 int fdes;
1164 caddr_t asa;
1165 int *alen;
1166 } */ *uap;
1167 int *retval;
1168 int compat;
1169{
1170 struct file *fp;
1171 register struct socket *so;
1172 struct sockaddr *sa;
1173 int len, error;
1174
1175 error = getsock(p->p_fd, uap->fdes, &fp);
1176 if (error)
1177 return (error);
1178 so = (struct socket *)fp->f_data;
1179 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1180 return (ENOTCONN);
1181 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1182 if (error)
1183 return (error);
1184 sa = 0;
1185 error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa);
1186 if (error)
1187 goto bad;
1188 if (sa == 0) {
1189 len = 0;
1190 goto gotnothing;
1191 }
1192 len = MIN(len, sa->sa_len);
1193#ifdef COMPAT_OLDSOCK
1194 if (compat)
1195 ((struct osockaddr *)sa)->sa_family =
1196 sa->sa_family;
1197#endif
1198 error = copyout(sa, (caddr_t)uap->asa, (u_int)len);
1199 if (error)
1200 goto bad;
1201gotnothing:
1202 error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
1203bad:
1204 if (sa) FREE(sa, M_SONAME);
1205 return (error);
1206}
1207
1208int
1209getpeername(p, uap, retval)
1210 struct proc *p;
1211 struct getpeername_args *uap;
1212 int *retval;
1213{
1214
1215 return (getpeername1(p, uap, retval, 0));
1216}
1217
1218#ifdef COMPAT_OLDSOCK
1219int
1220ogetpeername(p, uap, retval)
1221 struct proc *p;
1222 struct ogetpeername_args *uap;
1223 int *retval;
1224{
1225
1226 /* XXX uap should have type `getpeername_args *' to begin with. */
1227 return (getpeername1(p, (struct getpeername_args *)uap, retval, 1));
1228}
1229#endif /* COMPAT_OLDSOCK */
1230
1231int
1232sockargs(mp, buf, buflen, type)
1233 struct mbuf **mp;
1234 caddr_t buf;
1235 int buflen, type;
1236{
1237 register struct sockaddr *sa;
1238 register struct mbuf *m;
1239 int error;
1240
1241 if ((u_int)buflen > MLEN) {
1242#ifdef COMPAT_OLDSOCK
1243 if (type == MT_SONAME && (u_int)buflen <= 112)
1244 buflen = MLEN; /* unix domain compat. hack */
1245 else
1246#endif
1247 return (EINVAL);
1248 }
1249 m = m_get(M_WAIT, type);
1250 if (m == NULL)
1251 return (ENOBUFS);
1252 m->m_len = buflen;
1253 error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1254 if (error)
1255 (void) m_free(m);
1256 else {
1257 *mp = m;
1258 if (type == MT_SONAME) {
1259 sa = mtod(m, struct sockaddr *);
1260
1261#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1262 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1263 sa->sa_family = sa->sa_len;
1264#endif
1265 sa->sa_len = buflen;
1266 }
1267 }
1268 return (error);
1269}
1270
1271int
1272getsockaddr(namp, uaddr, len)
1273 struct sockaddr **namp;
1274 caddr_t uaddr;
1275 size_t len;
1276{
1277 struct sockaddr *sa;
1278 int error;
1279
1280 if (len > SOCK_MAXADDRLEN)
1281 return ENAMETOOLONG;
1282 MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK);
1283 error = copyin(uaddr, sa, len);
1284 if (error) {
1285 FREE(sa, M_SONAME);
1286 } else {
1287#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1288 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1289 sa->sa_family = sa->sa_len;
1290#endif
1291 sa->sa_len = len;
1292 *namp = sa;
1293 }
1294 return error;
1295}
1296
1297int
1298getsock(fdp, fdes, fpp)
1299 struct filedesc *fdp;
1300 int fdes;
1301 struct file **fpp;
1302{
1303 register struct file *fp;
1304
1305 if ((unsigned)fdes >= fdp->fd_nfiles ||
1306 (fp = fdp->fd_ofiles[fdes]) == NULL)
1307 return (EBADF);
1308 if (fp->f_type != DTYPE_SOCKET)
1309 return (ENOTSOCK);
1310 *fpp = fp;
1311 return (0);
1312}