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

55-freebsd-126-freebsd-12
Last change on this file since 3489e3b was 3489e3b, checked in by Sebastian Huber <sebastian.huber@…>, on 08/22/18 at 12:59:50

Update to FreeBSD head 2018-09-17

Git mirror commit 6c2192b1ef8c50788c751f878552526800b1e319.

Update #3472.

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