source: rtems-libbsd/rtemsbsd/src/rtems-bsd-syscalls.c @ 96dca8a

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 96dca8a was 96dca8a, checked in by Julien Delange <julien.delange@…>, on 03/23/12 at 20:07:00

Use new fsync_or_fdatasync default

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