int setsockopt (int s, int level, int name, const void *val, int len) { struct socket *so; struct mbuf *m = NULL; int error; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } if (len > MLEN) { errno = EINVAL; rtems_bsdnet_semaphore_release (); return -1; } if (val) { error = sockargstombuf (&m, val, len, MT_SOOPTS); if (error) { errno = error; rtems_bsdnet_semaphore_release (); return -1; } } error = sosetopt(so, level, name, m); if (error) { errno = error; rtems_bsdnet_semaphore_release (); return -1; } rtems_bsdnet_semaphore_release (); return 0; }
int bind (int s, struct sockaddr *name, int namelen) { int error; int ret = -1; struct socket *so; struct mbuf *nam; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) { error = sockargstombuf (&nam, name, namelen, MT_SONAME); if (error == 0) { error = sobind (so, nam); if (error == 0) ret = 0; else errno = error; m_freem (nam); } else { errno = error; } } rtems_bsdnet_semaphore_release (); return ret; }
/* * 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); }
int connect (int s, struct sockaddr *name, int namelen) { int error; int ret = -1; struct socket *so; struct mbuf *nam; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { errno = EALREADY; rtems_bsdnet_semaphore_release (); return -1; } error = sockargstombuf (&nam, name, namelen, MT_SONAME); if (error) { errno = error; rtems_bsdnet_semaphore_release (); return -1; } error = soconnect (so, nam); if (error) goto bad; if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { m_freem(nam); errno = EINPROGRESS; rtems_bsdnet_semaphore_release (); return -1; } while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { error = soconnsleep (so); if (error) break; } if (error == 0) { error = so->so_error; so->so_error = 0; } bad: so->so_state &= ~SS_ISCONNECTING; m_freem (nam); if (error) errno = error; else ret = 0; rtems_bsdnet_semaphore_release (); return ret; }
int listen (int s, int backlog) { int error; int ret = -1; struct socket *so; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) { error = solisten (so, backlog); if (error == 0) ret = 0; else errno = error; } rtems_bsdnet_semaphore_release (); return ret; }
int shutdown (int s, int how) { struct socket *so; int error; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } error = soshutdown(so, how); rtems_bsdnet_semaphore_release (); if (error) { errno = error; return -1; } return 0; }
int getsockopt (int s, int level, int name, void *aval, int *avalsize) { struct socket *so; struct mbuf *m = NULL, *m0; char *val = aval; int i, op, valsize; int error; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } if (val) valsize = *avalsize; else valsize = 0; if (((error = sogetopt(so, level, name, &m)) == 0) && val && valsize && m) { op = 0; while (m && op < valsize) { i = valsize - op; if (i > m->m_len) i = m->m_len; memcpy (val, mtod(m, caddr_t), i); op += i; val += i; m0 = m; MFREE (m0, m); } *avalsize = op; } if (m != NULL) (void) m_free(m); if (error) { errno = error; rtems_bsdnet_semaphore_release (); return -1; } rtems_bsdnet_semaphore_release (); return 0; }
static int getpeersockname (int s, struct sockaddr *name, int *namelen, int pflag) { struct socket *so; struct mbuf *m; int len = *namelen; int error; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } m = m_getclr(M_WAIT, MT_SONAME); if (m == NULL) { errno = ENOBUFS; rtems_bsdnet_semaphore_release (); return -1; } if (pflag) error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m); else error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m); if (error) { m_freem(m); errno = error; rtems_bsdnet_semaphore_release (); return -1; } if (len > m->m_len) { len = m->m_len; *namelen = len; } memcpy (name, mtod(m, caddr_t), len); m_freem (m); rtems_bsdnet_semaphore_release (); return 0; }
/* * All `receive' operations end up calling this routine. */ ssize_t recvmsg (int s, struct msghdr *mp, int flags) { int ret = -1; int error; struct uio auio; struct iovec *iov; struct socket *so; struct mbuf *from = NULL, *control = NULL; int i; int len; 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 = 0; iov = mp->msg_iov; for (i = 0; i < mp->msg_iovlen; i++, iov++) { if ((auio.uio_resid += iov->iov_len) < 0) { errno = EINVAL; rtems_bsdnet_semaphore_release (); return -1; } } len = auio.uio_resid; mp->msg_flags = flags; error = soreceive (so, &from, &auio, (struct mbuf **)NULL, mp->msg_control ? &control : (struct mbuf **)NULL, &mp->msg_flags); if (error) { if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK)) error = 0; } if (error) { errno = error; } else { ret = len - auio.uio_resid; if (mp->msg_name) { len = mp->msg_namelen; if ((len <= 0) || (from == NULL)) { len = 0; } else { if (len > from->m_len) len = from->m_len; memcpy (mp->msg_name, mtod(from, caddr_t), len); } mp->msg_namelen = len; } if (mp->msg_control) { struct mbuf *m; void *ctlbuf; len = mp->msg_controllen; m = control; mp->msg_controllen = 0; ctlbuf = mp->msg_control; while (m && (len > 0)) { unsigned int tocopy; if (len >= m->m_len) tocopy = m->m_len; else { mp->msg_flags |= MSG_CTRUNC; tocopy = len; } memcpy(ctlbuf, mtod(m, caddr_t), tocopy); ctlbuf += tocopy; len -= tocopy; m = m->m_next; } mp->msg_controllen = ctlbuf - mp->msg_control; } } if (from) m_freem (from); if (control) m_freem (control); rtems_bsdnet_semaphore_release (); return (ret); }
/* * All `transmit' operations end up calling this routine. */ ssize_t sendmsg (int s, const struct msghdr *mp, int flags) { int ret = -1; int error; struct uio auio; struct iovec *iov; struct socket *so; struct mbuf *to; struct mbuf *control = NULL; int i; int len; 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_WRITE; auio.uio_offset = 0; auio.uio_resid = 0; iov = mp->msg_iov; for (i = 0; i < mp->msg_iovlen; i++, iov++) { if ((auio.uio_resid += iov->iov_len) < 0) { errno = EINVAL; rtems_bsdnet_semaphore_release (); return -1; } } if (mp->msg_name) { error = sockargstombuf (&to, mp->msg_name, mp->msg_namelen, MT_SONAME); if (error) { errno = error; rtems_bsdnet_semaphore_release (); return -1; } } else { to = NULL; } if (mp->msg_control) { if (mp->msg_controllen < sizeof (struct cmsghdr)) { errno = EINVAL; if (to) m_freem(to); rtems_bsdnet_semaphore_release (); return -1; } sockargstombuf (&control, mp->msg_control, mp->msg_controllen, MT_CONTROL); } else { control = NULL; } len = auio.uio_resid; error = sosend (so, to, &auio, (struct mbuf *)0, control, flags); if (error) { if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK)) error = 0; } if (error) errno = error; else ret = len - auio.uio_resid; if (to) m_freem(to); rtems_bsdnet_semaphore_release (); return (ret); }
int accept (int s, struct sockaddr *name, int *namelen) { int fd; struct socket *head, *so; struct mbuf *nam; rtems_bsdnet_semaphore_obtain (); if ((head = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } if ((head->so_options & SO_ACCEPTCONN) == 0) { errno = EINVAL; rtems_bsdnet_semaphore_release (); return -1; } if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) { errno = EWOULDBLOCK; rtems_bsdnet_semaphore_release (); return -1; } while (head->so_comp.tqh_first == NULL && head->so_error == 0) { if (head->so_state & SS_CANTRCVMORE) { head->so_error = ECONNABORTED; break; } head->so_error = soconnsleep (head); } if (head->so_error) { errno = head->so_error; head->so_error = 0; rtems_bsdnet_semaphore_release (); return -1; } so = head->so_comp.tqh_first; TAILQ_REMOVE(&head->so_comp, so, so_list); head->so_qlen--; fd = rtems_bsdnet_makeFdForSocket (so); if (fd < 0) { TAILQ_INSERT_HEAD(&head->so_comp, so, so_list); head->so_qlen++; soconnwakeup (head); rtems_bsdnet_semaphore_release (); return -1; } so->so_state &= ~SS_COMP; so->so_head = NULL; nam = m_get(M_WAIT, MT_SONAME); (void) soaccept(so, nam); if (name) { /* check length before it is destroyed */ if (*namelen > nam->m_len) *namelen = nam->m_len; memcpy (name, mtod(nam, caddr_t), *namelen); } m_freem(nam); rtems_bsdnet_semaphore_release (); return (fd); }