source: rtems/c/src/lib/libnetworking/rtems/rtems_syscall.c @ cdf8a300

4.104.114.84.95
Last change on this file since cdf8a300 was cdf8a300, checked in by Joel Sherrill <joel.sherrill@…>, on 01/28/99 at 18:42:34

Patch from Eric Norum <eric@…> to avoid dereferencing a
NULL pointer.

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