source: rtems-libbsd/freebsd/sys/kern/uipc_syscalls.c @ 894c965

55-freebsd-126-freebsd-12
Last change on this file since 894c965 was 894c965, checked in by Sebastian Huber <sebastian.huber@…>, on 09/15/17 at 10:46:57

Support reference counting for file descriptors

Close #3132.

  • Property mode set to 100644
File size: 45.5 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 1982, 1986, 1989, 1990, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *      @(#)uipc_syscalls.c     8.4 (Berkeley) 2/21/94
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD$");
36
37#include <rtems/bsd/local/opt_capsicum.h>
38#include <rtems/bsd/local/opt_inet.h>
39#include <rtems/bsd/local/opt_inet6.h>
40#include <rtems/bsd/local/opt_compat.h>
41#include <rtems/bsd/local/opt_ktrace.h>
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/capsicum.h>
46#include <sys/kernel.h>
47#include <sys/lock.h>
48#include <sys/mutex.h>
49#include <sys/sysproto.h>
50#include <sys/malloc.h>
51#include <sys/filedesc.h>
52#include <sys/proc.h>
53#include <sys/filio.h>
54#include <sys/jail.h>
55#include <sys/mbuf.h>
56#include <sys/protosw.h>
57#include <sys/rwlock.h>
58#include <sys/socket.h>
59#include <sys/socketvar.h>
60#include <sys/syscallsubr.h>
61#ifdef KTRACE
62#include <sys/ktrace.h>
63#endif
64#ifdef COMPAT_FREEBSD32
65#include <compat/freebsd32/freebsd32_util.h>
66#endif
67
68#include <net/vnet.h>
69
70#include <security/audit/audit.h>
71#include <security/mac/mac_framework.h>
72
73/*
74 * Flags for accept1() and kern_accept4(), in addition to SOCK_CLOEXEC
75 * and SOCK_NONBLOCK.
76 */
77#define ACCEPT4_INHERIT 0x1
78#define ACCEPT4_COMPAT  0x2
79
80static int sendit(struct thread *td, int s, struct msghdr *mp, int flags);
81static int recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp);
82
83#ifndef __rtems__
84static int accept1(struct thread *td, int s, struct sockaddr *uname,
85                   socklen_t *anamelen, int flags);
86static int getsockname1(struct thread *td, struct getsockname_args *uap,
87                        int compat);
88static int getpeername1(struct thread *td, struct getpeername_args *uap,
89                        int compat);
90#endif /* __rtems__ */
91static int sockargs(struct mbuf **, char *, socklen_t, int);
92
93#ifndef __rtems__
94/*
95 * Convert a user file descriptor to a kernel file entry and check if required
96 * capability rights are present.
97 * If required copy of current set of capability rights is returned.
98 * A reference on the file entry is held upon returning.
99 */
100int
101getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
102    struct file **fpp, u_int *fflagp, struct filecaps *havecapsp)
103{
104        struct file *fp;
105        int error;
106
107        error = fget_cap(td, fd, rightsp, &fp, havecapsp);
108        if (error != 0)
109                return (error);
110        if (fp->f_type != DTYPE_SOCKET) {
111                fdrop(fp, td);
112                if (havecapsp != NULL)
113                        filecaps_free(havecapsp);
114                return (ENOTSOCK);
115        }
116        if (fflagp != NULL)
117                *fflagp = fp->f_flag;
118        *fpp = fp;
119        return (0);
120}
121#else /* __rtems__ */
122static int
123rtems_bsd_getsock(int fd, struct file **fpp, u_int *fflagp)
124{
125        struct file *fp;
126        int error;
127
128        if ((uint32_t) fd < rtems_libio_number_iops) {
129                unsigned int flags;
130
131                fp = rtems_bsd_fd_to_fp(fd);
132                flags = rtems_libio_iop_hold(&fp->f_io);
133                if ((flags & LIBIO_FLAGS_OPEN) == 0) {
134                        rtems_libio_iop_drop(&fp->f_io);
135                        fp = NULL;
136                        error = EBADF;
137                } else if (fp->f_io.pathinfo.handlers != &socketops) {
138                        rtems_libio_iop_drop(&fp->f_io);
139                        fp = NULL;
140                        error = ENOTSOCK;
141                } else {
142                        if (fflagp != NULL) {
143                                *fflagp = rtems_bsd_libio_flags_to_fflag(
144                                    fp->f_io.flags);
145                        }
146
147                        error = 0;
148                }
149        } else {
150                fp = NULL;
151                error = EBADF;
152        }
153
154        *fpp = fp;
155
156        return (error);
157}
158
159#define getsock_cap(td, fd, rights, fpp, fflagp, havecapsp) rtems_bsd_getsock(fd, fpp, fflagp)
160#endif /* __rtems__ */
161
162/*
163 * System call interface to the socket abstraction.
164 */
165#if defined(COMPAT_43)
166#define COMPAT_OLDSOCK
167#endif
168
169#ifdef __rtems__
170static
171#endif /* __rtems__ */
172int
173sys_socket(struct thread *td, struct socket_args *uap)
174{
175
176        return (kern_socket(td, uap->domain, uap->type, uap->protocol));
177}
178
179int
180kern_socket(struct thread *td, int domain, int type, int protocol)
181{
182        struct socket *so;
183        struct file *fp;
184        int fd, error, oflag, fflag;
185
186        AUDIT_ARG_SOCKET(domain, type, protocol);
187
188        oflag = 0;
189        fflag = 0;
190        if ((type & SOCK_CLOEXEC) != 0) {
191                type &= ~SOCK_CLOEXEC;
192                oflag |= O_CLOEXEC;
193        }
194        if ((type & SOCK_NONBLOCK) != 0) {
195                type &= ~SOCK_NONBLOCK;
196                fflag |= FNONBLOCK;
197        }
198
199#ifdef MAC
200        error = mac_socket_check_create(td->td_ucred, domain, type, protocol);
201        if (error != 0)
202                return (error);
203#endif
204        error = falloc(td, &fp, &fd, oflag);
205        if (error != 0)
206                return (error);
207        /* An extra reference on `fp' has been held for us by falloc(). */
208        error = socreate(domain, &so, type, protocol, td->td_ucred, td);
209        if (error != 0) {
210                fdclose(td, fp, fd);
211        } else {
212                finit(fp, FREAD | FWRITE | fflag, DTYPE_SOCKET, so, &socketops);
213                if ((fflag & FNONBLOCK) != 0)
214                        (void) fo_ioctl(fp, FIONBIO, &fflag, td->td_ucred, td);
215                td->td_retval[0] = fd;
216        }
217        fdrop(fp, td);
218        return (error);
219}
220#ifdef __rtems__
221int
222socket(int domain, int type, int protocol)
223{
224        struct thread *td = rtems_bsd_get_curthread_or_null();
225        struct socket_args ua = {
226                .domain = domain,
227                .type = type,
228                .protocol = protocol
229        };
230        int error;
231
232        if (td != NULL) {
233                error = sys_socket(td, &ua);
234        } else {
235                error = ENOMEM;
236        }
237
238        if (error == 0) {
239                return td->td_retval[0];
240        } else {
241                rtems_set_errno_and_return_minus_one(error);
242        }
243}
244#endif /* __rtems__ */
245
246#ifdef __rtems__
247static int kern_bindat(struct thread *td, int dirfd, int fd,
248    struct sockaddr *sa);
249
250static
251#endif /* __rtems__ */
252int
253sys_bind(struct thread *td, struct bind_args *uap)
254{
255        struct sockaddr *sa;
256        int error;
257
258        error = getsockaddr(&sa, uap->name, uap->namelen);
259        if (error == 0) {
260                error = kern_bindat(td, AT_FDCWD, uap->s, sa);
261                free(sa, M_SONAME);
262        }
263        return (error);
264}
265#ifdef __rtems__
266int
267bind(int socket, const struct sockaddr *address, socklen_t address_len)
268{
269        struct thread *td = rtems_bsd_get_curthread_or_null();
270        struct bind_args ua = {
271                .s = socket,
272                .name = (caddr_t) address,
273                .namelen = address_len
274        };
275        int error;
276
277        if (td != NULL) {
278                error = sys_bind(td, &ua);
279        } else {
280                error = ENOMEM;
281        }
282
283        return rtems_bsd_error_to_status_and_errno(error);
284}
285#endif /* __rtems__ */
286
287int
288kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
289{
290        struct socket *so;
291        struct file *fp;
292        cap_rights_t rights;
293        int error;
294
295        AUDIT_ARG_FD(fd);
296        AUDIT_ARG_SOCKADDR(td, dirfd, sa);
297        error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_BIND),
298            &fp, NULL, NULL);
299        if (error != 0)
300                return (error);
301        so = fp->f_data;
302#ifdef KTRACE
303        if (KTRPOINT(td, KTR_STRUCT))
304                ktrsockaddr(sa);
305#endif
306#ifdef MAC
307        error = mac_socket_check_bind(td->td_ucred, so, sa);
308        if (error == 0) {
309#endif
310                if (dirfd == AT_FDCWD)
311                        error = sobind(so, sa, td);
312                else
313                        error = sobindat(dirfd, so, sa, td);
314#ifdef MAC
315        }
316#endif
317        fdrop(fp, td);
318        return (error);
319}
320
321#ifndef __rtems__
322static
323int
324sys_bindat(struct thread *td, struct bindat_args *uap)
325{
326        struct sockaddr *sa;
327        int error;
328
329        error = getsockaddr(&sa, uap->name, uap->namelen);
330        if (error == 0) {
331                error = kern_bindat(td, uap->fd, uap->s, sa);
332                free(sa, M_SONAME);
333        }
334        return (error);
335}
336#endif /* __rtems__ */
337
338int
339sys_listen(struct thread *td, struct listen_args *uap)
340{
341
342        return (kern_listen(td, uap->s, uap->backlog));
343}
344
345int
346kern_listen(struct thread *td, int s, int backlog)
347{
348        struct socket *so;
349        struct file *fp;
350        cap_rights_t rights;
351        int error;
352
353        AUDIT_ARG_FD(s);
354        error = getsock_cap(td, s, cap_rights_init(&rights, CAP_LISTEN),
355            &fp, NULL, NULL);
356        if (error == 0) {
357                so = fp->f_data;
358#ifdef MAC
359                error = mac_socket_check_listen(td->td_ucred, so);
360                if (error == 0)
361#endif
362                        error = solisten(so, backlog, td);
363                fdrop(fp, td);
364        }
365        return (error);
366}
367#ifdef __rtems__
368int
369listen(int socket, int backlog)
370{
371        struct thread *td = rtems_bsd_get_curthread_or_null();
372        struct listen_args ua = {
373                .s = socket,
374                .backlog = backlog
375        };
376        int error;
377
378        if (td != NULL) {
379                error = sys_listen(td, &ua);
380        } else {
381                error = ENOMEM;
382        }
383
384        return rtems_bsd_error_to_status_and_errno(error);
385}
386#endif /* __rtems__ */
387
388#ifdef __rtems__
389static int kern_accept4(struct thread *td, int s, struct sockaddr **name,
390    socklen_t *namelen, int flags, struct file **fp);
391#endif /* __rtems__ */
392/*
393 * accept1()
394 */
395static int
396accept1(td, s, uname, anamelen, flags)
397        struct thread *td;
398        int s;
399        struct sockaddr *uname;
400        socklen_t *anamelen;
401        int flags;
402{
403        struct sockaddr *name;
404        socklen_t namelen;
405        struct file *fp;
406        int error;
407
408        if (uname == NULL)
409                return (kern_accept4(td, s, NULL, NULL, flags, NULL));
410
411        error = copyin(anamelen, &namelen, sizeof (namelen));
412        if (error != 0)
413                return (error);
414
415        error = kern_accept4(td, s, &name, &namelen, flags, &fp);
416
417        if (error != 0)
418                return (error);
419
420        if (error == 0 && uname != NULL) {
421#ifdef COMPAT_OLDSOCK
422                if (flags & ACCEPT4_COMPAT)
423                        ((struct osockaddr *)name)->sa_family =
424                            name->sa_family;
425#endif
426                error = copyout(name, uname, namelen);
427        }
428        if (error == 0)
429                error = copyout(&namelen, anamelen,
430                    sizeof(namelen));
431        if (error != 0)
432                fdclose(td, fp, td->td_retval[0]);
433        fdrop(fp, td);
434        free(name, M_SONAME);
435        return (error);
436}
437#ifdef __rtems__
438int
439accept(int socket, struct sockaddr *__restrict address,
440    socklen_t *__restrict address_len)
441{
442        struct thread *td = rtems_bsd_get_curthread_or_null();
443        int error;
444
445        if (td != NULL) {
446                error = accept1(td, socket, address, address_len,
447                    ACCEPT4_INHERIT);
448        } else {
449                error = ENOMEM;
450        }
451
452        if (error == 0) {
453                return td->td_retval[0];
454        } else {
455                rtems_set_errno_and_return_minus_one(error);
456        }
457}
458#endif /* __rtems__ */
459
460#ifndef __rtems__
461int
462kern_accept(struct thread *td, int s, struct sockaddr **name,
463    socklen_t *namelen, struct file **fp)
464{
465        return (kern_accept4(td, s, name, namelen, ACCEPT4_INHERIT, fp));
466}
467#endif /* __rtems__ */
468
469int
470kern_accept4(struct thread *td, int s, struct sockaddr **name,
471    socklen_t *namelen, int flags, struct file **fp)
472{
473        struct file *headfp, *nfp = NULL;
474        struct sockaddr *sa = NULL;
475        struct socket *head, *so;
476        struct filecaps fcaps;
477        cap_rights_t rights;
478        u_int fflag;
479        pid_t pgid;
480        int error, fd, tmp;
481
482        if (name != NULL)
483                *name = NULL;
484
485        AUDIT_ARG_FD(s);
486        error = getsock_cap(td, s, cap_rights_init(&rights, CAP_ACCEPT),
487            &headfp, &fflag, &fcaps);
488        if (error != 0)
489                return (error);
490        head = headfp->f_data;
491        if ((head->so_options & SO_ACCEPTCONN) == 0) {
492                error = EINVAL;
493                goto done;
494        }
495#ifdef MAC
496        error = mac_socket_check_accept(td->td_ucred, head);
497        if (error != 0)
498                goto done;
499#endif
500        error = falloc_caps(td, &nfp, &fd,
501            (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps);
502        if (error != 0)
503                goto done;
504        ACCEPT_LOCK();
505        if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
506                ACCEPT_UNLOCK();
507                error = EWOULDBLOCK;
508                goto noconnection;
509        }
510        while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
511                if (head->so_rcv.sb_state & SBS_CANTRCVMORE) {
512                        head->so_error = ECONNABORTED;
513                        break;
514                }
515                error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH,
516                    "accept", 0);
517                if (error != 0) {
518                        ACCEPT_UNLOCK();
519                        goto noconnection;
520                }
521        }
522        if (head->so_error) {
523                error = head->so_error;
524                head->so_error = 0;
525                ACCEPT_UNLOCK();
526                goto noconnection;
527        }
528        so = TAILQ_FIRST(&head->so_comp);
529        KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP"));
530        KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP"));
531
532        /*
533         * Before changing the flags on the socket, we have to bump the
534         * reference count.  Otherwise, if the protocol calls sofree(),
535         * the socket will be released due to a zero refcount.
536         */
537        SOCK_LOCK(so);                  /* soref() and so_state update */
538        soref(so);                      /* file descriptor reference */
539
540        TAILQ_REMOVE(&head->so_comp, so, so_list);
541        head->so_qlen--;
542        if (flags & ACCEPT4_INHERIT)
543                so->so_state |= (head->so_state & SS_NBIO);
544        else
545                so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0;
546        so->so_qstate &= ~SQ_COMP;
547        so->so_head = NULL;
548
549        SOCK_UNLOCK(so);
550        ACCEPT_UNLOCK();
551
552        /* An extra reference on `nfp' has been held for us by falloc(). */
553        td->td_retval[0] = fd;
554
555        /* connection has been removed from the listen queue */
556        KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
557
558        if (flags & ACCEPT4_INHERIT) {
559                pgid = fgetown(&head->so_sigio);
560                if (pgid != 0)
561                        fsetown(pgid, &so->so_sigio);
562        } else {
563                fflag &= ~(FNONBLOCK | FASYNC);
564                if (flags & SOCK_NONBLOCK)
565                        fflag |= FNONBLOCK;
566        }
567
568        finit(nfp, fflag, DTYPE_SOCKET, so, &socketops);
569        /* Sync socket nonblocking/async state with file flags */
570        tmp = fflag & FNONBLOCK;
571        (void) fo_ioctl(nfp, FIONBIO, &tmp, td->td_ucred, td);
572        tmp = fflag & FASYNC;
573        (void) fo_ioctl(nfp, FIOASYNC, &tmp, td->td_ucred, td);
574        sa = NULL;
575        error = soaccept(so, &sa);
576        if (error != 0)
577                goto noconnection;
578        if (sa == NULL) {
579                if (name)
580                        *namelen = 0;
581                goto done;
582        }
583        AUDIT_ARG_SOCKADDR(td, AT_FDCWD, sa);
584        if (name) {
585                /* check sa_len before it is destroyed */
586                if (*namelen > sa->sa_len)
587                        *namelen = sa->sa_len;
588#ifdef KTRACE
589                if (KTRPOINT(td, KTR_STRUCT))
590                        ktrsockaddr(sa);
591#endif
592                *name = sa;
593                sa = NULL;
594        }
595noconnection:
596        free(sa, M_SONAME);
597
598        /*
599         * close the new descriptor, assuming someone hasn't ripped it
600         * out from under us.
601         */
602        if (error != 0)
603                fdclose(td, nfp, fd);
604
605        /*
606         * Release explicitly held references before returning.  We return
607         * a reference on nfp to the caller on success if they request it.
608         */
609done:
610        if (nfp == NULL)
611                filecaps_free(&fcaps);
612        if (fp != NULL) {
613                if (error == 0) {
614                        *fp = nfp;
615                        nfp = NULL;
616                } else
617                        *fp = NULL;
618        }
619        if (nfp != NULL)
620                fdrop(nfp, td);
621        fdrop(headfp, td);
622        return (error);
623}
624
625#ifndef __rtems__
626int
627sys_accept(td, uap)
628        struct thread *td;
629        struct accept_args *uap;
630{
631
632        return (accept1(td, uap->s, uap->name, uap->anamelen, ACCEPT4_INHERIT));
633}
634
635int
636sys_accept4(td, uap)
637        struct thread *td;
638        struct accept4_args *uap;
639{
640
641        if (uap->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
642                return (EINVAL);
643
644        return (accept1(td, uap->s, uap->name, uap->anamelen, uap->flags));
645}
646
647#ifdef COMPAT_OLDSOCK
648int
649oaccept(td, uap)
650        struct thread *td;
651        struct accept_args *uap;
652{
653
654        return (accept1(td, uap->s, uap->name, uap->anamelen,
655            ACCEPT4_INHERIT | ACCEPT4_COMPAT));
656}
657#endif /* COMPAT_OLDSOCK */
658#endif /* __rtems__ */
659
660#ifdef __rtems__
661static int kern_connectat(struct thread *td, int dirfd, int fd,
662    struct sockaddr *sa);
663
664static
665#endif /* __rtems__ */
666int
667sys_connect(struct thread *td, struct connect_args *uap)
668{
669        struct sockaddr *sa;
670        int error;
671
672        error = getsockaddr(&sa, uap->name, uap->namelen);
673        if (error == 0) {
674                error = kern_connectat(td, AT_FDCWD, uap->s, sa);
675                free(sa, M_SONAME);
676        }
677        return (error);
678}
679#ifdef __rtems__
680int
681connect(int socket, const struct sockaddr *address, socklen_t address_len)
682{
683        struct thread *td = rtems_bsd_get_curthread_or_null();
684        struct connect_args ua = {
685                .s = socket,
686                .name = (caddr_t) address,
687                .namelen = address_len
688        };
689        int error;
690
691        if (td != NULL) {
692                error = sys_connect(td, &ua);
693        } else {
694                error = ENOMEM;
695        }
696
697        return rtems_bsd_error_to_status_and_errno(error);
698}
699#endif /* __rtems__ */
700
701int
702kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
703{
704        struct socket *so;
705        struct file *fp;
706        cap_rights_t rights;
707        int error, interrupted = 0;
708
709        AUDIT_ARG_FD(fd);
710        AUDIT_ARG_SOCKADDR(td, dirfd, sa);
711        error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_CONNECT),
712            &fp, NULL, NULL);
713        if (error != 0)
714                return (error);
715        so = fp->f_data;
716        if (so->so_state & SS_ISCONNECTING) {
717                error = EALREADY;
718                goto done1;
719        }
720#ifdef KTRACE
721        if (KTRPOINT(td, KTR_STRUCT))
722                ktrsockaddr(sa);
723#endif
724#ifdef MAC
725        error = mac_socket_check_connect(td->td_ucred, so, sa);
726        if (error != 0)
727                goto bad;
728#endif
729        if (dirfd == AT_FDCWD)
730                error = soconnect(so, sa, td);
731        else
732                error = soconnectat(dirfd, so, sa, td);
733        if (error != 0)
734                goto bad;
735        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
736                error = EINPROGRESS;
737                goto done1;
738        }
739        SOCK_LOCK(so);
740        while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
741                error = msleep(&so->so_timeo, SOCK_MTX(so), PSOCK | PCATCH,
742                    "connec", 0);
743                if (error != 0) {
744                        if (error == EINTR || error == ERESTART)
745                                interrupted = 1;
746                        break;
747                }
748        }
749        if (error == 0) {
750                error = so->so_error;
751                so->so_error = 0;
752        }
753        SOCK_UNLOCK(so);
754bad:
755        if (!interrupted)
756                so->so_state &= ~SS_ISCONNECTING;
757        if (error == ERESTART)
758                error = EINTR;
759done1:
760        fdrop(fp, td);
761        return (error);
762}
763
764#ifndef __rtems__
765int
766sys_connectat(struct thread *td, struct connectat_args *uap)
767{
768        struct sockaddr *sa;
769        int error;
770
771        error = getsockaddr(&sa, uap->name, uap->namelen);
772        if (error == 0) {
773                error = kern_connectat(td, uap->fd, uap->s, sa);
774                free(sa, M_SONAME);
775        }
776        return (error);
777}
778#endif /* __rtems__ */
779
780int
781kern_socketpair(struct thread *td, int domain, int type, int protocol,
782    int *rsv)
783{
784        struct file *fp1, *fp2;
785        struct socket *so1, *so2;
786        int fd, error, oflag, fflag;
787
788        AUDIT_ARG_SOCKET(domain, type, protocol);
789
790        oflag = 0;
791        fflag = 0;
792        if ((type & SOCK_CLOEXEC) != 0) {
793                type &= ~SOCK_CLOEXEC;
794                oflag |= O_CLOEXEC;
795        }
796        if ((type & SOCK_NONBLOCK) != 0) {
797                type &= ~SOCK_NONBLOCK;
798                fflag |= FNONBLOCK;
799        }
800#ifdef MAC
801        /* We might want to have a separate check for socket pairs. */
802        error = mac_socket_check_create(td->td_ucred, domain, type,
803            protocol);
804        if (error != 0)
805                return (error);
806#endif
807        error = socreate(domain, &so1, type, protocol, td->td_ucred, td);
808        if (error != 0)
809                return (error);
810        error = socreate(domain, &so2, type, protocol, td->td_ucred, td);
811        if (error != 0)
812                goto free1;
813        /* On success extra reference to `fp1' and 'fp2' is set by falloc. */
814        error = falloc(td, &fp1, &fd, oflag);
815        if (error != 0)
816                goto free2;
817        rsv[0] = fd;
818        fp1->f_data = so1;      /* so1 already has ref count */
819        error = falloc(td, &fp2, &fd, oflag);
820        if (error != 0)
821                goto free3;
822        fp2->f_data = so2;      /* so2 already has ref count */
823        rsv[1] = fd;
824        error = soconnect2(so1, so2);
825        if (error != 0)
826                goto free4;
827        if (type == SOCK_DGRAM) {
828                /*
829                 * Datagram socket connection is asymmetric.
830                 */
831                 error = soconnect2(so2, so1);
832                 if (error != 0)
833                        goto free4;
834        }
835        finit(fp1, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp1->f_data,
836            &socketops);
837        finit(fp2, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp2->f_data,
838            &socketops);
839        if ((fflag & FNONBLOCK) != 0) {
840                (void) fo_ioctl(fp1, FIONBIO, &fflag, td->td_ucred, td);
841                (void) fo_ioctl(fp2, FIONBIO, &fflag, td->td_ucred, td);
842        }
843        fdrop(fp1, td);
844        fdrop(fp2, td);
845        return (0);
846free4:
847        fdclose(td, fp2, rsv[1]);
848        fdrop(fp2, td);
849free3:
850        fdclose(td, fp1, rsv[0]);
851        fdrop(fp1, td);
852free2:
853        if (so2 != NULL)
854                (void)soclose(so2);
855free1:
856        if (so1 != NULL)
857                (void)soclose(so1);
858        return (error);
859}
860
861#ifdef __rtems__
862static
863#endif /* __rtems__ */
864int
865sys_socketpair(struct thread *td, struct socketpair_args *uap)
866{
867#ifndef __rtems__
868        int error, sv[2];
869#else /* __rtems__ */
870        int error;
871        int *sv = uap->rsv;
872#endif /* __rtems__ */
873
874        error = kern_socketpair(td, uap->domain, uap->type,
875            uap->protocol, sv);
876        if (error != 0)
877                return (error);
878#ifndef __rtems__
879        error = copyout(sv, uap->rsv, 2 * sizeof(int));
880        if (error != 0) {
881                (void)kern_close(td, sv[0]);
882                (void)kern_close(td, sv[1]);
883        }
884#endif /* __rtems__ */
885        return (error);
886}
887#ifdef __rtems__
888int
889socketpair(int domain, int type, int protocol, int *socket_vector)
890{
891        struct thread *td = rtems_bsd_get_curthread_or_null();
892        struct socketpair_args ua = {
893                .domain = domain,
894                .type = type,
895                .protocol = protocol,
896                .rsv = socket_vector
897        };
898        int error;
899
900        if (td != NULL) {
901                error = sys_socketpair(td, &ua);
902        } else {
903                error = ENOMEM;
904        }
905
906        return rtems_bsd_error_to_status_and_errno(error);
907}
908#endif /* __rtems__ */
909
910#ifdef __rtems__
911static int
912kern_sendit( struct thread *td, int s, struct msghdr *mp, int flags,
913    struct mbuf *control, enum uio_seg segflg);
914#endif /* __rtems__ */
915static int
916sendit(struct thread *td, int s, struct msghdr *mp, int flags)
917{
918        struct mbuf *control;
919        struct sockaddr *to;
920        int error;
921
922#ifdef CAPABILITY_MODE
923        if (IN_CAPABILITY_MODE(td) && (mp->msg_name != NULL))
924                return (ECAPMODE);
925#endif
926
927        if (mp->msg_name != NULL) {
928                error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
929                if (error != 0) {
930                        to = NULL;
931                        goto bad;
932                }
933                mp->msg_name = to;
934        } else {
935                to = NULL;
936        }
937
938        if (mp->msg_control) {
939                if (mp->msg_controllen < sizeof(struct cmsghdr)
940#ifdef COMPAT_OLDSOCK
941                    && mp->msg_flags != MSG_COMPAT
942#endif
943                ) {
944                        error = EINVAL;
945                        goto bad;
946                }
947                error = sockargs(&control, mp->msg_control,
948                    mp->msg_controllen, MT_CONTROL);
949                if (error != 0)
950                        goto bad;
951#ifdef COMPAT_OLDSOCK
952                if (mp->msg_flags == MSG_COMPAT) {
953                        struct cmsghdr *cm;
954
955                        M_PREPEND(control, sizeof(*cm), M_WAITOK);
956                        cm = mtod(control, struct cmsghdr *);
957                        cm->cmsg_len = control->m_len;
958                        cm->cmsg_level = SOL_SOCKET;
959                        cm->cmsg_type = SCM_RIGHTS;
960                }
961#endif
962        } else {
963                control = NULL;
964        }
965
966        error = kern_sendit(td, s, mp, flags, control, UIO_USERSPACE);
967
968bad:
969        free(to, M_SONAME);
970        return (error);
971}
972
973int
974kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
975    struct mbuf *control, enum uio_seg segflg)
976{
977        struct file *fp;
978        struct uio auio;
979        struct iovec *iov;
980        struct socket *so;
981#ifndef __rtems__
982        cap_rights_t rights;
983#endif /* __rtems__ */
984#ifdef KTRACE
985        struct uio *ktruio = NULL;
986#endif
987        ssize_t len;
988        int i, error;
989
990        AUDIT_ARG_FD(s);
991#ifndef __rtems__
992        cap_rights_init(&rights, CAP_SEND);
993        if (mp->msg_name != NULL) {
994                AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name);
995                cap_rights_set(&rights, CAP_CONNECT);
996        }
997#endif /* __rtems__ */
998        error = getsock_cap(td, s, &rights, &fp, NULL, NULL);
999        if (error != 0) {
1000                m_freem(control);
1001                return (error);
1002        }
1003        so = (struct socket *)fp->f_data;
1004
1005#ifdef KTRACE
1006        if (mp->msg_name != NULL && KTRPOINT(td, KTR_STRUCT))
1007                ktrsockaddr(mp->msg_name);
1008#endif
1009#ifdef MAC
1010        if (mp->msg_name != NULL) {
1011                error = mac_socket_check_connect(td->td_ucred, so,
1012                    mp->msg_name);
1013                if (error != 0) {
1014                        m_freem(control);
1015                        goto bad;
1016                }
1017        }
1018        error = mac_socket_check_send(td->td_ucred, so);
1019        if (error != 0) {
1020                m_freem(control);
1021                goto bad;
1022        }
1023#endif
1024
1025        auio.uio_iov = mp->msg_iov;
1026        auio.uio_iovcnt = mp->msg_iovlen;
1027        auio.uio_segflg = segflg;
1028        auio.uio_rw = UIO_WRITE;
1029        auio.uio_td = td;
1030        auio.uio_offset = 0;                    /* XXX */
1031        auio.uio_resid = 0;
1032        iov = mp->msg_iov;
1033        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
1034                if ((auio.uio_resid += iov->iov_len) < 0) {
1035                        error = EINVAL;
1036                        m_freem(control);
1037                        goto bad;
1038                }
1039        }
1040#ifdef KTRACE
1041        if (KTRPOINT(td, KTR_GENIO))
1042                ktruio = cloneuio(&auio);
1043#endif
1044        len = auio.uio_resid;
1045        error = sosend(so, mp->msg_name, &auio, 0, control, flags, td);
1046        if (error != 0) {
1047                if (auio.uio_resid != len && (error == ERESTART ||
1048                    error == EINTR || error == EWOULDBLOCK))
1049                        error = 0;
1050                /* Generation of SIGPIPE can be controlled per socket */
1051                if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&
1052                    !(flags & MSG_NOSIGNAL)) {
1053#ifndef __rtems__
1054                        PROC_LOCK(td->td_proc);
1055                        tdsignal(td, SIGPIPE);
1056                        PROC_UNLOCK(td->td_proc);
1057#else /* __rtems__ */
1058                /* FIXME: Determine if we really want to use signals */
1059#endif /* __rtems__ */
1060                }
1061        }
1062        if (error == 0)
1063                td->td_retval[0] = len - auio.uio_resid;
1064#ifdef KTRACE
1065        if (ktruio != NULL) {
1066                ktruio->uio_resid = td->td_retval[0];
1067                ktrgenio(s, UIO_WRITE, ktruio, error);
1068        }
1069#endif
1070bad:
1071        fdrop(fp, td);
1072        return (error);
1073}
1074
1075#ifdef __rtems__
1076static
1077#endif /* __rtems__ */
1078int
1079sys_sendto(struct thread *td, struct sendto_args *uap)
1080{
1081        struct msghdr msg;
1082        struct iovec aiov;
1083
1084        msg.msg_name = uap->to;
1085        msg.msg_namelen = uap->tolen;
1086        msg.msg_iov = &aiov;
1087        msg.msg_iovlen = 1;
1088        msg.msg_control = 0;
1089#ifdef COMPAT_OLDSOCK
1090        msg.msg_flags = 0;
1091#endif
1092        aiov.iov_base = uap->buf;
1093        aiov.iov_len = uap->len;
1094        return (sendit(td, uap->s, &msg, uap->flags));
1095}
1096#ifdef __rtems__
1097ssize_t
1098sendto(int socket, const void *message, size_t length, int flags,
1099    const struct sockaddr *dest_addr, socklen_t dest_len)
1100{
1101        struct thread *td = rtems_bsd_get_curthread_or_null();
1102        struct sendto_args ua = {
1103                .s = socket,
1104                .buf = (caddr_t) message,
1105                .len = length,
1106                .flags = flags,
1107                .to = (caddr_t) dest_addr,
1108                .tolen = dest_len
1109        };
1110        int error;
1111
1112        if (td != NULL) {
1113                error = sys_sendto(td, &ua);
1114        } else {
1115                error = ENOMEM;
1116        }
1117
1118        if (error == 0) {
1119                return td->td_retval[0];
1120        } else {
1121                rtems_set_errno_and_return_minus_one(error);
1122        }
1123}
1124
1125int
1126rtems_bsd_sendto(int socket, struct mbuf *m, int flags,
1127    const struct sockaddr *dest_addr)
1128{
1129        struct thread *td = rtems_bsd_get_curthread_or_null();
1130        struct file *fp;
1131        struct socket *so;
1132        int error;
1133
1134        error = getsock_cap(td->td_proc->p_fd, socket, CAP_WRITE, &fp, NULL, NULL);
1135        if (error)
1136                return (error);
1137        so = (struct socket *)fp->f_data;
1138
1139        if (td != NULL) {
1140                error = sosend(so, __DECONST(struct sockaddr *, dest_addr),
1141                    NULL, m, NULL, flags, td);
1142        } else {
1143                error = ENOMEM;
1144        }
1145
1146        return (error);
1147}
1148#endif /* __rtems__ */
1149
1150#ifndef __rtems__
1151#ifdef COMPAT_OLDSOCK
1152int
1153osend(struct thread *td, struct osend_args *uap)
1154{
1155        struct msghdr msg;
1156        struct iovec aiov;
1157
1158        msg.msg_name = 0;
1159        msg.msg_namelen = 0;
1160        msg.msg_iov = &aiov;
1161        msg.msg_iovlen = 1;
1162        aiov.iov_base = uap->buf;
1163        aiov.iov_len = uap->len;
1164        msg.msg_control = 0;
1165        msg.msg_flags = 0;
1166        return (sendit(td, uap->s, &msg, uap->flags));
1167}
1168
1169int
1170osendmsg(struct thread *td, struct osendmsg_args *uap)
1171{
1172        struct msghdr msg;
1173        struct iovec *iov;
1174        int error;
1175
1176        error = copyin(uap->msg, &msg, sizeof (struct omsghdr));
1177        if (error != 0)
1178                return (error);
1179        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1180        if (error != 0)
1181                return (error);
1182        msg.msg_iov = iov;
1183        msg.msg_flags = MSG_COMPAT;
1184        error = sendit(td, uap->s, &msg, uap->flags);
1185        free(iov, M_IOV);
1186        return (error);
1187}
1188#endif
1189#endif /* __rtems__ */
1190
1191#ifdef __rtems__
1192static
1193#endif /* __rtems__ */
1194int
1195sys_sendmsg(struct thread *td, struct sendmsg_args *uap)
1196{
1197        struct msghdr msg;
1198        struct iovec *iov;
1199        int error;
1200
1201        error = copyin(uap->msg, &msg, sizeof (msg));
1202        if (error != 0)
1203                return (error);
1204        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1205        if (error != 0)
1206                return (error);
1207        msg.msg_iov = iov;
1208#ifdef COMPAT_OLDSOCK
1209        msg.msg_flags = 0;
1210#endif
1211        error = sendit(td, uap->s, &msg, uap->flags);
1212        free(iov, M_IOV);
1213        return (error);
1214}
1215#ifdef __rtems__
1216ssize_t
1217sendmsg(int socket, const struct msghdr *message, int flags)
1218{
1219        struct thread *td = rtems_bsd_get_curthread_or_null();
1220        struct sendmsg_args ua = {
1221                .s = socket,
1222                .msg = message,
1223                .flags = flags
1224        };
1225        int error;
1226
1227        if (td != NULL) {
1228                error = sys_sendmsg(td, &ua);
1229        } else {
1230                error = ENOMEM;
1231        }
1232
1233        if (error == 0) {
1234                return td->td_retval[0];
1235        } else {
1236                rtems_set_errno_and_return_minus_one(error);
1237        }
1238}
1239#endif /* __rtems__ */
1240
1241#ifdef __rtems__
1242static
1243#endif /* __rtems__ */
1244int
1245kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg,
1246    struct mbuf **controlp)
1247{
1248        struct uio auio;
1249        struct iovec *iov;
1250        struct mbuf *m, *control = NULL;
1251        caddr_t ctlbuf;
1252        struct file *fp;
1253        struct socket *so;
1254        struct sockaddr *fromsa = NULL;
1255        cap_rights_t rights;
1256#ifdef KTRACE
1257        struct uio *ktruio = NULL;
1258#endif
1259        ssize_t len;
1260        int error, i;
1261
1262        if (controlp != NULL)
1263                *controlp = NULL;
1264
1265        AUDIT_ARG_FD(s);
1266        error = getsock_cap(td, s, cap_rights_init(&rights, CAP_RECV),
1267            &fp, NULL, NULL);
1268        if (error != 0)
1269                return (error);
1270        so = fp->f_data;
1271
1272#ifdef MAC
1273        error = mac_socket_check_receive(td->td_ucred, so);
1274        if (error != 0) {
1275                fdrop(fp, td);
1276                return (error);
1277        }
1278#endif
1279
1280        auio.uio_iov = mp->msg_iov;
1281        auio.uio_iovcnt = mp->msg_iovlen;
1282        auio.uio_segflg = UIO_USERSPACE;
1283        auio.uio_rw = UIO_READ;
1284        auio.uio_td = td;
1285        auio.uio_offset = 0;                    /* XXX */
1286        auio.uio_resid = 0;
1287        iov = mp->msg_iov;
1288        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
1289                if ((auio.uio_resid += iov->iov_len) < 0) {
1290                        fdrop(fp, td);
1291                        return (EINVAL);
1292                }
1293        }
1294#ifdef KTRACE
1295        if (KTRPOINT(td, KTR_GENIO))
1296                ktruio = cloneuio(&auio);
1297#endif
1298        len = auio.uio_resid;
1299        error = soreceive(so, &fromsa, &auio, NULL,
1300            (mp->msg_control || controlp) ? &control : NULL,
1301            &mp->msg_flags);
1302        if (error != 0) {
1303                if (auio.uio_resid != len && (error == ERESTART ||
1304                    error == EINTR || error == EWOULDBLOCK))
1305                        error = 0;
1306        }
1307        if (fromsa != NULL)
1308                AUDIT_ARG_SOCKADDR(td, AT_FDCWD, fromsa);
1309#ifdef KTRACE
1310        if (ktruio != NULL) {
1311                ktruio->uio_resid = len - auio.uio_resid;
1312                ktrgenio(s, UIO_READ, ktruio, error);
1313        }
1314#endif
1315        if (error != 0)
1316                goto out;
1317        td->td_retval[0] = len - auio.uio_resid;
1318        if (mp->msg_name) {
1319                len = mp->msg_namelen;
1320                if (len <= 0 || fromsa == NULL)
1321                        len = 0;
1322                else {
1323                        /* save sa_len before it is destroyed by MSG_COMPAT */
1324                        len = MIN(len, fromsa->sa_len);
1325#ifdef COMPAT_OLDSOCK
1326                        if (mp->msg_flags & MSG_COMPAT)
1327                                ((struct osockaddr *)fromsa)->sa_family =
1328                                    fromsa->sa_family;
1329#endif
1330                        if (fromseg == UIO_USERSPACE) {
1331                                error = copyout(fromsa, mp->msg_name,
1332                                    (unsigned)len);
1333                                if (error != 0)
1334                                        goto out;
1335                        } else
1336                                bcopy(fromsa, mp->msg_name, len);
1337                }
1338                mp->msg_namelen = len;
1339        }
1340        if (mp->msg_control && controlp == NULL) {
1341#ifdef COMPAT_OLDSOCK
1342                /*
1343                 * We assume that old recvmsg calls won't receive access
1344                 * rights and other control info, esp. as control info
1345                 * is always optional and those options didn't exist in 4.3.
1346                 * If we receive rights, trim the cmsghdr; anything else
1347                 * is tossed.
1348                 */
1349                if (control && mp->msg_flags & MSG_COMPAT) {
1350                        if (mtod(control, struct cmsghdr *)->cmsg_level !=
1351                            SOL_SOCKET ||
1352                            mtod(control, struct cmsghdr *)->cmsg_type !=
1353                            SCM_RIGHTS) {
1354                                mp->msg_controllen = 0;
1355                                goto out;
1356                        }
1357                        control->m_len -= sizeof (struct cmsghdr);
1358                        control->m_data += sizeof (struct cmsghdr);
1359                }
1360#endif
1361                len = mp->msg_controllen;
1362                m = control;
1363                mp->msg_controllen = 0;
1364                ctlbuf = mp->msg_control;
1365
1366                while (m && len > 0) {
1367                        unsigned int tocopy;
1368
1369                        if (len >= m->m_len)
1370                                tocopy = m->m_len;
1371                        else {
1372                                mp->msg_flags |= MSG_CTRUNC;
1373                                tocopy = len;
1374                        }
1375
1376                        if ((error = copyout(mtod(m, caddr_t),
1377                                        ctlbuf, tocopy)) != 0)
1378                                goto out;
1379
1380                        ctlbuf += tocopy;
1381                        len -= tocopy;
1382                        m = m->m_next;
1383                }
1384                mp->msg_controllen = ctlbuf - (caddr_t)mp->msg_control;
1385        }
1386out:
1387        fdrop(fp, td);
1388#ifdef KTRACE
1389        if (fromsa && KTRPOINT(td, KTR_STRUCT))
1390                ktrsockaddr(fromsa);
1391#endif
1392        free(fromsa, M_SONAME);
1393
1394        if (error == 0 && controlp != NULL)
1395                *controlp = control;
1396        else  if (control)
1397                m_freem(control);
1398
1399        return (error);
1400}
1401
1402static int
1403recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp)
1404{
1405        int error;
1406
1407        error = kern_recvit(td, s, mp, UIO_USERSPACE, NULL);
1408        if (error != 0)
1409                return (error);
1410        if (namelenp != NULL) {
1411                error = copyout(&mp->msg_namelen, namelenp, sizeof (socklen_t));
1412#ifdef COMPAT_OLDSOCK
1413                if (mp->msg_flags & MSG_COMPAT)
1414                        error = 0;      /* old recvfrom didn't check */
1415#endif
1416        }
1417        return (error);
1418}
1419
1420#ifdef __rtems__
1421static
1422#endif /* __rtems__ */
1423int
1424sys_recvfrom(struct thread *td, struct recvfrom_args *uap)
1425{
1426        struct msghdr msg;
1427        struct iovec aiov;
1428        int error;
1429
1430        if (uap->fromlenaddr) {
1431                error = copyin(uap->fromlenaddr,
1432                    &msg.msg_namelen, sizeof (msg.msg_namelen));
1433                if (error != 0)
1434                        goto done2;
1435        } else {
1436                msg.msg_namelen = 0;
1437        }
1438        msg.msg_name = uap->from;
1439        msg.msg_iov = &aiov;
1440        msg.msg_iovlen = 1;
1441        aiov.iov_base = uap->buf;
1442        aiov.iov_len = uap->len;
1443        msg.msg_control = 0;
1444        msg.msg_flags = uap->flags;
1445        error = recvit(td, uap->s, &msg, uap->fromlenaddr);
1446done2:
1447        return (error);
1448}
1449#ifdef __rtems__
1450ssize_t
1451recvfrom(int socket, void *__restrict buffer, size_t length, int flags,
1452    struct sockaddr *__restrict address, socklen_t *__restrict address_len)
1453{
1454        struct thread *td = rtems_bsd_get_curthread_or_null();
1455        struct recvfrom_args ua = {
1456                .s = socket,
1457                .buf = buffer,
1458                .len = length,
1459                .flags = flags,
1460                .from = address,
1461                .fromlenaddr = address_len
1462        };
1463        int error;
1464
1465        if (td != NULL) {
1466                error = sys_recvfrom(td, &ua);
1467        } else {
1468                error = ENOMEM;
1469        }
1470
1471        if (error == 0) {
1472                return td->td_retval[0];
1473        } else {
1474                rtems_set_errno_and_return_minus_one(error);
1475        }
1476}
1477#endif /* __rtems__ */
1478
1479#ifndef __rtems__
1480#ifdef COMPAT_OLDSOCK
1481int
1482orecvfrom(struct thread *td, struct recvfrom_args *uap)
1483{
1484
1485        uap->flags |= MSG_COMPAT;
1486        return (sys_recvfrom(td, uap));
1487}
1488#endif
1489
1490#ifdef COMPAT_OLDSOCK
1491int
1492orecv(struct thread *td, struct orecv_args *uap)
1493{
1494        struct msghdr msg;
1495        struct iovec aiov;
1496
1497        msg.msg_name = 0;
1498        msg.msg_namelen = 0;
1499        msg.msg_iov = &aiov;
1500        msg.msg_iovlen = 1;
1501        aiov.iov_base = uap->buf;
1502        aiov.iov_len = uap->len;
1503        msg.msg_control = 0;
1504        msg.msg_flags = uap->flags;
1505        return (recvit(td, uap->s, &msg, NULL));
1506}
1507
1508/*
1509 * Old recvmsg.  This code takes advantage of the fact that the old msghdr
1510 * overlays the new one, missing only the flags, and with the (old) access
1511 * rights where the control fields are now.
1512 */
1513int
1514orecvmsg(struct thread *td, struct orecvmsg_args *uap)
1515{
1516        struct msghdr msg;
1517        struct iovec *iov;
1518        int error;
1519
1520        error = copyin(uap->msg, &msg, sizeof (struct omsghdr));
1521        if (error != 0)
1522                return (error);
1523        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1524        if (error != 0)
1525                return (error);
1526        msg.msg_flags = uap->flags | MSG_COMPAT;
1527        msg.msg_iov = iov;
1528        error = recvit(td, uap->s, &msg, &uap->msg->msg_namelen);
1529        if (msg.msg_controllen && error == 0)
1530                error = copyout(&msg.msg_controllen,
1531                    &uap->msg->msg_accrightslen, sizeof (int));
1532        free(iov, M_IOV);
1533        return (error);
1534}
1535#endif
1536#endif /* __rtems__ */
1537
1538#ifdef __rtems__
1539static
1540#endif /* __rtems__ */
1541int
1542sys_recvmsg(struct thread *td, struct recvmsg_args *uap)
1543{
1544        struct msghdr msg;
1545        struct iovec *uiov, *iov;
1546        int error;
1547
1548        error = copyin(uap->msg, &msg, sizeof (msg));
1549        if (error != 0)
1550                return (error);
1551        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1552        if (error != 0)
1553                return (error);
1554        msg.msg_flags = uap->flags;
1555#ifdef COMPAT_OLDSOCK
1556        msg.msg_flags &= ~MSG_COMPAT;
1557#endif
1558        uiov = msg.msg_iov;
1559        msg.msg_iov = iov;
1560        error = recvit(td, uap->s, &msg, NULL);
1561        if (error == 0) {
1562                msg.msg_iov = uiov;
1563                error = copyout(&msg, uap->msg, sizeof(msg));
1564        }
1565        free(iov, M_IOV);
1566        return (error);
1567}
1568#ifdef __rtems__
1569ssize_t
1570recvmsg(int socket, struct msghdr *message, int flags)
1571{
1572        struct thread *td = rtems_bsd_get_curthread_or_null();
1573        struct recvmsg_args ua = {
1574                .s = socket,
1575                .msg = message,
1576                .flags = flags
1577        };
1578        int error;
1579
1580        if (td != NULL) {
1581                error = sys_recvmsg(td, &ua);
1582        } else {
1583                error = ENOMEM;
1584        }
1585
1586        if (error == 0) {
1587                return td->td_retval[0];
1588        } else {
1589                rtems_set_errno_and_return_minus_one(error);
1590        }
1591}
1592#endif /* __rtems__ */
1593
1594#ifdef __rtems__
1595static
1596#endif /* __rtems__ */
1597int
1598sys_shutdown(struct thread *td, struct shutdown_args *uap)
1599{
1600
1601        return (kern_shutdown(td, uap->s, uap->how));
1602}
1603
1604int
1605kern_shutdown(struct thread *td, int s, int how)
1606{
1607        struct socket *so;
1608        struct file *fp;
1609        cap_rights_t rights;
1610        int error;
1611
1612        AUDIT_ARG_FD(s);
1613        error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SHUTDOWN),
1614            &fp, NULL, NULL);
1615        if (error == 0) {
1616                so = fp->f_data;
1617                error = soshutdown(so, how);
1618#ifndef __rtems__
1619                /*
1620                 * Previous versions did not return ENOTCONN, but 0 in
1621                 * case the socket was not connected. Some important
1622                 * programs like syslogd up to r279016, 2015-02-19,
1623                 * still depend on this behavior.
1624                 */
1625                if (error == ENOTCONN &&
1626                    td->td_proc->p_osrel < P_OSREL_SHUTDOWN_ENOTCONN)
1627                        error = 0;
1628#endif /* __rtems__ */
1629                fdrop(fp, td);
1630        }
1631        return (error);
1632}
1633#ifdef __rtems__
1634int
1635shutdown(int socket, int how)
1636{
1637        struct shutdown_args ua = {
1638                .s = socket,
1639                .how = how
1640        };
1641        int error = sys_shutdown(NULL, &ua);
1642
1643        return rtems_bsd_error_to_status_and_errno(error);
1644}
1645#endif /* __rtems__ */
1646
1647#ifdef __rtems__
1648static int kern_setsockopt( struct thread *td, int s, int level, int name,
1649    void *val, enum uio_seg valseg, socklen_t valsize);
1650
1651static
1652#endif /* __rtems__ */
1653int
1654sys_setsockopt(struct thread *td, struct setsockopt_args *uap)
1655{
1656
1657        return (kern_setsockopt(td, uap->s, uap->level, uap->name,
1658            uap->val, UIO_USERSPACE, uap->valsize));
1659}
1660#ifdef __rtems__
1661int
1662setsockopt(int socket, int level, int option_name, const void *option_value,
1663    socklen_t option_len)
1664{
1665        struct thread *td = rtems_bsd_get_curthread_or_null();
1666        struct setsockopt_args ua = {
1667                .s = socket,
1668                .level = level,
1669                .name = option_name,
1670                .val = __DECONST(void *, option_value),
1671                .valsize = option_len
1672        };
1673        int error;
1674
1675        if (td != NULL) {
1676                error = sys_setsockopt(td, &ua);
1677        } else {
1678                error = ENOMEM;
1679        }
1680
1681        return rtems_bsd_error_to_status_and_errno(error);
1682}
1683#endif /* __rtems__ */
1684
1685int
1686kern_setsockopt(struct thread *td, int s, int level, int name, void *val,
1687    enum uio_seg valseg, socklen_t valsize)
1688{
1689        struct socket *so;
1690        struct file *fp;
1691        struct sockopt sopt;
1692        cap_rights_t rights;
1693        int error;
1694
1695        if (val == NULL && valsize != 0)
1696                return (EFAULT);
1697        if ((int)valsize < 0)
1698                return (EINVAL);
1699
1700        sopt.sopt_dir = SOPT_SET;
1701        sopt.sopt_level = level;
1702        sopt.sopt_name = name;
1703        sopt.sopt_val = val;
1704        sopt.sopt_valsize = valsize;
1705        switch (valseg) {
1706        case UIO_USERSPACE:
1707                sopt.sopt_td = td;
1708                break;
1709        case UIO_SYSSPACE:
1710                sopt.sopt_td = NULL;
1711                break;
1712        default:
1713                panic("kern_setsockopt called with bad valseg");
1714        }
1715
1716        AUDIT_ARG_FD(s);
1717        error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SETSOCKOPT),
1718            &fp, NULL, NULL);
1719        if (error == 0) {
1720                so = fp->f_data;
1721                error = sosetopt(so, &sopt);
1722                fdrop(fp, td);
1723        }
1724        return(error);
1725}
1726
1727#ifdef __rtems__
1728static int kern_getsockopt( struct thread *td, int s, int level, int name,
1729    void *val, enum uio_seg valseg, socklen_t *valsize);
1730
1731static
1732#endif /* __rtems__ */
1733int
1734sys_getsockopt(struct thread *td, struct getsockopt_args *uap)
1735{
1736        socklen_t valsize;
1737        int error;
1738
1739        if (uap->val) {
1740                error = copyin(uap->avalsize, &valsize, sizeof (valsize));
1741                if (error != 0)
1742                        return (error);
1743        }
1744
1745        error = kern_getsockopt(td, uap->s, uap->level, uap->name,
1746            uap->val, UIO_USERSPACE, &valsize);
1747
1748        if (error == 0)
1749                error = copyout(&valsize, uap->avalsize, sizeof (valsize));
1750        return (error);
1751}
1752#ifdef __rtems__
1753int
1754getsockopt(int socket, int level, int option_name, void *__restrict
1755    option_value, socklen_t *__restrict option_len)
1756{
1757        struct thread *td = rtems_bsd_get_curthread_or_null();
1758        struct getsockopt_args ua = {
1759                .s = socket,
1760                .level = level,
1761                .name = option_name,
1762                .val = (caddr_t) option_value,
1763                .avalsize = option_len
1764        };
1765        int error;
1766
1767        if (td != NULL) {
1768                error = sys_getsockopt(td, &ua);
1769        } else {
1770                error = ENOMEM;
1771        }
1772
1773        return rtems_bsd_error_to_status_and_errno(error);
1774}
1775#endif /* __rtems__ */
1776
1777/*
1778 * Kernel version of getsockopt.
1779 * optval can be a userland or userspace. optlen is always a kernel pointer.
1780 */
1781int
1782kern_getsockopt(struct thread *td, int s, int level, int name, void *val,
1783    enum uio_seg valseg, socklen_t *valsize)
1784{
1785        struct socket *so;
1786        struct file *fp;
1787        struct sockopt sopt;
1788        cap_rights_t rights;
1789        int error;
1790
1791        if (val == NULL)
1792                *valsize = 0;
1793        if ((int)*valsize < 0)
1794                return (EINVAL);
1795
1796        sopt.sopt_dir = SOPT_GET;
1797        sopt.sopt_level = level;
1798        sopt.sopt_name = name;
1799        sopt.sopt_val = val;
1800        sopt.sopt_valsize = (size_t)*valsize; /* checked non-negative above */
1801        switch (valseg) {
1802        case UIO_USERSPACE:
1803                sopt.sopt_td = td;
1804                break;
1805        case UIO_SYSSPACE:
1806                sopt.sopt_td = NULL;
1807                break;
1808        default:
1809                panic("kern_getsockopt called with bad valseg");
1810        }
1811
1812        AUDIT_ARG_FD(s);
1813        error = getsock_cap(td, s, cap_rights_init(&rights, CAP_GETSOCKOPT),
1814            &fp, NULL, NULL);
1815        if (error == 0) {
1816                so = fp->f_data;
1817                error = sogetopt(so, &sopt);
1818                *valsize = sopt.sopt_valsize;
1819                fdrop(fp, td);
1820        }
1821        return (error);
1822}
1823
1824#ifdef __rtems__
1825int
1826kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
1827    socklen_t *alen);
1828#endif /* __rtems__ */
1829/*
1830 * getsockname1() - Get socket name.
1831 */
1832static int
1833getsockname1(struct thread *td, struct getsockname_args *uap, int compat)
1834{
1835        struct sockaddr *sa;
1836        socklen_t len;
1837        int error;
1838
1839        error = copyin(uap->alen, &len, sizeof(len));
1840        if (error != 0)
1841                return (error);
1842
1843        error = kern_getsockname(td, uap->fdes, &sa, &len);
1844        if (error != 0)
1845                return (error);
1846
1847        if (len != 0) {
1848#ifdef COMPAT_OLDSOCK
1849                if (compat)
1850                        ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1851#endif
1852                error = copyout(sa, uap->asa, (u_int)len);
1853        }
1854        free(sa, M_SONAME);
1855        if (error == 0)
1856                error = copyout(&len, uap->alen, sizeof(len));
1857        return (error);
1858}
1859#ifdef __rtems__
1860int
1861getsockname(int socket, struct sockaddr *__restrict address,
1862    socklen_t *__restrict address_len)
1863{
1864        struct thread *td = rtems_bsd_get_curthread_or_null();
1865        struct getsockname_args ua = {
1866                .fdes = socket,
1867                .asa = address,
1868                .alen = address_len
1869        };
1870        int error;
1871
1872        if (td != NULL) {
1873                error = getsockname1(td, &ua, 0);
1874        } else {
1875                error = ENOMEM;
1876        }
1877
1878        return rtems_bsd_error_to_status_and_errno(error);
1879}
1880#endif /* __rtems__ */
1881
1882int
1883kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
1884    socklen_t *alen)
1885{
1886        struct socket *so;
1887        struct file *fp;
1888        cap_rights_t rights;
1889        socklen_t len;
1890        int error;
1891
1892        AUDIT_ARG_FD(fd);
1893        error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETSOCKNAME),
1894            &fp, NULL, NULL);
1895        if (error != 0)
1896                return (error);
1897        so = fp->f_data;
1898        *sa = NULL;
1899        CURVNET_SET(so->so_vnet);
1900        error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, sa);
1901        CURVNET_RESTORE();
1902        if (error != 0)
1903                goto bad;
1904        if (*sa == NULL)
1905                len = 0;
1906        else
1907                len = MIN(*alen, (*sa)->sa_len);
1908        *alen = len;
1909#ifdef KTRACE
1910        if (KTRPOINT(td, KTR_STRUCT))
1911                ktrsockaddr(*sa);
1912#endif
1913bad:
1914        fdrop(fp, td);
1915        if (error != 0 && *sa != NULL) {
1916                free(*sa, M_SONAME);
1917                *sa = NULL;
1918        }
1919        return (error);
1920}
1921
1922#ifndef __rtems__
1923int
1924sys_getsockname(struct thread *td, struct getsockname_args *uap)
1925{
1926
1927        return (getsockname1(td, uap, 0));
1928}
1929
1930#ifdef COMPAT_OLDSOCK
1931int
1932ogetsockname(struct thread *td, struct getsockname_args *uap)
1933{
1934
1935        return (getsockname1(td, uap, 1));
1936}
1937#endif /* COMPAT_OLDSOCK */
1938#endif /* __rtems__ */
1939
1940#ifdef __rtems__
1941static int
1942kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
1943    socklen_t *alen);
1944#endif /* __rtems__ */
1945/*
1946 * getpeername1() - Get name of peer for connected socket.
1947 */
1948static int
1949getpeername1(struct thread *td, struct getpeername_args *uap, int compat)
1950{
1951        struct sockaddr *sa;
1952        socklen_t len;
1953        int error;
1954
1955        error = copyin(uap->alen, &len, sizeof (len));
1956        if (error != 0)
1957                return (error);
1958
1959        error = kern_getpeername(td, uap->fdes, &sa, &len);
1960        if (error != 0)
1961                return (error);
1962
1963        if (len != 0) {
1964#ifdef COMPAT_OLDSOCK
1965                if (compat)
1966                        ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1967#endif
1968                error = copyout(sa, uap->asa, (u_int)len);
1969        }
1970        free(sa, M_SONAME);
1971        if (error == 0)
1972                error = copyout(&len, uap->alen, sizeof(len));
1973        return (error);
1974}
1975#ifdef __rtems__
1976int
1977getpeername(int socket, struct sockaddr *__restrict address,
1978    socklen_t *__restrict address_len)
1979{
1980        struct thread *td = rtems_bsd_get_curthread_or_null();
1981        struct getpeername_args ua = {
1982                .fdes = socket,
1983                .asa = address,
1984                .alen = address_len
1985        };
1986        int error;
1987
1988        if (td != NULL) {
1989                error = getpeername1(td, &ua, 0);
1990        } else {
1991                error = ENOMEM;
1992        }
1993
1994        return rtems_bsd_error_to_status_and_errno(error);
1995}
1996#endif /* __rtems__ */
1997
1998int
1999kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
2000    socklen_t *alen)
2001{
2002        struct socket *so;
2003        struct file *fp;
2004        cap_rights_t rights;
2005        socklen_t len;
2006        int error;
2007
2008        AUDIT_ARG_FD(fd);
2009        error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETPEERNAME),
2010            &fp, NULL, NULL);
2011        if (error != 0)
2012                return (error);
2013        so = fp->f_data;
2014        if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
2015                error = ENOTCONN;
2016                goto done;
2017        }
2018        *sa = NULL;
2019        CURVNET_SET(so->so_vnet);
2020        error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, sa);
2021        CURVNET_RESTORE();
2022        if (error != 0)
2023                goto bad;
2024        if (*sa == NULL)
2025                len = 0;
2026        else
2027                len = MIN(*alen, (*sa)->sa_len);
2028        *alen = len;
2029#ifdef KTRACE
2030        if (KTRPOINT(td, KTR_STRUCT))
2031                ktrsockaddr(*sa);
2032#endif
2033bad:
2034        if (error != 0 && *sa != NULL) {
2035                free(*sa, M_SONAME);
2036                *sa = NULL;
2037        }
2038done:
2039        fdrop(fp, td);
2040        return (error);
2041}
2042
2043#ifndef __rtems__
2044int
2045sys_getpeername(struct thread *td, struct getpeername_args *uap)
2046{
2047
2048        return (getpeername1(td, uap, 0));
2049}
2050
2051#ifdef COMPAT_OLDSOCK
2052int
2053ogetpeername(struct thread *td, struct ogetpeername_args *uap)
2054{
2055
2056        /* XXX uap should have type `getpeername_args *' to begin with. */
2057        return (getpeername1(td, (struct getpeername_args *)uap, 1));
2058}
2059#endif /* COMPAT_OLDSOCK */
2060#endif /* __rtems__ */
2061
2062static int
2063sockargs(struct mbuf **mp, char *buf, socklen_t buflen, int type)
2064{
2065        struct sockaddr *sa;
2066        struct mbuf *m;
2067        int error;
2068
2069        if (buflen > MLEN) {
2070#ifdef COMPAT_OLDSOCK
2071                if (type == MT_SONAME && buflen <= 112)
2072                        buflen = MLEN;          /* unix domain compat. hack */
2073                else
2074#endif
2075                        if (buflen > MCLBYTES)
2076                                return (EINVAL);
2077        }
2078        m = m_get2(buflen, M_WAITOK, type, 0);
2079        m->m_len = buflen;
2080        error = copyin(buf, mtod(m, void *), buflen);
2081        if (error != 0)
2082                (void) m_free(m);
2083        else {
2084                *mp = m;
2085                if (type == MT_SONAME) {
2086                        sa = mtod(m, struct sockaddr *);
2087
2088#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
2089                        if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
2090                                sa->sa_family = sa->sa_len;
2091#endif
2092                        sa->sa_len = buflen;
2093                }
2094        }
2095        return (error);
2096}
2097
2098int
2099getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len)
2100{
2101        struct sockaddr *sa;
2102        int error;
2103
2104        if (len > SOCK_MAXADDRLEN)
2105                return (ENAMETOOLONG);
2106        if (len < offsetof(struct sockaddr, sa_data[0]))
2107                return (EINVAL);
2108        sa = malloc(len, M_SONAME, M_WAITOK);
2109        error = copyin(uaddr, sa, len);
2110        if (error != 0) {
2111                free(sa, M_SONAME);
2112        } else {
2113#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
2114                if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
2115                        sa->sa_family = sa->sa_len;
2116#endif
2117                sa->sa_len = len;
2118                *namp = sa;
2119        }
2120        return (error);
2121}
Note: See TracBrowser for help on using the repository browser.