/** * @file * * @brief Sock Mbuf * @ingroup libfs */ /* * NOTE: * This is derived from libnetworking/rtems/rtems_syscall.c * * RTEMS/libnetworking LICENSING restrictions may apply * * Author (modifications only): * Copyright: 2002, Stanford University and * Till Straumann, * Licensing: 'LICENSE.NET' file in the RTEMS top source directory * for more information. * * The RTEMS TCP/IP stack is a port of the FreeBSD TCP/IP stack. The following * copyright and licensing information applies to this code. * * This code is found under the c/src/libnetworking directory but does not * constitute the entire contents of that subdirectory. * * * Copyright (c) 1980, 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * Portions Copyright (c) 1993 by Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #define _KERNEL #define __BSD_VISIBLE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include struct socket *rtems_bsdnet_fdToSocket(int fd); /* * Package system call argument into mbuf. * * (unfortunately, the original is not public) */ static int sockaddrtombuf (struct mbuf **mp, const struct sockaddr *buf, int buflen) { struct mbuf *m; struct sockaddr *sa; if ((u_int)buflen > MLEN) return (EINVAL); rtems_bsdnet_semaphore_obtain(); m = m_get(M_WAIT, MT_SONAME); rtems_bsdnet_semaphore_release(); if (m == NULL) return (ENOBUFS); m->m_len = buflen; memcpy (mtod(m, caddr_t), buf, buflen); *mp = m; sa = mtod(m, struct sockaddr *); sa->sa_len = buflen; return 0; } static void dummyproc(caddr_t ext_buf, u_int ext_size) { } /* * send data by simply allocating an MBUF packet * header and pointing it to our data region. * * Optionally, the caller may supply 'reference' * and 'free' procs. (The latter may call the * user back once the networking stack has * released the buffer). * * The callbacks are provided with the 'closure' * pointer and the 'buflen' argument. */ ssize_t sendto_nocpy ( int s, const void *buf, size_t buflen, int flags, const struct sockaddr *toaddr, int tolen, void *closure, void (*freeproc)(caddr_t, u_int), void (*refproc)(caddr_t, u_int) ) { int error; struct socket *so; struct mbuf *to, *m; int ret = -1; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } error = sockaddrtombuf (&to, toaddr, tolen); if (error) { errno = error; rtems_bsdnet_semaphore_release (); return -1; } MGETHDR(m, M_WAIT, MT_DATA); m->m_pkthdr.len = 0; m->m_pkthdr.rcvif = (struct ifnet *) 0; m->m_flags |= M_EXT; m->m_ext.ext_buf = closure ? closure : (void*)buf; m->m_ext.ext_size = buflen; /* we _must_ supply non-null procs; otherwise, * the kernel code assumes it's a mbuf cluster */ m->m_ext.ext_free = freeproc ? freeproc : dummyproc; m->m_ext.ext_ref = refproc ? refproc : dummyproc; m->m_pkthdr.len += buflen; m->m_len = buflen; m->m_data = (void*)buf; error = sosend (so, to, NULL, m, NULL, flags); if (error) { if (/*auio.uio_resid != len &&*/ (error == EINTR || error == EWOULDBLOCK)) error = 0; } if (error) errno = error; else ret = buflen; if (to) m_freem(to); rtems_bsdnet_semaphore_release (); return (ret); } /* * receive data in an 'mbuf chain'. * The chain must be released once the * data has been extracted: * * rtems_bsdnet_semaphore_obtain(); * m_freem(chain); * rtems_bsdnet_semaphore_release(); */ ssize_t recv_mbuf_from(int s, struct mbuf **ppm, long len, struct sockaddr *fromaddr, int *fromlen) { int ret = -1; int error; struct uio auio; struct socket *so; struct mbuf *from = NULL; memset(&auio, 0, sizeof(auio)); *ppm = 0; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } /* auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_READ; auio.uio_offset = 0; */ auio.uio_resid = len; error = soreceive (so, &from, &auio, (struct mbuf **) ppm, (struct mbuf **)NULL, NULL); if (error) { if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK)) error = 0; } if (error) { errno = error; } else { ret = len - auio.uio_resid; if (fromaddr) { len = *fromlen; if ((len <= 0) || (from == NULL)) { len = 0; } else { if (len > from->m_len) len = from->m_len; memcpy (fromaddr, mtod(from, caddr_t), len); } *fromlen = len; } } if (from) m_freem (from); if (error && *ppm) { m_freem(*ppm); *ppm = 0; } rtems_bsdnet_semaphore_release (); return (ret); }