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

4.104.114.84.95
Last change on this file since caeacbcc was caeacbcc, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/22/04 at 04:04:21

2004-04-22 Ralf Corsepius <ralf_corsepius@…>

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