source: rtems/cpukit/libnetworking/rtems/rtems_syscall.c @ 2b2cfb7

4.104.114.84.95
Last change on this file since 2b2cfb7 was 7192476f, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/08/06 at 07:18:27

Use size_t instead of uint32_t for read/write count-args.

  • 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;
293        struct mbuf *control = NULL;
294        int i;
295        int len;
296
297        rtems_bsdnet_semaphore_obtain ();
298        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
299                rtems_bsdnet_semaphore_release ();
300                return -1;
301        }
302        auio.uio_iov = mp->msg_iov;
303        auio.uio_iovcnt = mp->msg_iovlen;
304        auio.uio_segflg = UIO_USERSPACE;
305        auio.uio_rw = UIO_WRITE;
306        auio.uio_offset = 0;
307        auio.uio_resid = 0;
308        iov = mp->msg_iov;
309        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
310                if ((auio.uio_resid += iov->iov_len) < 0) {
311                        errno = EINVAL;
312                        rtems_bsdnet_semaphore_release ();
313                        return -1;
314                }
315        }
316        if (mp->msg_name) {
317                error = sockargstombuf (&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
318                if (error) {
319                        errno = error;
320                        rtems_bsdnet_semaphore_release ();
321                        return -1;
322                }
323        }
324        else {
325                to = NULL;
326        }
327        if (mp->msg_control) {
328                if (mp->msg_controllen < sizeof (struct cmsghdr)) {
329                        errno = EINVAL;
330                        if (to)
331                                m_freem(to);
332                        rtems_bsdnet_semaphore_release ();
333                        return -1;
334                }
335                sockargstombuf (&control, mp->msg_control, mp->msg_controllen, MT_CONTROL);
336        }
337        else {
338                control = NULL;
339        }
340        len = auio.uio_resid;
341        error = sosend (so, to, &auio, (struct mbuf *)0, control, flags);
342        if (error) {
343                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
344                        error = 0;
345        }
346        if (error)
347                errno = error;
348        else
349                ret = len - auio.uio_resid;
350        if (to)
351                m_freem(to);
352        rtems_bsdnet_semaphore_release ();
353        return (ret);
354}
355
356/*
357 * Send a message to a host
358 */
359ssize_t
360sendto (int s, const void *buf, size_t buflen, int flags, const struct sockaddr *to, int tolen)
361{
362        struct msghdr msg;
363        struct iovec iov;
364
365        iov.iov_base = (void *)buf;
366        iov.iov_len = buflen;
367        msg.msg_name = (caddr_t)to;
368        msg.msg_namelen = tolen;
369        msg.msg_iov = &iov;
370        msg.msg_iovlen = 1;
371        msg.msg_control = NULL;
372        msg.msg_controllen = 0;
373        return sendmsg (s, &msg, flags);
374}
375
376/*
377 * Send a message to a connected host
378 */
379ssize_t
380send (int s, const void *buf, size_t buflen, int flags)
381{
382        return sendto (s, buf, buflen, flags, NULL, 0);
383}
384
385/*
386 * All `receive' operations end up calling this routine.
387 */
388ssize_t
389recvmsg (int s, struct msghdr *mp, int flags)
390{
391        int ret = -1;
392        int error;
393        struct uio auio;
394        struct iovec *iov;
395        struct socket *so;
396        struct mbuf *from = NULL, *control = NULL;
397        int i;
398        int len;
399
400        rtems_bsdnet_semaphore_obtain ();
401        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
402                rtems_bsdnet_semaphore_release ();
403                return -1;
404        }
405        auio.uio_iov = mp->msg_iov;
406        auio.uio_iovcnt = mp->msg_iovlen;
407        auio.uio_segflg = UIO_USERSPACE;
408        auio.uio_rw = UIO_READ;
409        auio.uio_offset = 0;
410        auio.uio_resid = 0;
411        iov = mp->msg_iov;
412        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
413                if ((auio.uio_resid += iov->iov_len) < 0) {
414                        errno = EINVAL;
415                        rtems_bsdnet_semaphore_release ();
416                        return -1;
417                }
418        }
419        len = auio.uio_resid;
420        mp->msg_flags = flags;
421        error = soreceive (so, &from, &auio, (struct mbuf **)NULL,
422                        mp->msg_control ? &control : (struct mbuf **)NULL,
423                        &mp->msg_flags);
424        if (error) {
425                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
426                        error = 0;
427        }
428        if (error) {
429                errno = error;
430        }
431        else {
432                ret = len - auio.uio_resid;
433                if (mp->msg_name) {
434                        len = mp->msg_namelen;
435                        if ((len <= 0) || (from == NULL)) {
436                                len = 0;
437                        }
438                        else {
439                                if (len > from->m_len)
440                                        len = from->m_len;
441                                memcpy (mp->msg_name, mtod(from, caddr_t), len);
442                        }
443                        mp->msg_namelen = len;
444                }
445                if (mp->msg_control) {
446                        struct mbuf *m;
447                        void *ctlbuf;
448
449                        len = mp->msg_controllen;
450                        m = control;
451                        mp->msg_controllen = 0;
452                        ctlbuf = mp->msg_control;
453
454                        while (m && (len > 0)) {
455                                unsigned int tocopy;
456
457                                if (len >= m->m_len)
458                                        tocopy = m->m_len;
459                                else {
460                                        mp->msg_flags |= MSG_CTRUNC;
461                                        tocopy = len;
462                                }
463                                memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
464                                ctlbuf += tocopy;
465                                len -= tocopy;
466                                m = m->m_next;
467                        }
468                        mp->msg_controllen = ctlbuf - mp->msg_control;
469                }
470        }
471        if (from)
472                m_freem (from);
473        if (control)
474                m_freem (control);
475        rtems_bsdnet_semaphore_release ();
476        return (ret);
477}
478
479/*
480 * Receive a message from a host
481 */
482ssize_t
483recvfrom (int s, void *buf, size_t buflen, int flags, const struct sockaddr *from, int *fromlen)
484{
485        struct msghdr msg;
486        struct iovec iov;
487        int ret;
488
489        iov.iov_base = buf;
490        iov.iov_len = buflen;
491        msg.msg_name = (caddr_t)from;
492        if (fromlen)
493                msg.msg_namelen = *fromlen;
494        else
495        msg.msg_namelen = 0;
496        msg.msg_iov = &iov;
497        msg.msg_iovlen = 1;
498        msg.msg_control = NULL;
499        msg.msg_controllen = 0;
500        ret = recvmsg (s, &msg, flags);
501        if ((from != NULL) && (fromlen != NULL) && (ret >= 0))
502                *fromlen = msg.msg_namelen;
503        return ret;
504}
505
506/*
507 * Receive a message from a connected host
508 */
509ssize_t
510recv (int s, void *buf, size_t buflen, int flags)
511{
512        return recvfrom (s, buf, buflen, flags, NULL, NULL);
513}
514
515int
516setsockopt (int s, int level, int name, const void *val, int len)
517{
518        struct socket *so;
519        struct mbuf *m = NULL;
520        int error;
521
522        rtems_bsdnet_semaphore_obtain ();
523        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
524                rtems_bsdnet_semaphore_release ();
525                return -1;
526        }
527        if (len > MLEN) {
528                errno = EINVAL;
529                rtems_bsdnet_semaphore_release ();
530                return -1;
531        }
532        if (val) {
533                error = sockargstombuf (&m, val, len, MT_SOOPTS);
534                if (error) {
535                        errno = error;
536                        rtems_bsdnet_semaphore_release ();
537                        return -1;
538                }
539        }
540        error = sosetopt(so, level, name, m);
541        if (error) {
542                errno = error;
543                rtems_bsdnet_semaphore_release ();
544                return -1;
545        }
546        rtems_bsdnet_semaphore_release ();
547        return 0;
548}
549
550int
551getsockopt (int s, int level, int name, void *aval, int *avalsize)
552{
553        struct socket *so;
554        struct mbuf *m = NULL, *m0;
555        char *val = aval;
556        int i, op, valsize;
557        int error;
558
559        rtems_bsdnet_semaphore_obtain ();
560        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
561                rtems_bsdnet_semaphore_release ();
562                return -1;
563        }
564        if (val)
565                valsize = *avalsize;
566        else
567                valsize = 0;
568        if (((error = sogetopt(so, level, name, &m)) == 0) && val && valsize && m) {
569                op = 0;
570                while (m && op < valsize) {
571                        i = valsize - op;
572                        if (i > m->m_len)
573                                i = m->m_len;
574                        memcpy (val, mtod(m, caddr_t), i);
575                        op += i;
576                        val += i;
577                        m0 = m;
578                        MFREE (m0, m);
579                }
580                *avalsize = op;
581        }
582        if (m != NULL)
583                (void) m_free(m);
584        if (error) {
585                errno = error;
586                rtems_bsdnet_semaphore_release ();
587                return -1;
588        }
589        rtems_bsdnet_semaphore_release ();
590        return 0;
591}
592
593static int
594getpeersockname (int s, struct sockaddr *name, int *namelen, int pflag)
595{
596        struct socket *so;
597        struct mbuf *m;
598        int len = *namelen;
599        int error;
600
601        rtems_bsdnet_semaphore_obtain ();
602        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
603                rtems_bsdnet_semaphore_release ();
604                return -1;
605        }
606        m = m_getclr(M_WAIT, MT_SONAME);
607        if (m == NULL) {
608                errno = ENOBUFS;
609                rtems_bsdnet_semaphore_release ();
610                return -1;
611        }
612        if (pflag)
613                error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m);
614        else
615                error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m);
616        if (error) {
617                m_freem(m);
618                errno = error;
619                rtems_bsdnet_semaphore_release ();
620                return -1;
621        }
622        if (len > m->m_len) {
623                len = m->m_len;
624                *namelen = len;
625        }
626        memcpy (name, mtod(m, caddr_t), len);
627        m_freem (m);
628        rtems_bsdnet_semaphore_release ();
629        return 0;
630}
631
632int
633getpeername (int s, struct sockaddr *name, int *namelen)
634{
635        return getpeersockname (s, name, namelen, 1);
636}
637int
638getsockname (int s, struct sockaddr *name, int *namelen)
639{
640        return getpeersockname (s, name, namelen, 0);
641}
642
643int
644sysctl(int *name, u_int namelen, void *oldp,
645       size_t *oldlenp, void *newp, size_t newlen)
646{
647  int    error;
648        size_t j;
649
650  rtems_bsdnet_semaphore_obtain ();
651  error = userland_sysctl (0, name, namelen, oldp, oldlenp, 1, newp, newlen, &j);
652  rtems_bsdnet_semaphore_release ();
653
654  if (oldlenp)
655    *oldlenp = j;
656
657  if (error)
658  {
659    errno = error;
660    return -1;
661  }
662  return 0;
663}
664
665/*
666 ************************************************************************
667 *                      RTEMS I/O HANDLER ROUTINES                      *
668 ************************************************************************
669 */
670static int
671rtems_bsdnet_close (rtems_libio_t *iop)
672{
673        struct socket *so;
674        int error;
675
676        rtems_bsdnet_semaphore_obtain ();
677        if ((so = iop->data1) == NULL) {
678                errno = EBADF;
679                rtems_bsdnet_semaphore_release ();
680                return -1;
681        }
682        error = soclose (so);
683        rtems_bsdnet_semaphore_release ();
684        if (error) {
685                errno = error;
686                return -1;
687        }
688        return 0;
689}
690
691static ssize_t
692rtems_bsdnet_read (rtems_libio_t *iop, void *buffer, size_t count)
693{
694        return recv (iop->data0, buffer, count, 0);
695}
696
697static ssize_t
698rtems_bsdnet_write (rtems_libio_t *iop, const void *buffer, size_t count)
699{
700        return send (iop->data0, buffer, count, 0);
701}
702
703static int
704so_ioctl (rtems_libio_t *iop, struct socket *so, uint32_t   command, void *buffer)
705{
706        switch (command) {
707        case FIONBIO:
708                if (*(int *)buffer) {
709                        iop->flags |= O_NONBLOCK;
710                        so->so_state |= SS_NBIO;
711                }
712                else {
713                        iop->flags &= ~O_NONBLOCK;
714                        so->so_state &= ~SS_NBIO;
715                }
716                return 0;
717
718        case FIONREAD:
719                *(int *)buffer = so->so_rcv.sb_cc;
720                return 0;
721        }
722
723        if (IOCGROUP(command) == 'i')
724                return ifioctl (so, command, buffer, NULL);
725        if (IOCGROUP(command) == 'r')
726                return rtioctl (command, buffer, NULL);
727        return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0);
728}
729
730static int
731rtems_bsdnet_ioctl (rtems_libio_t *iop, uint32_t   command, void *buffer)
732{
733        struct socket *so;
734        int error;
735
736        rtems_bsdnet_semaphore_obtain ();
737        if ((so = iop->data1) == NULL) {
738                errno = EBADF;
739                rtems_bsdnet_semaphore_release ();
740                return -1;
741        }
742        error = so_ioctl (iop, so, command, buffer);
743        rtems_bsdnet_semaphore_release ();
744        if (error) {
745                errno = error;
746                return -1;
747        }
748        return 0;
749}
750
751static int
752rtems_bsdnet_fcntl (int cmd, rtems_libio_t *iop)
753{
754        struct socket *so;
755
756        if (cmd == F_SETFL) {
757                rtems_bsdnet_semaphore_obtain ();
758                if ((so = iop->data1) == NULL) {
759                        rtems_bsdnet_semaphore_release ();
760                        return EBADF;
761                }
762                if (iop->flags & LIBIO_FLAGS_NO_DELAY)
763                        so->so_state |= SS_NBIO;
764                else
765                        so->so_state &= ~SS_NBIO;
766                rtems_bsdnet_semaphore_release ();
767        }
768        return 0;
769}
770
771static int
772rtems_bsdnet_fstat (rtems_filesystem_location_info_t *loc, struct stat *sp)
773{
774        sp->st_mode = S_IFSOCK;
775        return 0;
776}
777
778static const rtems_filesystem_file_handlers_r socket_handlers = {
779        NULL,                   /* open */
780        rtems_bsdnet_close,     /* close */
781        rtems_bsdnet_read,      /* read */
782        rtems_bsdnet_write,     /* write */
783        rtems_bsdnet_ioctl,     /* ioctl */
784        NULL,                   /* lseek */
785        rtems_bsdnet_fstat,     /* fstat */
786        NULL,                   /* fchmod */
787        NULL,                   /* ftruncate */
788        NULL,                   /* fpathconf */
789        NULL,                   /* fsync */
790        NULL,                   /* fdatasync */
791        rtems_bsdnet_fcntl,     /* fcntl */
792};
Note: See TracBrowser for help on using the repository browser.