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

5-freebsd-12
Last change on this file since 94b5368 was 94b5368, checked in by Sebastian Huber <sebastian.huber@…>, on Jul 2, 2018 at 6:21:37 AM

Avoid malloc() in getsockaddr()

The getsockaddr() function is used to allocate a struct sockaddr of the
right length and initialize it with userspace provided data. It is used
for the connect(), bind() and sendit() family functions. In particular,
the sendit() function is used by the UDP send functions. This means
each UDP send needs a malloc() and free() invocation. This is a
performance problem in RTEMS (first-fit heap) and may lead to heap
fragmentation. Replace the malloc() allocation with a stack allocation.
This requires SOCK_MAXADDRLEN (= 255) of additional stack space for
libbsd.

A further optimization would be to get rid of the stack copy of the
socket address. However, this would require to check each consumer of
the address to ensure that it is not modified.

  • 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};
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.