source: rtems/cpukit/libnetworking/rtems/rtems_syscall.c @ 4aa8a23

4.104.114.84.9
Last change on this file since 4aa8a23 was 4aa8a23, checked in by Ralf Corsepius <ralf.corsepius@…>, on Feb 2, 2005 at 3:06:41 AM

Include config.h.

  • Property mode set to 100644
File size: 16.1 KB
Line 
1/*
2 *  $Id$
3 */
4
5#if HAVE_CONFIG_H
6#include "config.h"
7#endif
8
9#include <string.h>
10#include <stdarg.h>
11/* #include <stdlib.h> */
12#include <stdio.h>
13#include <errno.h>
14
15#include <rtems.h>
16#include <rtems/libio.h>
17#include <rtems/error.h>
18#include <rtems/rtems_bsdnet.h>
19
20#include <sys/errno.h>
21#include <sys/types.h>
22#include <sys/param.h>
23#include <sys/mbuf.h>
24#include <sys/socket.h>
25#include <sys/socketvar.h>
26#include <sys/protosw.h>
27#include <sys/proc.h>
28#include <sys/fcntl.h>
29#include <sys/filio.h>
30#include <sys/sysctl.h>
31
32#include <net/if.h>
33#include <net/route.h>
34
35/*
36 * Hooks to RTEMS I/O system
37 */
38static const rtems_filesystem_file_handlers_r socket_handlers;
39int rtems_bsdnet_makeFdForSocket(void *so, const rtems_filesystem_file_handlers_r *h);
40struct socket *rtems_bsdnet_fdToSocket(int fd);
41
42/*
43 * Package system call argument into mbuf.
44 */
45static int
46sockargstombuf (struct mbuf **mp, const void *buf, int buflen, int type)
47{
48        struct mbuf *m;
49
50        if ((u_int)buflen > MLEN)
51                return (EINVAL);
52        m = m_get(M_WAIT, type);
53        if (m == NULL)
54                return (ENOBUFS);
55        m->m_len = buflen;
56        memcpy (mtod(m, caddr_t), buf, buflen);
57        *mp = m;
58        if (type == MT_SONAME) {
59                struct sockaddr *sa;
60                sa = mtod(m, struct sockaddr *);
61                sa->sa_len = buflen;
62        }
63        return 0;
64}
65
66/*
67 *********************************************************************
68 *                       BSD-style entry points                      *
69 *********************************************************************
70 */
71int
72socket (int domain, int type, int protocol)
73{
74        int fd;
75        int error;
76        struct socket *so;
77
78        rtems_bsdnet_semaphore_obtain ();
79        error = socreate(domain, &so, type, protocol, NULL);
80        if (error == 0) {
81                fd = rtems_bsdnet_makeFdForSocket (so, &socket_handlers);
82                if (fd < 0)
83                        soclose (so);
84        }
85        else {
86                errno = error;
87                fd = -1;
88        }
89        rtems_bsdnet_semaphore_release ();
90        return fd;
91}
92
93int
94bind (int s, struct sockaddr *name, int namelen)
95{
96        int error;
97        int ret = -1;
98        struct socket *so;
99        struct mbuf *nam;
100
101        rtems_bsdnet_semaphore_obtain ();
102        if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) {
103                error = sockargstombuf (&nam, name, namelen, MT_SONAME);
104                if (error == 0) {
105                        error = sobind (so, nam);
106                        if (error == 0)
107                                ret = 0;
108                        else
109                                errno = error;
110                        m_freem (nam);
111                }
112                else {
113                        errno = error;
114                }
115        }
116        rtems_bsdnet_semaphore_release ();
117        return ret;
118}
119
120int
121connect (int s, struct sockaddr *name, int namelen)
122{
123        int error;
124        int ret = -1;
125        struct socket *so;
126        struct mbuf *nam;
127
128        rtems_bsdnet_semaphore_obtain ();
129        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
130                rtems_bsdnet_semaphore_release ();
131                return -1;
132        }
133        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
134                errno = EALREADY;
135                rtems_bsdnet_semaphore_release ();
136                return -1;
137        }
138        error = sockargstombuf (&nam, name, namelen, MT_SONAME);
139        if (error) {
140                errno = error;
141                rtems_bsdnet_semaphore_release ();
142                return -1;
143        }
144        error = soconnect (so, nam);
145        if (error)
146                goto bad;
147        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
148                m_freem(nam);
149                errno = EINPROGRESS;
150                rtems_bsdnet_semaphore_release ();
151                return -1;
152        }
153        while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
154                error = soconnsleep (so);
155                if (error)
156                        break;
157        }
158        if (error == 0) {
159                error = so->so_error;
160                so->so_error = 0;
161        }
162    bad:
163        so->so_state &= ~SS_ISCONNECTING;
164        m_freem (nam);
165        if (error)
166                errno = error;
167        else
168                ret = 0;
169        rtems_bsdnet_semaphore_release ();
170        return ret;
171}
172
173int
174listen (int s, int backlog)
175{
176        int error;
177        int ret = -1;
178        struct socket *so;
179
180        rtems_bsdnet_semaphore_obtain ();
181        if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) {
182                error = solisten (so, backlog);
183                if (error == 0)
184                        ret = 0;
185                else
186                        errno = error;
187        }
188        rtems_bsdnet_semaphore_release ();
189        return ret;
190}
191
192int
193accept (int s, struct sockaddr *name, int *namelen)
194{
195        int fd;
196        struct socket *head, *so;
197        struct mbuf *nam;
198
199        rtems_bsdnet_semaphore_obtain ();
200        if ((head = rtems_bsdnet_fdToSocket (s)) == NULL) {
201                rtems_bsdnet_semaphore_release ();
202                return -1;
203        }
204        if ((head->so_options & SO_ACCEPTCONN) == 0) {
205                errno = EINVAL;
206                rtems_bsdnet_semaphore_release ();
207                return -1;
208        }
209        if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) {
210                errno = EWOULDBLOCK;
211                rtems_bsdnet_semaphore_release ();
212                return -1;
213        }
214        while (head->so_comp.tqh_first == NULL && head->so_error == 0) {
215                if (head->so_state & SS_CANTRCVMORE) {
216                        head->so_error = ECONNABORTED;
217                        break;
218                }
219                head->so_error = soconnsleep (head);
220        }
221        if (head->so_error) {
222                errno = head->so_error;
223                head->so_error = 0;
224                rtems_bsdnet_semaphore_release ();
225                return -1;
226        }
227
228        so = head->so_comp.tqh_first;
229        TAILQ_REMOVE(&head->so_comp, so, so_list);
230        head->so_qlen--;
231
232        fd = rtems_bsdnet_makeFdForSocket (so, &socket_handlers);
233        if (fd < 0) {
234                TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
235                head->so_qlen++;
236                soconnwakeup (head);
237                rtems_bsdnet_semaphore_release ();
238                return -1;
239        }
240        so->so_state &= ~SS_COMP;
241        so->so_head = NULL;
242
243        nam = m_get(M_WAIT, MT_SONAME);
244        (void) soaccept(so, nam);
245        if (name) {
246                 /* check length before it is destroyed */
247                if (*namelen > nam->m_len)
248                        *namelen = nam->m_len;
249                memcpy (name, mtod(nam, caddr_t), *namelen);
250        }
251        m_freem(nam);
252        rtems_bsdnet_semaphore_release ();
253        return (fd);
254
255}
256
257/*
258 *  Shutdown routine
259 */
260
261int
262shutdown (int s, int how)
263{
264      struct socket *so;
265      int error;
266
267      rtems_bsdnet_semaphore_obtain ();
268      if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
269              rtems_bsdnet_semaphore_release ();
270              return -1;
271      }
272      error = soshutdown(so, how);
273      rtems_bsdnet_semaphore_release ();
274      if (error) {
275              errno = error;
276              return -1;
277      }
278      return 0;
279}
280
281/*
282 * All `transmit' operations end up calling this routine.
283 */
284ssize_t
285sendmsg (int s, const struct msghdr *mp, int flags)
286{
287        int ret = -1;
288        int error;
289        struct uio auio;
290        struct iovec *iov;
291        struct socket *so;
292        struct mbuf *to, *control;
293        int i;
294        int len;
295
296        rtems_bsdnet_semaphore_obtain ();
297        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
298                rtems_bsdnet_semaphore_release ();
299                return -1;
300        }
301        auio.uio_iov = mp->msg_iov;
302        auio.uio_iovcnt = mp->msg_iovlen;
303        auio.uio_segflg = UIO_USERSPACE;
304        auio.uio_rw = UIO_WRITE;
305        auio.uio_offset = 0;
306        auio.uio_resid = 0;
307        iov = mp->msg_iov;
308        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
309                if ((auio.uio_resid += iov->iov_len) < 0) {
310                        errno = EINVAL;
311                        rtems_bsdnet_semaphore_release ();
312                        return -1;
313                }
314        }
315        if (mp->msg_name) {
316                error = sockargstombuf (&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
317                if (error) {
318                        errno = error;
319                        rtems_bsdnet_semaphore_release ();
320                        return -1;
321                }
322        }
323        else {
324                to = NULL;
325        }
326        if (mp->msg_control) {
327                if (mp->msg_controllen < sizeof (struct cmsghdr)) {
328                        errno = EINVAL;
329                        if (to)
330                                m_freem(to);
331                        rtems_bsdnet_semaphore_release ();
332                        return -1;
333                }
334                sockargstombuf (&control, mp->msg_control, mp->msg_controllen, MT_CONTROL);
335        }
336        else {
337                control = NULL;
338        }
339        len = auio.uio_resid;
340        error = sosend (so, to, &auio, (struct mbuf *)0, control, flags);
341        if (error) {
342                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
343                        error = 0;
344        }
345        if (error)
346                errno = error;
347        else
348                ret = len - auio.uio_resid;
349        if (to)
350                m_freem(to);
351        rtems_bsdnet_semaphore_release ();
352        return (ret);
353}
354
355/*
356 * Send a message to a host
357 */
358ssize_t
359sendto (int s, const void *buf, size_t buflen, int flags, const struct sockaddr *to, int tolen)
360{
361        struct msghdr msg;
362        struct iovec iov;
363
364        iov.iov_base = (void *)buf;
365        iov.iov_len = buflen;
366        msg.msg_name = (caddr_t)to;
367        msg.msg_namelen = tolen;
368        msg.msg_iov = &iov;
369        msg.msg_iovlen = 1;
370        msg.msg_control = NULL;
371        msg.msg_controllen = 0;
372        return sendmsg (s, &msg, flags);
373}
374
375/*
376 * Send a message to a connected host
377 */
378ssize_t
379send (int s, const void *buf, size_t buflen, int flags)
380{
381        return sendto (s, buf, buflen, flags, NULL, 0);
382}
383
384/*
385 * All `receive' operations end up calling this routine.
386 */
387ssize_t
388recvmsg (int s, struct msghdr *mp, int flags)
389{
390        int ret = -1;
391        int error;
392        struct uio auio;
393        struct iovec *iov;
394        struct socket *so;
395        struct mbuf *from = NULL, *control = NULL;
396        int i;
397        int len;
398
399        rtems_bsdnet_semaphore_obtain ();
400        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
401                rtems_bsdnet_semaphore_release ();
402                return -1;
403        }
404        auio.uio_iov = mp->msg_iov;
405        auio.uio_iovcnt = mp->msg_iovlen;
406        auio.uio_segflg = UIO_USERSPACE;
407        auio.uio_rw = UIO_READ;
408        auio.uio_offset = 0;
409        auio.uio_resid = 0;
410        iov = mp->msg_iov;
411        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
412                if ((auio.uio_resid += iov->iov_len) < 0) {
413                        errno = EINVAL;
414                        rtems_bsdnet_semaphore_release ();
415                        return -1;
416                }
417        }
418        len = auio.uio_resid;
419        mp->msg_flags = flags;
420        error = soreceive (so, &from, &auio, (struct mbuf **)NULL,
421                        mp->msg_control ? &control : (struct mbuf **)NULL,
422                        &mp->msg_flags);
423        if (error) {
424                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
425                        error = 0;
426        }
427        if (error) {
428                errno = error;
429        }
430        else {
431                ret = len - auio.uio_resid;
432                if (mp->msg_name) {
433                        len = mp->msg_namelen;
434                        if ((len <= 0) || (from == NULL)) {
435                                len = 0;
436                        }
437                        else {
438                                if (len > from->m_len)
439                                        len = from->m_len;
440                                memcpy (mp->msg_name, mtod(from, caddr_t), len);
441                        }
442                        mp->msg_namelen = len;
443                }
444                if (mp->msg_control) {
445                        struct mbuf *m;
446                        void *ctlbuf;
447
448                        len = mp->msg_controllen;
449                        m = control;
450                        mp->msg_controllen = 0;
451                        ctlbuf = mp->msg_control;
452
453                        while (m && (len > 0)) {
454                                unsigned int tocopy;
455
456                                if (len >= m->m_len)
457                                        tocopy = m->m_len;
458                                else {
459                                        mp->msg_flags |= MSG_CTRUNC;
460                                        tocopy = len;
461                                }
462                                memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
463                                ctlbuf += tocopy;
464                                len -= tocopy;
465                                m = m->m_next;
466                        }
467                        mp->msg_controllen = ctlbuf - mp->msg_control;
468                }
469        }
470        if (from)
471                m_freem (from);
472        if (control)
473                m_freem (control);
474        rtems_bsdnet_semaphore_release ();
475        return (ret);
476}
477
478/*
479 * Receive a message from a host
480 */
481ssize_t
482recvfrom (int s, void *buf, size_t buflen, int flags, const struct sockaddr *from, int *fromlen)
483{
484        struct msghdr msg;
485        struct iovec iov;
486        int ret;
487
488        iov.iov_base = buf;
489        iov.iov_len = buflen;
490        msg.msg_name = (caddr_t)from;
491        if (fromlen)
492                msg.msg_namelen = *fromlen;
493        else
494        msg.msg_namelen = 0;
495        msg.msg_iov = &iov;
496        msg.msg_iovlen = 1;
497        msg.msg_control = NULL;
498        msg.msg_controllen = 0;
499        ret = recvmsg (s, &msg, flags);
500        if ((from != NULL) && (fromlen != NULL) && (ret >= 0))
501                *fromlen = msg.msg_namelen;
502        return ret;
503}
504
505/*
506 * Receive a message from a connected host
507 */
508ssize_t
509recv (int s, void *buf, size_t buflen, int flags)
510{
511        return recvfrom (s, buf, buflen, flags, NULL, NULL);
512}
513
514int
515setsockopt (int s, int level, int name, const void *val, int len)
516{
517        struct socket *so;
518        struct mbuf *m = NULL;
519        int error;
520
521        rtems_bsdnet_semaphore_obtain ();
522        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
523                rtems_bsdnet_semaphore_release ();
524                return -1;
525        }
526        if (len > MLEN) {
527                errno = EINVAL;
528                rtems_bsdnet_semaphore_release ();
529                return -1;
530        }
531        if (val) {
532                error = sockargstombuf (&m, val, len, MT_SOOPTS);
533                if (error) {
534                        errno = error;
535                        rtems_bsdnet_semaphore_release ();
536                        return -1;
537                }
538        }
539        error = sosetopt(so, level, name, m);
540        if (error) {
541                errno = error;
542                rtems_bsdnet_semaphore_release ();
543                return -1;
544        }
545        rtems_bsdnet_semaphore_release ();
546        return 0;
547}
548
549int
550getsockopt (int s, int level, int name, void *aval, int *avalsize)
551{
552        struct socket *so;
553        struct mbuf *m = NULL, *m0;
554        char *val = aval;
555        int i, op, valsize;
556        int error;
557
558        rtems_bsdnet_semaphore_obtain ();
559        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
560                rtems_bsdnet_semaphore_release ();
561                return -1;
562        }
563        if (val)
564                valsize = *avalsize;
565        else
566                valsize = 0;
567        if (((error = sogetopt(so, level, name, &m)) == 0) && val && valsize && m) {
568                op = 0;
569                while (m && op < valsize) {
570                        i = valsize - op;
571                        if (i > m->m_len)
572                                i = m->m_len;
573                        memcpy (val, mtod(m, caddr_t), i);
574                        op += i;
575                        val += i;
576                        m0 = m;
577                        MFREE (m0, m);
578                }
579                *avalsize = op;
580        }
581        if (m != NULL)
582                (void) m_free(m);
583        if (error) {
584                errno = error;
585                rtems_bsdnet_semaphore_release ();
586                return -1;
587        }
588        rtems_bsdnet_semaphore_release ();
589        return 0;
590}
591
592static int
593getpeersockname (int s, struct sockaddr *name, int *namelen, int pflag)
594{
595        struct socket *so;
596        struct mbuf *m;
597        int len = *namelen;
598        int error;
599
600        rtems_bsdnet_semaphore_obtain ();
601        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
602                rtems_bsdnet_semaphore_release ();
603                return -1;
604        }
605        m = m_getclr(M_WAIT, MT_SONAME);
606        if (m == NULL) {
607                errno = ENOBUFS;
608                rtems_bsdnet_semaphore_release ();
609                return -1;
610        }
611        if (pflag)
612                error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m);
613        else
614                error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m);
615        if (error) {
616                m_freem(m);
617                errno = error;
618                rtems_bsdnet_semaphore_release ();
619                return -1;
620        }
621        if (len > m->m_len) {
622                len = m->m_len;
623                *namelen = len;
624        }
625        memcpy (name, mtod(m, caddr_t), len);
626        m_freem (m);
627        rtems_bsdnet_semaphore_release ();
628        return 0;
629}
630
631int
632getpeername (int s, struct sockaddr *name, int *namelen)
633{
634        return getpeersockname (s, name, namelen, 1);
635}
636int
637getsockname (int s, struct sockaddr *name, int *namelen)
638{
639        return getpeersockname (s, name, namelen, 0);
640}
641
642int
643sysctl(int *name, u_int namelen, void *oldp,
644       size_t *oldlenp, void *newp, size_t newlen)
645{
646  int    error;
647        size_t j;
648
649  rtems_bsdnet_semaphore_obtain ();
650  error = userland_sysctl (0, name, namelen, oldp, oldlenp, 1, newp, newlen, &j);
651  rtems_bsdnet_semaphore_release ();
652
653  if (oldlenp)
654    *oldlenp = j;
655
656  if (error)
657  {
658    errno = error;
659    return -1;
660  }
661  return 0;
662}
663
664/*
665 ************************************************************************
666 *                      RTEMS I/O HANDLER ROUTINES                      *
667 ************************************************************************
668 */
669static int
670rtems_bsdnet_close (rtems_libio_t *iop)
671{
672        struct socket *so;
673        int error;
674
675        rtems_bsdnet_semaphore_obtain ();
676        if ((so = iop->data1) == NULL) {
677                errno = EBADF;
678                rtems_bsdnet_semaphore_release ();
679                return -1;
680        }
681        error = soclose (so);
682        rtems_bsdnet_semaphore_release ();
683        if (error) {
684                errno = error;
685                return -1;
686        }
687        return 0;
688}
689
690static ssize_t
691rtems_bsdnet_read (rtems_libio_t *iop, void *buffer, uint32_t   count)
692{
693        return recv (iop->data0, buffer, count, 0);
694}
695
696static ssize_t
697rtems_bsdnet_write (rtems_libio_t *iop, const void *buffer, uint32_t   count)
698{
699        return send (iop->data0, buffer, count, 0);
700}
701
702static int
703so_ioctl (rtems_libio_t *iop, struct socket *so, uint32_t   command, void *buffer)
704{
705        switch (command) {
706        case FIONBIO:
707                if (*(int *)buffer) {
708                        iop->flags |= O_NONBLOCK;
709                        so->so_state |= SS_NBIO;
710                }
711                else {
712                        iop->flags &= ~O_NONBLOCK;
713                        so->so_state &= ~SS_NBIO;
714                }
715                return 0;
716
717        case FIONREAD:
718                *(int *)buffer = so->so_rcv.sb_cc;
719                return 0;
720        }
721
722        if (IOCGROUP(command) == 'i')
723                return ifioctl (so, command, buffer, NULL);
724        if (IOCGROUP(command) == 'r')
725                return rtioctl (command, buffer, NULL);
726        return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0);
727}
728
729static int
730rtems_bsdnet_ioctl (rtems_libio_t *iop, uint32_t   command, void *buffer)
731{
732        struct socket *so;
733        int error;
734
735        rtems_bsdnet_semaphore_obtain ();
736        if ((so = iop->data1) == NULL) {
737                errno = EBADF;
738                rtems_bsdnet_semaphore_release ();
739                return -1;
740        }
741        error = so_ioctl (iop, so, command, buffer);
742        rtems_bsdnet_semaphore_release ();
743        if (error) {
744                errno = error;
745                return -1;
746        }
747        return 0;
748}
749
750static int
751rtems_bsdnet_fcntl (int cmd, rtems_libio_t *iop)
752{
753        struct socket *so;
754
755        if (cmd == F_SETFL) {
756                rtems_bsdnet_semaphore_obtain ();
757                if ((so = iop->data1) == NULL) {
758                        rtems_bsdnet_semaphore_release ();
759                        return EBADF;
760                }
761                if (iop->flags & LIBIO_FLAGS_NO_DELAY)
762                        so->so_state |= SS_NBIO;
763                else
764                        so->so_state &= ~SS_NBIO;
765                rtems_bsdnet_semaphore_release ();
766        }
767        return 0;
768}
769
770static int
771rtems_bsdnet_fstat (rtems_filesystem_location_info_t *loc, struct stat *sp)
772{
773        sp->st_mode = S_IFSOCK;
774        return 0;
775}
776
777static const rtems_filesystem_file_handlers_r socket_handlers = {
778        NULL,                   /* open */
779        rtems_bsdnet_close,     /* close */
780        rtems_bsdnet_read,      /* read */
781        rtems_bsdnet_write,     /* write */
782        rtems_bsdnet_ioctl,     /* ioctl */
783        NULL,                   /* lseek */
784        rtems_bsdnet_fstat,     /* fstat */
785        NULL,                   /* fchmod */
786        NULL,                   /* ftruncate */
787        NULL,                   /* fpathconf */
788        NULL,                   /* fsync */
789        NULL,                   /* fdatasync */
790        rtems_bsdnet_fcntl,     /* fcntl */
791};
Note: See TracBrowser for help on using the repository browser.