source: rtems-libbsd/rtemsbsd/src/rtems-bsd-syscalls.c @ 8420b94

4.115-freebsd-12freebsd-9.3
Last change on this file since 8420b94 was 8420b94, checked in by Jennifer Averett <jennifer.averett@…>, on May 8, 2012 at 2:14:42 PM

Modified copyright on rtems-bsd-xxx files to be consistant with FreeBSD copyright.

  • Property mode set to 100644
File size: 29.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2009, 2010 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Obere Lagerstr. 30
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40#include <freebsd/machine/rtems-bsd-config.h>
41
42#include <freebsd/sys/types.h>
43#include <freebsd/sys/param.h>
44#include <freebsd/sys/systm.h>
45#include <freebsd/sys/kernel.h>
46#include <freebsd/sys/lock.h>
47#include <freebsd/sys/mutex.h>
48#include <freebsd/sys/malloc.h>
49#include <freebsd/sys/proc.h>
50#include <freebsd/sys/fcntl.h>
51#include <freebsd/sys/protosw.h>
52#include <freebsd/sys/mbuf.h>
53#include <freebsd/sys/socket.h>
54#include <freebsd/sys/socketvar.h>
55#include <freebsd/sys/uio.h>
56#include <freebsd/machine/pcpu.h>
57#include <freebsd/net/vnet.h>
58
59#include <rtems/libio_.h>
60#include <rtems/libio.h>
61#include <rtems/seterr.h>
62
63static const rtems_filesystem_file_handlers_r socket_handlers;
64extern int killinfo( pid_t pid, int sig, const union sigval *value );
65
66/*
67 * Convert an RTEMS file descriptor to a BSD socket pointer.
68 */
69
70struct socket *rtems_bsdnet_fdToSocket(
71  int fd
72)
73{
74  rtems_libio_t *iop;
75
76  /* same as rtems_libio_check_fd(_fd) but different return */
77  if ((uint32_t)fd >= rtems_libio_number_iops) {
78    errno = EBADF;
79    return NULL;
80  }
81  iop = &rtems_libio_iops[fd];
82
83  /* same as rtems_libio_check_is_open(iop) but different return */
84  if ((iop->flags & LIBIO_FLAGS_OPEN) == 0) {
85    errno = EBADF;
86    return NULL;
87  }
88
89  if (iop->data1 == NULL)
90    errno = EBADF;
91  return iop->data1;
92}
93
94/*
95 * Create an RTEMS file descriptor for a socket
96 */
97
98int rtems_bsdnet_makeFdForSocket(
99  void *so,
100  const rtems_filesystem_file_handlers_r *h
101)
102{
103  rtems_libio_t *iop;
104  int fd;
105
106  iop = rtems_libio_allocate();
107  if (iop == 0)
108      rtems_set_errno_and_return_minus_one( ENFILE );
109
110  fd = iop - rtems_libio_iops;
111  iop->flags |= LIBIO_FLAGS_WRITE | LIBIO_FLAGS_READ;
112  iop->data0 = fd;
113  iop->data1 = so;
114  iop->pathinfo.handlers = h;
115  iop->pathinfo.ops = &rtems_filesystem_operations_default;
116  return fd;
117}
118
119/*
120 * The following code is based on FreeBSD uipc_syscalls.c
121 */
122
123int
124sockargs(mp, buf, buflen, type)
125        struct mbuf **mp;
126        caddr_t buf;
127        int buflen, type;
128{
129        struct sockaddr *sa;
130        struct mbuf *m;
131        int error;
132
133        if ((u_int)buflen > MLEN) {
134#ifdef COMPAT_OLDSOCK
135                if (type == MT_SONAME && (u_int)buflen <= 112)
136                        buflen = MLEN;          /* unix domain compat. hack */
137                else
138#endif
139                        if ((u_int)buflen > MCLBYTES)
140                                return (EINVAL);
141        }
142        m = m_get(M_WAIT, type);
143        if ((u_int)buflen > MLEN)
144                MCLGET(m, M_WAIT);
145        m->m_len = buflen;
146        error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
147        if (error)
148                (void) m_free(m);
149        else {
150                *mp = m;
151                if (type == MT_SONAME) {
152                        sa = mtod(m, struct sockaddr *);
153
154#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
155                        if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
156                                sa->sa_family = sa->sa_len;
157#endif
158                        sa->sa_len = buflen;
159                }
160        }
161        return (error);
162}
163
164int
165getsockaddr(namp, uaddr, len)
166        struct sockaddr **namp;
167        caddr_t uaddr;
168        size_t len;
169{
170        struct sockaddr *sa;
171        int error;
172
173        if (len > SOCK_MAXADDRLEN)
174                return (ENAMETOOLONG);
175        if (len < offsetof(struct sockaddr, sa_data[0]))
176                return (EINVAL);
177        sa = malloc(len, M_SONAME, M_WAITOK);
178        error = copyin(uaddr, sa, len);
179        if (error) {
180                free(sa, M_SONAME);
181        } else {
182#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
183                if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
184                        sa->sa_family = sa->sa_len;
185#endif
186                sa->sa_len = len;
187                *namp = sa;
188        }
189        return (error);
190}
191
192/*
193 *********************************************************************
194 *                       BSD-style entry points                      *
195 *********************************************************************
196 */
197int
198socket (int domain, int type, int protocol)
199{
200        struct thread *td;
201        struct socket *so;
202        int fd, error;
203
204        td = curthread;
205#ifdef MAC
206        error = mac_socket_check_create(td->td_ucred, domain, type, protocol);
207        if (error == 0 )
208        {
209#endif
210                /* An extra reference on `fp' has been held for us by falloc(). */
211                error = socreate(domain, &so, type, protocol, td->td_ucred, td);
212                if (error == 0) {
213                        fd = rtems_bsdnet_makeFdForSocket (so, &socket_handlers);
214                        if (fd < 0)
215                        {
216                                soclose (so);
217                                error = EBADF;
218                        }
219                }
220#ifdef MAC
221        }
222#endif
223        if( error == 0 )
224        {
225                return fd;
226        }
227        errno = error;
228        return -1;
229}
230
231int
232kern_bind(td, fd, sa)
233        struct thread *td;
234        int fd;
235        struct sockaddr *sa;
236{
237        struct socket *so;
238        int error;
239
240        if ((so = rtems_bsdnet_fdToSocket (fd)) == NULL) {
241                error = EBADF;
242                return (error);
243        }
244#ifdef KTRACE
245        if (KTRPOINT(td, KTR_STRUCT))
246                ktrsockaddr(sa);
247#endif
248#ifdef MAC
249        error = mac_socket_check_bind(td->td_ucred, so, sa);
250        if (error == 0)
251#endif
252                error = sobind(so, sa, td);
253        return (error);
254}
255
256int
257bind (int s, struct sockaddr *name, int namelen)
258{
259        struct thread *td;
260        struct sockaddr *sa;
261        int error;
262
263        error = getsockaddr(&sa, name, namelen);
264        if( error == 0 )
265        {
266                td = curthread;
267                error = kern_bind(td, s, sa);
268                free(sa, M_SONAME);
269        }
270        if( error == 0 )
271        {
272                return error;
273        }
274        errno = error;
275        return -1;
276}
277
278int
279kern_connect(td, fd, sa)
280        struct thread *td;
281        int fd;
282        struct sockaddr *sa;
283{
284        struct socket *so;
285        int error;
286        int interrupted = 0;
287
288        if ((so = rtems_bsdnet_fdToSocket (fd)) == NULL) {
289                error = EBADF;
290                return (error);
291        }
292
293        if (so->so_state & SS_ISCONNECTING) {
294                error = EALREADY;
295                goto done1;
296        }
297#ifdef KTRACE
298        if (KTRPOINT(td, KTR_STRUCT))
299                ktrsockaddr(sa);
300#endif
301#ifdef MAC
302        error = mac_socket_check_connect(td->td_ucred, so, sa);
303        if (error)
304                goto bad;
305#endif
306        error = soconnect(so, sa, td);
307        if (error)
308                goto bad;
309        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
310                error = EINPROGRESS;
311                goto done1;
312        }
313        SOCK_LOCK(so);
314        while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
315                error = msleep(&so->so_timeo, SOCK_MTX(so), PSOCK | PCATCH,
316                    "connec", 0);
317                if (error) {
318                        if (error == EINTR || error == ERESTART)
319                                interrupted = 1;
320                        break;
321                }
322        }
323        if (error == 0) {
324                error = so->so_error;
325                so->so_error = 0;
326        }
327        SOCK_UNLOCK(so);
328bad:
329        if (!interrupted)
330                so->so_state &= ~SS_ISCONNECTING;
331        if (error == ERESTART)
332                error = EINTR;
333done1:
334        return (error);
335}
336
337int
338connect (int s, struct sockaddr *name, int namelen)
339{
340        int error;
341        struct sockaddr *sa;
342        struct thread *td;
343
344        error = getsockaddr(&sa, name, namelen);
345        if (error == 0)
346        {
347                td = curthread;
348                error = kern_connect(td, s, sa);
349                free(sa, M_SONAME);
350        }
351        if( error == 0 )
352        {
353                return error;
354        }
355        errno = error;
356        return -1;
357}
358
359int
360listen (int s, int backlog)
361{
362        struct thread *td;
363        struct socket *so;
364        int error = 0;
365
366        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
367                error = EBADF;
368        }
369        if( error == 0 )
370        {
371                td = curthread;
372#ifdef MAC
373                error = mac_socket_check_listen(td->td_ucred, so);
374                if (error == 0) {
375#endif
376                        CURVNET_SET(so->so_vnet);
377                        error = solisten(so, backlog, td);
378                        CURVNET_RESTORE();
379#ifdef MAC
380                }
381#endif
382        }
383        if( error == 0 )
384        {
385                return error;
386        }
387        errno = error;
388        return -1;
389}
390
391int
392kern_accept(struct thread *td, int s, struct sockaddr **name, socklen_t *namelen)
393{
394        struct sockaddr *sa = NULL;
395        int error;
396        struct socket *head, *so;
397        int fd;
398        u_int fflag;
399        pid_t pgid;
400        int tmp;
401
402        if (name) {
403                *name = NULL;
404                if (*namelen < 0)
405                        return (EINVAL);
406        }
407
408        if ((head = rtems_bsdnet_fdToSocket (s)) == NULL) {
409                error = EBADF;
410                return (error);
411        }
412        if ((head->so_options & SO_ACCEPTCONN) == 0) {
413                error = EINVAL;
414                goto done;
415        }
416#ifdef MAC
417        error = mac_socket_check_accept(td->td_ucred, head);
418        if (error != 0)
419                goto done;
420#endif
421        ACCEPT_LOCK();
422        if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
423                ACCEPT_UNLOCK();
424                error = EWOULDBLOCK;
425                goto noconnection;
426        }
427        while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
428                if (head->so_rcv.sb_state & SBS_CANTRCVMORE) {
429                        head->so_error = ECONNABORTED;
430                        break;
431                }
432                error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH,
433                    "accept", 0);
434                if (error) {
435                        ACCEPT_UNLOCK();
436                        goto noconnection;
437                }
438        }
439        if (head->so_error) {
440                error = head->so_error;
441                head->so_error = 0;
442                ACCEPT_UNLOCK();
443                goto noconnection;
444        }
445        so = TAILQ_FIRST(&head->so_comp);
446        KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP"));
447        KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP"));
448
449        /*
450         * Before changing the flags on the socket, we have to bump the
451         * reference count.  Otherwise, if the protocol calls sofree(),
452         * the socket will be released due to a zero refcount.
453         */
454        SOCK_LOCK(so);                  /* soref() and so_state update */
455        soref(so);                      /* file descriptor reference */
456
457        TAILQ_REMOVE(&head->so_comp, so, so_list);
458        head->so_qlen--;
459
460        fd = rtems_bsdnet_makeFdForSocket (so, &socket_handlers);
461        if (fd < 0) {
462                TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
463                head->so_qlen++;
464    wakeup(head);
465                error = EBADF;
466                return (error);
467        }
468
469        so->so_state |= (head->so_state & SS_NBIO);
470        so->so_qstate &= ~SQ_COMP;
471        so->so_head = NULL;
472
473        SOCK_UNLOCK(so);
474        ACCEPT_UNLOCK();
475
476        td->td_retval[0] = fd;
477
478        sa = 0;
479        CURVNET_SET(so->so_vnet);
480        error = soaccept(so, &sa);
481        CURVNET_RESTORE();
482        if (error) {
483                /*
484                 * return a namelen of zero for older code which might
485                 * ignore the return value from accept.
486                 */
487                if (name)
488                        *namelen = 0;
489                goto noconnection;
490        }
491        if (sa == NULL) {
492                if (name)
493                        *namelen = 0;
494                goto done;
495        }
496        if (name) {
497                /* check sa_len before it is destroyed */
498                if (*namelen > sa->sa_len)
499                        *namelen = sa->sa_len;
500#ifdef KTRACE
501                if (KTRPOINT(td, KTR_STRUCT))
502                        ktrsockaddr(sa);
503#endif
504                *name = sa;
505                sa = NULL;
506        }
507noconnection:
508        if (sa)
509                free(sa, M_SONAME);
510
511done:
512        return (error);
513}
514
515static int
516accept1(td, s, _name, _namelen, compat)
517        struct thread *td;
518        int s;
519        struct sockaddr *_name;
520        int *_namelen;
521        int compat;
522{
523        struct sockaddr *name;
524        socklen_t namelen;
525        int error;
526
527        if (_name == NULL)
528                return (kern_accept(td, s, NULL, NULL));
529
530        error = copyin(_namelen, &namelen, sizeof (namelen));
531        if (error)
532                return (error);
533
534        error = kern_accept(td, s, &name, &namelen);
535
536        /*
537         * return a namelen of zero for older code which might
538         * ignore the return value from accept.
539         */
540        if (error) {
541                (void) copyout(&namelen,
542                    _namelen, sizeof(*_namelen));
543                return (error);
544        }
545
546        if (error == 0 && name != NULL) {
547#ifdef COMPAT_OLDSOCK
548                if (compat)
549                        ((struct osockaddr *)name)->sa_family =
550                            name->sa_family;
551#endif
552                error = copyout(name, _name, namelen);
553        }
554        if (error == 0)
555                error = copyout(&namelen, _namelen,
556                    sizeof(namelen));
557        free(name, M_SONAME);
558        return (error);
559}
560
561int
562accept (int s, struct sockaddr *name, int *namelen)
563{
564        struct thread *td;
565        int error;
566
567        td = curthread;
568        error = accept1(td, s, name, namelen, 0);
569        if( error == 0 )
570        {
571                return td->td_retval[0];
572        }
573        errno = error;
574        return -1;
575}
576
577/*
578 *  Shutdown routine
579 */
580
581int
582shutdown (int s, int how)
583{
584  struct socket *so;
585        int error = 0;
586
587        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
588                error = EBADF;
589        }
590        if( error == 0 )
591        {
592                error = soshutdown(so, how);
593        }
594        if( error == 0 )
595        {
596                return error;
597        }
598        errno = error;
599        return -1;
600}
601
602int
603kern_sendit(td, s, mp, flags, control, segflg)
604        struct thread *td;
605        int s;
606        struct msghdr *mp;
607        int flags;
608        struct mbuf *control;
609        enum uio_seg segflg;
610{
611        struct uio auio;
612        struct iovec *iov;
613        struct socket *so;
614        int i;
615        int len, error;
616#ifdef KTRACE
617        struct uio *ktruio = NULL;
618#endif
619
620        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
621                error = EBADF;
622                return (error);
623        }
624
625#ifdef MAC
626        if (mp->msg_name != NULL) {
627                error = mac_socket_check_connect(td->td_ucred, so,
628                    mp->msg_name);
629                if (error)
630                        goto bad;
631        }
632        error = mac_socket_check_send(td->td_ucred, so);
633        if (error)
634                goto bad;
635#endif
636
637        auio.uio_iov = mp->msg_iov;
638        auio.uio_iovcnt = mp->msg_iovlen;
639        auio.uio_segflg = segflg;
640        auio.uio_rw = UIO_WRITE;
641        auio.uio_td = td;
642        auio.uio_offset = 0;                    /* XXX */
643        auio.uio_resid = 0;
644        iov = mp->msg_iov;
645        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
646                if ((auio.uio_resid += iov->iov_len) < 0) {
647                        error = EINVAL;
648                        goto bad;
649                }
650        }
651#ifdef KTRACE
652        if (KTRPOINT(td, KTR_GENIO))
653                ktruio = cloneuio(&auio);
654#endif
655        len = auio.uio_resid;
656        error = sosend(so, mp->msg_name, &auio, 0, control, flags, td);
657        if (error) {
658                if (auio.uio_resid != len && (error == ERESTART ||
659                    error == EINTR || error == EWOULDBLOCK))
660                        error = 0;
661                /* Generation of SIGPIPE can be controlled per socket */
662                if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&
663                    !(flags & MSG_NOSIGNAL)) {
664                        PROC_LOCK(td->td_proc);
665      killinfo(td->td_proc->p_pid, SIGPIPE, NULL);
666                        PROC_UNLOCK(td->td_proc);
667                }
668        }
669        if (error == 0)
670                td->td_retval[0] = len - auio.uio_resid;
671#ifdef KTRACE
672        if (ktruio != NULL) {
673                ktruio->uio_resid = td->td_retval[0];
674                ktrgenio(s, UIO_WRITE, ktruio, error);
675        }
676#endif
677bad:
678        return (error);
679}
680
681static int
682sendit(td, s, mp, flags)
683        struct thread *td;
684        int s;
685        struct msghdr *mp;
686        int flags;
687{
688        struct mbuf *control;
689        struct sockaddr *to;
690        int error;
691
692        if (mp->msg_name != NULL) {
693                error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
694                if (error) {
695                        to = NULL;
696                        goto bad;
697                }
698                mp->msg_name = to;
699        } else {
700                to = NULL;
701        }
702
703        if (mp->msg_control) {
704                if (mp->msg_controllen < sizeof(struct cmsghdr)
705#ifdef COMPAT_OLDSOCK
706                    && mp->msg_flags != MSG_COMPAT
707#endif
708                ) {
709                        error = EINVAL;
710                        goto bad;
711                }
712                error = sockargs(&control, mp->msg_control,
713                    mp->msg_controllen, MT_CONTROL);
714                if (error)
715                        goto bad;
716#ifdef COMPAT_OLDSOCK
717                if (mp->msg_flags == MSG_COMPAT) {
718                        struct cmsghdr *cm;
719
720                        M_PREPEND(control, sizeof(*cm), M_WAIT);
721                        cm = mtod(control, struct cmsghdr *);
722                        cm->cmsg_len = control->m_len;
723                        cm->cmsg_level = SOL_SOCKET;
724                        cm->cmsg_type = SCM_RIGHTS;
725                }
726#endif
727        } else {
728                control = NULL;
729        }
730
731        error = kern_sendit(td, s, mp, flags, control, UIO_USERSPACE);
732
733bad:
734        if (to)
735                free(to, M_SONAME);
736        return (error);
737}
738
739/*
740 * All `transmit' operations end up calling this routine.
741 */
742ssize_t
743sendmsg (int s, const struct msghdr *mp, int flags)
744{
745        struct thread *td;
746        struct msghdr msg;
747        struct iovec *iov;
748        int error;
749
750        td = curthread;
751        error = copyin(mp, &msg, sizeof (msg));
752        if (error)
753                return (error);
754        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
755        if (error)
756                return (error);
757        msg.msg_iov = iov;
758#ifdef COMPAT_OLDSOCK
759        msg.msg_flags = 0;
760#endif
761        error = sendit(td, s, &msg, flags);
762        free(iov, M_IOV);
763        if( error == 0 )
764        {
765                return td->td_retval[0];
766        }
767        errno = error;
768        return -1;
769}
770
771/*
772 * Send a message to a host
773 */
774ssize_t
775sendto (int s, const void *buf, size_t len, int flags, const struct sockaddr *to, int tolen)
776{
777        struct thread *td;
778        struct msghdr msg;
779        struct iovec aiov;
780        int error;
781
782        td = curthread;
783        msg.msg_name = to;
784        msg.msg_namelen = tolen;
785        msg.msg_iov = &aiov;
786        msg.msg_iovlen = 1;
787        msg.msg_control = 0;
788#ifdef COMPAT_OLDSOCK
789        msg.msg_flags = 0;
790#endif
791        aiov.iov_base = buf;
792        aiov.iov_len = len;
793        error = sendit(td, s, &msg, flags);
794        if( error == 0 )
795        {
796                return td->td_retval[0];
797        }
798        errno = error;
799        return -1;
800}
801
802ssize_t
803send( int s, const void *msg, size_t len, int flags )
804{
805  return (sendto(s, msg, len, flags, NULL, 0));
806}
807
808int
809kern_recvit(td, s, mp, fromseg, controlp)
810        struct thread *td;
811        int s;
812        struct msghdr *mp;
813        enum uio_seg fromseg;
814        struct mbuf **controlp;
815{
816        struct uio auio;
817        struct iovec *iov;
818        int i;
819        socklen_t len;
820        int error;
821        struct mbuf *m, *control = 0;
822        caddr_t ctlbuf;
823        struct socket *so;
824        struct sockaddr *fromsa = 0;
825#ifdef KTRACE
826        struct uio *ktruio = NULL;
827#endif
828
829        if(controlp != NULL)
830                *controlp = 0;
831
832        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
833                error = EBADF;
834                return (error);
835        }
836
837#ifdef MAC
838        error = mac_socket_check_receive(td->td_ucred, so);
839        if (error) {
840                return (error);
841        }
842#endif
843
844        auio.uio_iov = mp->msg_iov;
845        auio.uio_iovcnt = mp->msg_iovlen;
846        auio.uio_segflg = UIO_USERSPACE;
847        auio.uio_rw = UIO_READ;
848        auio.uio_td = td;
849        auio.uio_offset = 0;                    /* XXX */
850        auio.uio_resid = 0;
851        iov = mp->msg_iov;
852        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
853                if ((auio.uio_resid += iov->iov_len) < 0) {
854                        return (EINVAL);
855                }
856        }
857#ifdef KTRACE
858        if (KTRPOINT(td, KTR_GENIO))
859                ktruio = cloneuio(&auio);
860#endif
861        len = auio.uio_resid;
862        CURVNET_SET(so->so_vnet);
863        error = soreceive(so, &fromsa, &auio, (struct mbuf **)0,
864            (mp->msg_control || controlp) ? &control : (struct mbuf **)0,
865            &mp->msg_flags);
866        CURVNET_RESTORE();
867        if (error) {
868                if (auio.uio_resid != (int)len && (error == ERESTART ||
869                    error == EINTR || error == EWOULDBLOCK))
870                        error = 0;
871        }
872#ifdef KTRACE
873        if (ktruio != NULL) {
874                ktruio->uio_resid = (int)len - auio.uio_resid;
875                ktrgenio(s, UIO_READ, ktruio, error);
876        }
877#endif
878        if (error)
879                goto out;
880        td->td_retval[0] = (int)len - auio.uio_resid;
881        if (mp->msg_name) {
882                len = mp->msg_namelen;
883                if (len <= 0 || fromsa == 0)
884                        len = 0;
885                else {
886                        /* save sa_len before it is destroyed by MSG_COMPAT */
887                        len = MIN(len, fromsa->sa_len);
888#ifdef COMPAT_OLDSOCK
889                        if (mp->msg_flags & MSG_COMPAT)
890                                ((struct osockaddr *)fromsa)->sa_family =
891                                    fromsa->sa_family;
892#endif
893                        if (fromseg == UIO_USERSPACE) {
894                                error = copyout(fromsa, mp->msg_name,
895                                    (unsigned)len);
896                                if (error)
897                                        goto out;
898                        } else
899                                bcopy(fromsa, mp->msg_name, len);
900                }
901                mp->msg_namelen = len;
902        }
903        if (mp->msg_control && controlp == NULL) {
904#ifdef COMPAT_OLDSOCK
905                /*
906                 * We assume that old recvmsg calls won't receive access
907                 * rights and other control info, esp. as control info
908                 * is always optional and those options didn't exist in 4.3.
909                 * If we receive rights, trim the cmsghdr; anything else
910                 * is tossed.
911                 */
912                if (control && mp->msg_flags & MSG_COMPAT) {
913                        if (mtod(control, struct cmsghdr *)->cmsg_level !=
914                            SOL_SOCKET ||
915                            mtod(control, struct cmsghdr *)->cmsg_type !=
916                            SCM_RIGHTS) {
917                                mp->msg_controllen = 0;
918                                goto out;
919                        }
920                        control->m_len -= sizeof (struct cmsghdr);
921                        control->m_data += sizeof (struct cmsghdr);
922                }
923#endif
924                len = mp->msg_controllen;
925                m = control;
926                mp->msg_controllen = 0;
927                ctlbuf = mp->msg_control;
928
929                while (m && len > 0) {
930                        unsigned int tocopy;
931
932                        if (len >= m->m_len)
933                                tocopy = m->m_len;
934                        else {
935                                mp->msg_flags |= MSG_CTRUNC;
936                                tocopy = len;
937                        }
938
939                        if ((error = copyout(mtod(m, caddr_t),
940                                        ctlbuf, tocopy)) != 0)
941                                goto out;
942
943                        ctlbuf += tocopy;
944                        len -= tocopy;
945                        m = m->m_next;
946                }
947                mp->msg_controllen = ctlbuf - (caddr_t)mp->msg_control;
948        }
949out:
950#ifdef KTRACE
951        if (fromsa && KTRPOINT(td, KTR_STRUCT))
952                ktrsockaddr(fromsa);
953#endif
954        if (fromsa)
955                free(fromsa, M_SONAME);
956
957        if (error == 0 && controlp != NULL)
958                *controlp = control;
959        else  if (control)
960                m_freem(control);
961
962        return (error);
963}
964
965static int
966recvit(td, s, mp, namelenp)
967        struct thread *td;
968        int s;
969        struct msghdr *mp;
970        void *namelenp;
971{
972        int error;
973
974        error = kern_recvit(td, s, mp, UIO_USERSPACE, NULL);
975        if (error)
976                return (error);
977        if (namelenp) {
978                error = copyout(&mp->msg_namelen, namelenp, sizeof (socklen_t));
979#ifdef COMPAT_OLDSOCK
980                if (mp->msg_flags & MSG_COMPAT)
981                        error = 0;      /* old recvfrom didn't check */
982#endif
983        }
984        return (error);
985}
986
987/*
988 * All `receive' operations end up calling this routine.
989 */
990ssize_t
991recvmsg (int s, struct msghdr *mp, int flags)
992{
993        struct thread *td;
994        struct msghdr msg;
995        struct iovec *uiov, *iov;
996        int error;
997
998        td = curthread;
999        error = copyin(mp, &msg, sizeof (msg));
1000        if (error == 0 )
1001        {
1002                error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1003                if (error == 0)
1004                {
1005                        msg.msg_flags = flags;
1006        #ifdef COMPAT_OLDSOCK
1007                        msg.msg_flags &= ~MSG_COMPAT;
1008        #endif
1009                        uiov = msg.msg_iov;
1010                        msg.msg_iov = iov;
1011                        error = recvit(td, s, &msg, NULL);
1012                        if (error == 0) {
1013                                msg.msg_iov = uiov;
1014                                error = copyout(&msg, mp, sizeof(msg));
1015                        }
1016                        free(iov, M_IOV);
1017                }
1018        }
1019        if( error == 0 )
1020        {
1021                return td->td_retval[0];
1022        }
1023        errno = error;
1024        return -1;
1025}
1026
1027/*
1028 * Receive a message from a host
1029 */
1030ssize_t
1031recvfrom (int s, void *buf, size_t len, int flags, const struct sockaddr *from, socklen_t *fromlenaddr)
1032{
1033        struct thread *td;
1034        struct msghdr msg;
1035        struct iovec aiov;
1036        int error;
1037
1038        td = curthread;
1039        if (fromlenaddr) {
1040                error = copyin(fromlenaddr,
1041                    &msg.msg_namelen, sizeof (msg.msg_namelen));
1042                if (error)
1043                        goto done2;
1044        } else {
1045                msg.msg_namelen = 0;
1046        }
1047        msg.msg_name = from;
1048        msg.msg_iov = &aiov;
1049        msg.msg_iovlen = 1;
1050        aiov.iov_base = buf;
1051        aiov.iov_len = len;
1052        msg.msg_control = 0;
1053        msg.msg_flags = flags;
1054        error = recvit(td, s, &msg, fromlenaddr);
1055done2:
1056        if( error == 0 )
1057        {
1058                return td->td_retval[0];
1059        }
1060        errno = error;
1061        return -1;
1062}
1063
1064ssize_t
1065recv( int s, void *buf, size_t len, int flags )
1066{
1067  return (recvfrom(s, buf, len, flags, NULL, 0));
1068}
1069
1070int
1071kern_setsockopt(td, s, level, name, val, valseg, valsize)
1072        struct thread *td;
1073        int s;
1074        int level;
1075        int name;
1076        void *val;
1077        enum uio_seg valseg;
1078        socklen_t valsize;
1079{
1080        int error;
1081        struct socket *so;
1082        struct sockopt sopt;
1083
1084        if (val == NULL && valsize != 0)
1085                return (EFAULT);
1086        if ((int)valsize < 0)
1087                return (EINVAL);
1088
1089        sopt.sopt_dir = SOPT_SET;
1090        sopt.sopt_level = level;
1091        sopt.sopt_name = name;
1092        sopt.sopt_val = val;
1093        sopt.sopt_valsize = valsize;
1094        switch (valseg) {
1095        case UIO_USERSPACE:
1096                sopt.sopt_td = td;
1097                break;
1098        case UIO_SYSSPACE:
1099                sopt.sopt_td = NULL;
1100                break;
1101        default:
1102                panic("kern_setsockopt called with bad valseg");
1103        }
1104
1105        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
1106                error = EBADF;
1107                return error;
1108        }
1109        CURVNET_SET(so->so_vnet);
1110        error = sosetopt(so, &sopt);
1111        CURVNET_RESTORE();
1112        return(error);
1113}
1114
1115int
1116setsockopt (int s, int level, int name, const void *val, socklen_t valsize)
1117{
1118        struct thread *td;
1119        int error;
1120
1121        td = curthread;
1122        error = kern_setsockopt(td, s, level, name, val, UIO_USERSPACE, valsize);
1123        if( error == 0 )
1124        {
1125                return error;
1126        }
1127        errno = error;
1128        return -1;
1129}
1130
1131int
1132kern_getsockopt(td, s, level, name, val, valseg, valsize)
1133        struct thread *td;
1134        int s;
1135        int level;
1136        int name;
1137        void *val;
1138        enum uio_seg valseg;
1139        socklen_t *valsize;
1140{
1141        int error;
1142        struct  socket *so;
1143        struct  sockopt sopt;
1144
1145        if (val == NULL)
1146                *valsize = 0;
1147        if ((int)*valsize < 0)
1148                return (EINVAL);
1149
1150        sopt.sopt_dir = SOPT_GET;
1151        sopt.sopt_level = level;
1152        sopt.sopt_name = name;
1153        sopt.sopt_val = val;
1154        sopt.sopt_valsize = (size_t)*valsize; /* checked non-negative above */
1155        switch (valseg) {
1156        case UIO_USERSPACE:
1157                sopt.sopt_td = td;
1158                break;
1159        case UIO_SYSSPACE:
1160                sopt.sopt_td = NULL;
1161                break;
1162        default:
1163                panic("kern_getsockopt called with bad valseg");
1164        }
1165
1166        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
1167                error = EBADF;
1168                return error;
1169        }
1170        CURVNET_SET(so->so_vnet);
1171        error = sogetopt(so, &sopt);
1172        CURVNET_RESTORE();
1173        *valsize = sopt.sopt_valsize;
1174        return (error);
1175}
1176
1177int
1178getsockopt (int s, int level, int name, void *val, socklen_t *avalsize)
1179{
1180        struct thread *td;
1181        socklen_t valsize;
1182        int     error = 0;
1183
1184        td = curthread;
1185        if (val) {
1186                error = copyin(avalsize, &valsize, sizeof (valsize));
1187        }
1188
1189        if( error == 0 )
1190        {
1191                error = kern_getsockopt(td, s, level, name, val, UIO_USERSPACE, &valsize);
1192
1193                if (error == 0)
1194                        error = copyout(&valsize, avalsize, sizeof (valsize));
1195        }
1196        if( error == 0 )
1197        {
1198                return error;
1199        }
1200        errno = error;
1201        return -1;
1202}
1203
1204int
1205kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
1206    socklen_t *alen)
1207{
1208        struct socket *so;
1209        socklen_t len;
1210        int error;
1211
1212        if (*alen < 0)
1213                return (EINVAL);
1214
1215        if ((so = rtems_bsdnet_fdToSocket (fd)) == NULL) {
1216                error = EBADF;
1217                return error;
1218        }
1219        if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
1220                error = ENOTCONN;
1221                goto done;
1222        }
1223        *sa = NULL;
1224        CURVNET_SET(so->so_vnet);
1225        error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, sa);
1226        CURVNET_RESTORE();
1227        if (error)
1228                goto bad;
1229        if (*sa == NULL)
1230                len = 0;
1231        else
1232                len = MIN(*alen, (*sa)->sa_len);
1233        *alen = len;
1234#ifdef KTRACE
1235        if (KTRPOINT(td, KTR_STRUCT))
1236                ktrsockaddr(*sa);
1237#endif
1238bad:
1239        if (error && *sa) {
1240                free(*sa, M_SONAME);
1241                *sa = NULL;
1242        }
1243done:
1244        return (error);
1245}
1246
1247static int
1248getpeername1(td, fdes, asa, alen, compat)
1249        struct thread *td;
1250        int     fdes;
1251        struct sockaddr * asa;
1252        socklen_t * alen;
1253        int compat;
1254{
1255        struct sockaddr *sa;
1256        socklen_t len;
1257        int error;
1258
1259        error = copyin(alen, &len, sizeof (len));
1260        if (error)
1261                return (error);
1262
1263        error = kern_getpeername(td, fdes, &sa, &len);
1264        if (error)
1265                return (error);
1266
1267        if (len != 0) {
1268#ifdef COMPAT_OLDSOCK
1269                if (compat)
1270                        ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1271#endif
1272                error = copyout(sa, asa, (u_int)len);
1273        }
1274        free(sa, M_SONAME);
1275        if (error == 0)
1276                error = copyout(&len, alen, sizeof(len));
1277        return (error);
1278}
1279
1280int
1281getpeername (int s, struct sockaddr *name, socklen_t *namelen)
1282{
1283        struct thread *td;
1284        int error;
1285
1286        td = curthread;
1287        error = getpeername1(td, s, name, namelen, 0);
1288        if( error == 0 )
1289        {
1290                return error;
1291        }
1292        errno = error;
1293        return -1;
1294}
1295
1296int
1297kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
1298    socklen_t *alen)
1299{
1300        struct socket *so;
1301        socklen_t len;
1302        int error;
1303
1304        if (*alen < 0)
1305                return (EINVAL);
1306
1307        if ((so = rtems_bsdnet_fdToSocket (fd)) == NULL) {
1308                error = EBADF;
1309                return error;
1310        }
1311        *sa = NULL;
1312        CURVNET_SET(so->so_vnet);
1313        error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, sa);
1314        CURVNET_RESTORE();
1315        if (error)
1316                goto bad;
1317        if (*sa == NULL)
1318                len = 0;
1319        else
1320                len = MIN(*alen, (*sa)->sa_len);
1321        *alen = len;
1322#ifdef KTRACE
1323        if (KTRPOINT(td, KTR_STRUCT))
1324                ktrsockaddr(*sa);
1325#endif
1326bad:
1327        if (error && *sa) {
1328                free(*sa, M_SONAME);
1329                *sa = NULL;
1330        }
1331        return (error);
1332}
1333
1334static int
1335getsockname1(td, fdes, asa, alen, compat)
1336        struct thread *td;
1337        int     fdes;
1338        struct sockaddr *  asa;
1339        socklen_t * alen;
1340        int compat;
1341{
1342        struct sockaddr *sa;
1343        socklen_t len;
1344        int error;
1345
1346        error = copyin(alen, &len, sizeof(len));
1347        if (error)
1348                return (error);
1349
1350        error = kern_getsockname(td, fdes, &sa, &len);
1351        if (error)
1352                return (error);
1353
1354        if (len != 0) {
1355#ifdef COMPAT_OLDSOCK
1356                if (compat)
1357                        ((struct osockaddr *)sa)->sa_family = sa->sa_family;
1358#endif
1359                error = copyout(sa, asa, (u_int)len);
1360        }
1361        free(sa, M_SONAME);
1362        if (error == 0)
1363                error = copyout(&len, alen, sizeof(len));
1364        return (error);
1365}
1366
1367int
1368getsockname (int s, struct sockaddr *name, socklen_t *namelen)
1369{
1370        struct thread *td;
1371        int error;
1372
1373        td = curthread;
1374        error = getsockname1(td, s, name, namelen, 0);
1375        if( error == 0 )
1376        {
1377                return error;
1378        }
1379        errno = error;
1380        return -1;
1381}
1382
1383/*
1384 ************************************************************************
1385 *                      RTEMS I/O HANDLER ROUTINES                      *
1386 ************************************************************************
1387 */
1388static int
1389rtems_bsdnet_close (rtems_libio_t *iop)
1390{
1391        struct socket *so;
1392        int error;
1393
1394        if ((so = iop->data1) == NULL) {
1395                errno = EBADF;
1396                return -1;
1397        }
1398        error = soclose (so);
1399        if (error) {
1400                errno = error;
1401                return -1;
1402        }
1403        return 0;
1404}
1405
1406static ssize_t
1407rtems_bsdnet_read (rtems_libio_t *iop, void *buffer, size_t count)
1408{
1409        return recv (iop->data0, buffer, count, 0);
1410}
1411
1412static ssize_t
1413rtems_bsdnet_write (rtems_libio_t *iop, const void *buffer, size_t count)
1414{
1415        return send (iop->data0, buffer, count, 0);
1416}
1417
1418static int
1419so_ioctl (rtems_libio_t *iop, struct socket *so, uint32_t   command, void *buffer)
1420{
1421        switch (command) {
1422        case FIONBIO:
1423                SOCK_LOCK(so);
1424                if (*(int *)buffer) {
1425                        iop->flags |= O_NONBLOCK;
1426                        so->so_state |= SS_NBIO;
1427                }
1428                else {
1429                        iop->flags &= ~O_NONBLOCK;
1430                        so->so_state &= ~SS_NBIO;
1431                }
1432                SOCK_UNLOCK(so);
1433                return 0;
1434
1435        case FIONREAD:
1436                *(int *)buffer = so->so_rcv.sb_cc;
1437                return 0;
1438        }
1439
1440        if (IOCGROUP(command) == 'i')
1441                return ifioctl (so, command, buffer, NULL);
1442        if (IOCGROUP(command) == 'r')
1443                return rtioctl (command, buffer, NULL);
1444        return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0, curthread);
1445}
1446
1447static int
1448rtems_bsdnet_ioctl (rtems_libio_t *iop, uint32_t   command, void *buffer)
1449{
1450        struct socket *so;
1451        int error;
1452
1453        if ((so = iop->data1) == NULL) {
1454                errno = EBADF;
1455                return -1;
1456        }
1457        error = so_ioctl (iop, so, command, buffer);
1458        if (error) {
1459                errno = error;
1460                return -1;
1461        }
1462        return 0;
1463}
1464
1465static int
1466rtems_bsdnet_fcntl (int cmd, rtems_libio_t *iop)
1467{
1468        struct socket *so;
1469
1470        if (cmd == F_SETFL) {
1471                if ((so = iop->data1) == NULL) {
1472                        return EBADF;
1473                }
1474                SOCK_LOCK(so);
1475                if (iop->flags & LIBIO_FLAGS_NO_DELAY)
1476                        so->so_state |= SS_NBIO;
1477                else
1478                        so->so_state &= ~SS_NBIO;
1479                SOCK_UNLOCK(so);
1480        }
1481  return 0;
1482}
1483
1484static int
1485rtems_bsdnet_fstat (rtems_filesystem_location_info_t *loc, struct stat *sp)
1486{
1487        sp->st_mode = S_IFSOCK;
1488        return 0;
1489}
1490
1491static const rtems_filesystem_file_handlers_r socket_handlers = {
1492        rtems_filesystem_default_open,          /* open */
1493        rtems_bsdnet_close,                     /* close */
1494        rtems_bsdnet_read,                      /* read */
1495        rtems_bsdnet_write,                     /* write */
1496        rtems_bsdnet_ioctl,                     /* ioctl */
1497        rtems_filesystem_default_lseek,         /* lseek */
1498        rtems_bsdnet_fstat,                     /* fstat */
1499        rtems_filesystem_default_fchmod,        /* fchmod */
1500        rtems_filesystem_default_ftruncate,     /* ftruncate */
1501        rtems_filesystem_default_fsync_or_fdatasync,            /* fsync */
1502        rtems_filesystem_default_fsync_or_fdatasync,    /* fdatasync */
1503        rtems_bsdnet_fcntl,                     /* fcntl */
1504        rtems_filesystem_default_rmnod          /* rmnod */
1505};
Note: See TracBrowser for help on using the repository browser.