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

55-freebsd-126-freebsd-12
Last change on this file since b03a1c0 was b03a1c0, checked in by Sebastian Huber <sebastian.huber@…>, on 11/15/17 at 12:24:29

Fix file descriptor reference counting in accept()

Update #3132.

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