source: rtems-libbsd/rtemsbsd/rtems/rtems-bsd-syscalls.c @ ec702ab

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since ec702ab was ec702ab, checked in by Sebastian Huber <sebastian.huber@…>, on 10/14/13 at 12:55:04

Use socket read() and write() from FreeBSD

  • Property mode set to 100644
File size: 13.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2009, 2010 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Obere Lagerstr. 30
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40#include <machine/rtems-bsd-config.h>
41#include <machine/rtems-bsd-thread.h>
42
43#include <rtems/bsd/sys/types.h>
44#include <rtems/bsd/sys/param.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <rtems/bsd/sys/lock.h>
48#include <sys/mutex.h>
49#include <sys/malloc.h>
50#include <sys/proc.h>
51#include <sys/fcntl.h>
52#include <sys/protosw.h>
53#include <sys/mbuf.h>
54#include <sys/socket.h>
55#include <sys/socketvar.h>
56#include <sys/uio.h>
57#include <machine/pcpu.h>
58#include <net/vnet.h>
59
60#include <rtems/libio_.h>
61#include <rtems/libio.h>
62#include <rtems/seterr.h>
63
64static const rtems_filesystem_file_handlers_r socket_handlers;
65extern int killinfo( pid_t pid, int sig, const union sigval *value );
66
67/*
68 * Convert an RTEMS file descriptor to a BSD socket pointer.
69 */
70
71struct socket *rtems_bsdnet_fdToSocket(
72  int fd
73)
74{
75  rtems_libio_t *iop;
76
77  /* same as rtems_libio_check_fd(_fd) but different return */
78  if ((uint32_t)fd >= rtems_libio_number_iops) {
79    errno = EBADF;
80    return NULL;
81  }
82  iop = &rtems_libio_iops[fd];
83
84  /* same as rtems_libio_check_is_open(iop) but different return */
85  if ((iop->flags & LIBIO_FLAGS_OPEN) == 0) {
86    errno = EBADF;
87    return NULL;
88  }
89
90  if (iop->data1 == NULL)
91    errno = EBADF;
92  return iop->data1;
93}
94
95/*
96 * Create an RTEMS file descriptor for a socket
97 */
98static int rtems_bsdnet_makeFdForSocket (void *so)
99{
100  rtems_libio_t *iop;
101  int fd;
102
103  iop = rtems_libio_allocate();
104  if (iop == 0)
105      rtems_set_errno_and_return_minus_one( ENFILE );
106
107  fd = iop - rtems_libio_iops;
108  iop->flags |= LIBIO_FLAGS_WRITE | LIBIO_FLAGS_READ;
109  iop->data0 = fd;
110  iop->data1 = so;
111  iop->pathinfo.handlers = &socket_handlers;
112  iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry;
113  rtems_filesystem_location_add_to_mt_entry(&iop->pathinfo);
114  return fd;
115}
116
117/*
118 * The following code is based on FreeBSD uipc_syscalls.c
119 */
120
121int
122sockargs(mp, buf, buflen, type)
123        struct mbuf **mp;
124        caddr_t buf;
125        int buflen, type;
126{
127        struct sockaddr *sa;
128        struct mbuf *m;
129        int error;
130
131        if ((u_int)buflen > MLEN) {
132#ifdef COMPAT_OLDSOCK
133                if (type == MT_SONAME && (u_int)buflen <= 112)
134                        buflen = MLEN;          /* unix domain compat. hack */
135                else
136#endif
137                        if ((u_int)buflen > MCLBYTES)
138                                return (EINVAL);
139        }
140        m = m_get(M_WAIT, type);
141        if ((u_int)buflen > MLEN)
142                MCLGET(m, M_WAIT);
143        m->m_len = buflen;
144        error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
145        if (error)
146                (void) m_free(m);
147        else {
148                *mp = m;
149                if (type == MT_SONAME) {
150                        sa = mtod(m, struct sockaddr *);
151
152#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
153                        if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
154                                sa->sa_family = sa->sa_len;
155#endif
156                        sa->sa_len = buflen;
157                }
158        }
159        return (error);
160}
161
162/*
163 *********************************************************************
164 *                       BSD-style entry points                      *
165 *********************************************************************
166 */
167
168int
169kern_sendit(td, s, mp, flags, control, segflg)
170        struct thread *td;
171        int s;
172        struct msghdr *mp;
173        int flags;
174        struct mbuf *control;
175        enum uio_seg segflg;
176{
177        struct uio auio;
178        struct iovec *iov;
179        struct socket *so;
180        int i;
181        int len, error;
182#ifdef KTRACE
183        struct uio *ktruio = NULL;
184#endif
185
186        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
187                error = EBADF;
188                return (error);
189        }
190
191#ifdef MAC
192        if (mp->msg_name != NULL) {
193                error = mac_socket_check_connect(td->td_ucred, so,
194                    mp->msg_name);
195                if (error)
196                        goto bad;
197        }
198        error = mac_socket_check_send(td->td_ucred, so);
199        if (error)
200                goto bad;
201#endif
202
203        auio.uio_iov = mp->msg_iov;
204        auio.uio_iovcnt = mp->msg_iovlen;
205        auio.uio_segflg = segflg;
206        auio.uio_rw = UIO_WRITE;
207        auio.uio_td = td;
208        auio.uio_offset = 0;                    /* XXX */
209        auio.uio_resid = 0;
210        iov = mp->msg_iov;
211        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
212                if ((auio.uio_resid += iov->iov_len) < 0) {
213                        error = EINVAL;
214                        goto bad;
215                }
216        }
217#ifdef KTRACE
218        if (KTRPOINT(td, KTR_GENIO))
219                ktruio = cloneuio(&auio);
220#endif
221        len = auio.uio_resid;
222        error = sosend(so, mp->msg_name, &auio, 0, control, flags, td);
223        if (error) {
224                if (auio.uio_resid != len && (error == ERESTART ||
225                    error == EINTR || error == EWOULDBLOCK))
226                        error = 0;
227                /* Generation of SIGPIPE can be controlled per socket */
228                if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&
229                    !(flags & MSG_NOSIGNAL)) {
230                        killinfo(rtems_bsd_get_task_id(td), SIGPIPE, NULL);
231                }
232        }
233        if (error == 0)
234                td->td_retval[0] = len - auio.uio_resid;
235#ifdef KTRACE
236        if (ktruio != NULL) {
237                ktruio->uio_resid = td->td_retval[0];
238                ktrgenio(s, UIO_WRITE, ktruio, error);
239        }
240#endif
241bad:
242        return (error);
243}
244
245static int
246sendit(td, s, mp, flags)
247        struct thread *td;
248        int s;
249        struct msghdr *mp;
250        int flags;
251{
252        struct mbuf *control;
253        struct sockaddr *to;
254        int error;
255
256        if (mp->msg_name != NULL) {
257                error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
258                if (error) {
259                        to = NULL;
260                        goto bad;
261                }
262                mp->msg_name = to;
263        } else {
264                to = NULL;
265        }
266
267        if (mp->msg_control) {
268                if (mp->msg_controllen < sizeof(struct cmsghdr)
269#ifdef COMPAT_OLDSOCK
270                    && mp->msg_flags != MSG_COMPAT
271#endif
272                ) {
273                        error = EINVAL;
274                        goto bad;
275                }
276                error = sockargs(&control, mp->msg_control,
277                    mp->msg_controllen, MT_CONTROL);
278                if (error)
279                        goto bad;
280#ifdef COMPAT_OLDSOCK
281                if (mp->msg_flags == MSG_COMPAT) {
282                        struct cmsghdr *cm;
283
284                        M_PREPEND(control, sizeof(*cm), M_WAIT);
285                        cm = mtod(control, struct cmsghdr *);
286                        cm->cmsg_len = control->m_len;
287                        cm->cmsg_level = SOL_SOCKET;
288                        cm->cmsg_type = SCM_RIGHTS;
289                }
290#endif
291        } else {
292                control = NULL;
293        }
294
295        error = kern_sendit(td, s, mp, flags, control, UIO_USERSPACE);
296
297bad:
298        if (to)
299                free(to, M_SONAME);
300        return (error);
301}
302
303/*
304 * All `transmit' operations end up calling this routine.
305 */
306ssize_t
307sendmsg (int s, const struct msghdr *mp, int flags)
308{
309        struct thread *td;
310        struct msghdr msg;
311        struct iovec *iov;
312        int error;
313
314        td = curthread;
315        error = copyin(mp, &msg, sizeof (msg));
316        if (error)
317                return (error);
318        error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
319        if (error)
320                return (error);
321        msg.msg_iov = iov;
322#ifdef COMPAT_OLDSOCK
323        msg.msg_flags = 0;
324#endif
325        error = sendit(td, s, &msg, flags);
326        free(iov, M_IOV);
327        if( error == 0 )
328        {
329                return td->td_retval[0];
330        }
331        errno = error;
332        return -1;
333}
334
335/*
336 * Send a message to a host
337 */
338ssize_t
339sendto (int s, const void *buf, size_t len, int flags, const struct sockaddr *to, int tolen)
340{
341        struct thread *td;
342        struct msghdr msg;
343        struct iovec aiov;
344        int error;
345
346        td = curthread;
347        msg.msg_name = to;
348        msg.msg_namelen = tolen;
349        msg.msg_iov = &aiov;
350        msg.msg_iovlen = 1;
351        msg.msg_control = 0;
352#ifdef COMPAT_OLDSOCK
353        msg.msg_flags = 0;
354#endif
355        aiov.iov_base = buf;
356        aiov.iov_len = len;
357        error = sendit(td, s, &msg, flags);
358        if( error == 0 )
359        {
360                return td->td_retval[0];
361        }
362        errno = error;
363        return -1;
364}
365
366int
367kern_recvit(td, s, mp, fromseg, controlp)
368        struct thread *td;
369        int s;
370        struct msghdr *mp;
371        enum uio_seg fromseg;
372        struct mbuf **controlp;
373{
374        struct uio auio;
375        struct iovec *iov;
376        int i;
377        socklen_t len;
378        int error;
379        struct mbuf *m, *control = 0;
380        caddr_t ctlbuf;
381        struct socket *so;
382        struct sockaddr *fromsa = 0;
383#ifdef KTRACE
384        struct uio *ktruio = NULL;
385#endif
386
387        if(controlp != NULL)
388                *controlp = 0;
389
390        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
391                error = EBADF;
392                return (error);
393        }
394
395#ifdef MAC
396        error = mac_socket_check_receive(td->td_ucred, so);
397        if (error) {
398                return (error);
399        }
400#endif
401
402        auio.uio_iov = mp->msg_iov;
403        auio.uio_iovcnt = mp->msg_iovlen;
404        auio.uio_segflg = UIO_USERSPACE;
405        auio.uio_rw = UIO_READ;
406        auio.uio_td = td;
407        auio.uio_offset = 0;                    /* XXX */
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                        return (EINVAL);
413                }
414        }
415#ifdef KTRACE
416        if (KTRPOINT(td, KTR_GENIO))
417                ktruio = cloneuio(&auio);
418#endif
419        len = auio.uio_resid;
420        CURVNET_SET(so->so_vnet);
421        error = soreceive(so, &fromsa, &auio, (struct mbuf **)0,
422            (mp->msg_control || controlp) ? &control : (struct mbuf **)0,
423            &mp->msg_flags);
424        CURVNET_RESTORE();
425        if (error) {
426                if (auio.uio_resid != (int)len && (error == ERESTART ||
427                    error == EINTR || error == EWOULDBLOCK))
428                        error = 0;
429        }
430#ifdef KTRACE
431        if (ktruio != NULL) {
432                ktruio->uio_resid = (int)len - auio.uio_resid;
433                ktrgenio(s, UIO_READ, ktruio, error);
434        }
435#endif
436        if (error)
437                goto out;
438        td->td_retval[0] = (int)len - auio.uio_resid;
439        if (mp->msg_name) {
440                len = mp->msg_namelen;
441                if (len <= 0 || fromsa == 0)
442                        len = 0;
443                else {
444                        /* save sa_len before it is destroyed by MSG_COMPAT */
445                        len = MIN(len, fromsa->sa_len);
446#ifdef COMPAT_OLDSOCK
447                        if (mp->msg_flags & MSG_COMPAT)
448                                ((struct osockaddr *)fromsa)->sa_family =
449                                    fromsa->sa_family;
450#endif
451                        if (fromseg == UIO_USERSPACE) {
452                                error = copyout(fromsa, mp->msg_name,
453                                    (unsigned)len);
454                                if (error)
455                                        goto out;
456                        } else
457                                bcopy(fromsa, mp->msg_name, len);
458                }
459                mp->msg_namelen = len;
460        }
461        if (mp->msg_control && controlp == NULL) {
462#ifdef COMPAT_OLDSOCK
463                /*
464                 * We assume that old recvmsg calls won't receive access
465                 * rights and other control info, esp. as control info
466                 * is always optional and those options didn't exist in 4.3.
467                 * If we receive rights, trim the cmsghdr; anything else
468                 * is tossed.
469                 */
470                if (control && mp->msg_flags & MSG_COMPAT) {
471                        if (mtod(control, struct cmsghdr *)->cmsg_level !=
472                            SOL_SOCKET ||
473                            mtod(control, struct cmsghdr *)->cmsg_type !=
474                            SCM_RIGHTS) {
475                                mp->msg_controllen = 0;
476                                goto out;
477                        }
478                        control->m_len -= sizeof (struct cmsghdr);
479                        control->m_data += sizeof (struct cmsghdr);
480                }
481#endif
482                len = mp->msg_controllen;
483                m = control;
484                mp->msg_controllen = 0;
485                ctlbuf = mp->msg_control;
486
487                while (m && len > 0) {
488                        unsigned int tocopy;
489
490                        if (len >= m->m_len)
491                                tocopy = m->m_len;
492                        else {
493                                mp->msg_flags |= MSG_CTRUNC;
494                                tocopy = len;
495                        }
496
497                        if ((error = copyout(mtod(m, caddr_t),
498                                        ctlbuf, tocopy)) != 0)
499                                goto out;
500
501                        ctlbuf += tocopy;
502                        len -= tocopy;
503                        m = m->m_next;
504                }
505                mp->msg_controllen = ctlbuf - (caddr_t)mp->msg_control;
506        }
507out:
508#ifdef KTRACE
509        if (fromsa && KTRPOINT(td, KTR_STRUCT))
510                ktrsockaddr(fromsa);
511#endif
512        if (fromsa)
513                free(fromsa, M_SONAME);
514
515        if (error == 0 && controlp != NULL)
516                *controlp = control;
517        else  if (control)
518                m_freem(control);
519
520        return (error);
521}
522
523static int
524recvit(td, s, mp, namelenp)
525        struct thread *td;
526        int s;
527        struct msghdr *mp;
528        void *namelenp;
529{
530        int error;
531
532        error = kern_recvit(td, s, mp, UIO_USERSPACE, NULL);
533        if (error)
534                return (error);
535        if (namelenp) {
536                error = copyout(&mp->msg_namelen, namelenp, sizeof (socklen_t));
537#ifdef COMPAT_OLDSOCK
538                if (mp->msg_flags & MSG_COMPAT)
539                        error = 0;      /* old recvfrom didn't check */
540#endif
541        }
542        return (error);
543}
544
545/*
546 * All `receive' operations end up calling this routine.
547 */
548ssize_t
549recvmsg (int s, struct msghdr *mp, int flags)
550{
551        struct thread *td;
552        struct msghdr msg;
553        struct iovec *uiov, *iov;
554        int error;
555
556        td = curthread;
557        error = copyin(mp, &msg, sizeof (msg));
558        if (error == 0 )
559        {
560                error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
561                if (error == 0)
562                {
563                        msg.msg_flags = flags;
564        #ifdef COMPAT_OLDSOCK
565                        msg.msg_flags &= ~MSG_COMPAT;
566        #endif
567                        uiov = msg.msg_iov;
568                        msg.msg_iov = iov;
569                        error = recvit(td, s, &msg, NULL);
570                        if (error == 0) {
571                                msg.msg_iov = uiov;
572                                error = copyout(&msg, mp, sizeof(msg));
573                        }
574                        free(iov, M_IOV);
575                }
576        }
577        if( error == 0 )
578        {
579                return td->td_retval[0];
580        }
581        errno = error;
582        return -1;
583}
584
585/*
586 * Receive a message from a host
587 */
588ssize_t
589recvfrom (int s, void *buf, size_t len, int flags, const struct sockaddr *from, socklen_t *fromlenaddr)
590{
591        struct thread *td;
592        struct msghdr msg;
593        struct iovec aiov;
594        int error;
595
596        td = curthread;
597        if (fromlenaddr) {
598                error = copyin(fromlenaddr,
599                    &msg.msg_namelen, sizeof (msg.msg_namelen));
600                if (error)
601                        goto done2;
602        } else {
603                msg.msg_namelen = 0;
604        }
605        msg.msg_name = from;
606        msg.msg_iov = &aiov;
607        msg.msg_iovlen = 1;
608        aiov.iov_base = buf;
609        aiov.iov_len = len;
610        msg.msg_control = 0;
611        msg.msg_flags = flags;
612        error = recvit(td, s, &msg, fromlenaddr);
613done2:
614        if( error == 0 )
615        {
616                return td->td_retval[0];
617        }
618        errno = error;
619        return -1;
620}
Note: See TracBrowser for help on using the repository browser.