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

55-freebsd-126-freebsd-12
Last change on this file since 0963419 was 0963419, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 24, 2018 at 7:06:14 AM

Fix alignment of getsockaddr_sockaddr

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