source: rtems-libbsd/rtemsbsd/rtems/rtems-bsd-syscalls.c @ 609df33

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 609df33 was 609df33, checked in by Sebastian Huber <sebastian.huber@…>, on 10/11/13 at 11:20:26

Use send() and recv() from FreeBSD

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