source: rtems/cpukit/libnetworking/rtems/rtems_syscall.c @ b3f8c9e1

4.104.11
Last change on this file since b3f8c9e1 was b3f8c9e1, checked in by Ralf Corsepius <ralf.corsepius@…>, on Dec 22, 2008 at 7:47:28 AM

Include <errno.h> (POSIX,C99) instead of <sys/errno.h> (BSD'ism).

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