OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/rtos/rtems/c/src/libnetworking/kern
    from Rev 30 to Rev 173
    Reverse comparison

Rev 30 → Rev 173

/uipc_domain.c
0,0 → 1,228
/*
* Copyright (c) 1982, 1986, 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 acknowledgement:
* 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.
*
* @(#)uipc_domain.c 8.2 (Berkeley) 10/18/93
* $Id: uipc_domain.c,v 1.2 2001-09-27 12:01:51 chris Exp $
*/
 
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/systm.h>
 
/*
* System initialization
*
* Note: domain initialization wants to take place on a per domain basis
* as a result of traversing a linker set. Most likely, each domain
* want to call a registration function rather than being handled here
* in domaininit(). Probably this will look like:
*
* SYSINIT(unique, SI_SUB_PROTO_DOMAI, SI_ORDER_ANY, domain_add, xxx)
*
* Where 'xxx' is replaced by the address of a parameter struct to be
* passed to the doamin_add() function.
*/
 
#if !defined(__rtems__)
static int x_save_spl; /* used by kludge*/
static void kludge_splimp __P((void *));
static void kludge_splx __P((void *));
void domaininit __P((void *));
SYSINIT(splimp, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, kludge_splimp, &x_save_spl)
SYSINIT(domain, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, domaininit, NULL)
SYSINIT(splx, SI_SUB_PROTO_END, SI_ORDER_FIRST, kludge_splx, &x_save_spl)
#endif
 
static void pffasttimo __P((void *));
static void pfslowtimo __P((void *));
 
struct domain *domains;
 
#define ADDDOMAIN(x) { \
__CONCAT(x,domain.dom_next) = domains; \
domains = &__CONCAT(x,domain); \
}
 
extern struct linker_set domain_set;
 
/* ARGSUSED*/
void
domaininit(dummy)
void *dummy;
{
register struct domain *dp;
register struct protosw *pr;
 
/* - not in our sources
#ifdef ISDN
ADDDOMAIN(isdn);
#endif
*/
 
for (dp = domains; dp; dp = dp->dom_next) {
if (dp->dom_init)
(*dp->dom_init)();
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++){
#ifdef PRU_OLDSTYLE
/* See comments in uipc_socket2.c. */
if (pr->pr_usrreqs == 0 && pr->pr_ousrreq)
pr->pr_usrreqs = &pru_oldstyle;
#endif
if (pr->pr_init)
(*pr->pr_init)();
}
}
 
if (max_linkhdr < 16) /* XXX */
max_linkhdr = 16;
max_hdr = max_linkhdr + max_protohdr;
max_datalen = MHLEN - max_hdr;
timeout(pffasttimo, (void *)0, 1);
timeout(pfslowtimo, (void *)0, 1);
}
 
 
#if !defined(__rtems__)
/*
* The following two operations are kludge code. Most likely, they should
* be done as a "domainpreinit()" for the first function and then rolled
* in as the last act of "domaininit()" for the second.
*
* In point of fact, it is questionable why other initialization prior
* to this does not also take place at splimp by default.
*/
static void
kludge_splimp(udata)
void *udata;
{
int *savesplp = udata;
 
*savesplp = splimp();
}
 
static void
kludge_splx(udata)
void *udata;
{
int *savesplp = udata;
 
splx( *savesplp);
}
#endif /* !defined(__rtems__) */
 
struct protosw *
pffindtype(int family, int type)
{
register struct domain *dp;
register struct protosw *pr;
 
for (dp = domains; dp; dp = dp->dom_next)
if (dp->dom_family == family)
goto found;
return (0);
found:
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_type && pr->pr_type == type)
return (pr);
return (0);
}
 
struct protosw *
pffindproto(int family, int protocol, int type)
{
register struct domain *dp;
register struct protosw *pr;
struct protosw *maybe = 0;
 
if (family == 0)
return (0);
for (dp = domains; dp; dp = dp->dom_next)
if (dp->dom_family == family)
goto found;
return (0);
found:
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
return (pr);
 
if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
pr->pr_protocol == 0 && maybe == (struct protosw *)0)
maybe = pr;
}
return (maybe);
}
 
void
pfctlinput(cmd, sa)
int cmd;
struct sockaddr *sa;
{
register struct domain *dp;
register struct protosw *pr;
 
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_ctlinput)
(*pr->pr_ctlinput)(cmd, sa, (void *)0);
}
 
static void
pfslowtimo(arg)
void *arg;
{
register struct domain *dp;
register struct protosw *pr;
 
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_slowtimo)
(*pr->pr_slowtimo)();
timeout(pfslowtimo, (void *)0, hz/2);
}
 
static void
pffasttimo(arg)
void *arg;
{
register struct domain *dp;
register struct protosw *pr;
 
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_fasttimo)
(*pr->pr_fasttimo)();
timeout(pffasttimo, (void *)0, hz/5);
}
/Makefile.am
0,0 → 1,35
##
## $Id: Makefile.am,v 1.2 2001-09-27 12:01:50 chris Exp $
##
 
AUTOMAKE_OPTIONS = foreign 1.4
 
LIBNAME = lib.a
LIB = $(ARCH)/$(LIBNAME)
 
C_FILES = kern_subr.c uipc_domain.c uipc_mbuf.c uipc_socket.c uipc_socket2.c
C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
 
OBJS = $(C_O_FILES)
 
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../../../automake/lib.am
 
#
# Add local stuff here using +=
#
 
AM_CPPFLAGS += -D_COMPILING_BSD_KERNEL_ -DKERNEL -DINET -DNFS -DDIAGNOSTIC \
-DBOOTP_COMPAT
 
$(LIB): $(OBJS)
$(make-library)
 
all-local: $(ARCH) $(OBJS) $(LIB)
 
.PRECIOUS: $(LIB)
 
EXTRA_DIST = kern_subr.c uipc_domain.c uipc_mbuf.c uipc_socket.c \
uipc_socket2.c
 
include $(top_srcdir)/../../../automake/local.am
/uipc_socket.c
0,0 → 1,1143
/*
* Copyright (c) 1982, 1986, 1988, 1990, 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 acknowledgement:
* 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.
*
* @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94
* $Id: uipc_socket.c,v 1.2 2001-09-27 12:01:51 chris Exp $
*/
 
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/kernel.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/sysctl.h>
#include <limits.h>
 
static int somaxconn = SOMAXCONN;
SYSCTL_INT(_kern, KERN_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, 0, "");
 
/*
* Socket operation routines.
* These routines are called by the routines in
* sys_socket.c or from a system process, and
* implement the semantics of socket operations by
* switching out to the protocol specific routines.
*/
/*ARGSUSED*/
int
socreate(dom, aso, type, proto, p)
int dom;
struct socket **aso;
register int type;
int proto;
struct proc *p;
{
register struct protosw *prp;
register struct socket *so;
register int error;
 
if (proto)
prp = pffindproto(dom, proto, type);
else
prp = pffindtype(dom, type);
if (prp == 0 || prp->pr_usrreqs == 0)
return (EPROTONOSUPPORT);
if (prp->pr_type != type)
return (EPROTOTYPE);
MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
bzero((caddr_t)so, sizeof(*so));
TAILQ_INIT(&so->so_incomp);
TAILQ_INIT(&so->so_comp);
so->so_type = type;
so->so_state = SS_PRIV;
so->so_uid = 0;
so->so_proto = prp;
error = (*prp->pr_usrreqs->pru_attach)(so, proto);
if (error) {
so->so_state |= SS_NOFDREF;
sofree(so);
return (error);
}
*aso = so;
return (0);
}
 
int
sobind(so, nam)
struct socket *so;
struct mbuf *nam;
{
int s = splnet();
int error;
 
error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam);
splx(s);
return (error);
}
 
int
solisten(so, backlog)
register struct socket *so;
int backlog;
{
int s = splnet(), error;
 
error = (*so->so_proto->pr_usrreqs->pru_listen)(so);
if (error) {
splx(s);
return (error);
}
if (so->so_comp.tqh_first == NULL)
so->so_options |= SO_ACCEPTCONN;
if (backlog < 0 || backlog > somaxconn)
backlog = somaxconn;
so->so_qlimit = backlog;
splx(s);
return (0);
}
 
void
sofree(so)
register struct socket *so;
{
struct socket *head = so->so_head;
 
if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
return;
if (head != NULL) {
if (so->so_state & SS_INCOMP) {
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
} else if (so->so_state & SS_COMP) {
TAILQ_REMOVE(&head->so_comp, so, so_list);
} else {
panic("sofree: not queued");
}
head->so_qlen--;
so->so_state &= ~(SS_INCOMP|SS_COMP);
so->so_head = NULL;
}
sbrelease(&so->so_snd);
sorflush(so);
FREE(so, M_SOCKET);
}
 
/*
* Close a socket on last file table reference removal.
* Initiate disconnect if connected.
* Free socket when disconnect complete.
*/
int
soclose(so)
register struct socket *so;
{
int s = splnet(); /* conservative */
int error = 0;
 
if (so->so_options & SO_ACCEPTCONN) {
struct socket *sp, *sonext;
 
for (sp = so->so_incomp.tqh_first; sp != NULL; sp = sonext) {
sonext = sp->so_list.tqe_next;
(void) soabort(sp);
}
for (sp = so->so_comp.tqh_first; sp != NULL; sp = sonext) {
sonext = sp->so_list.tqe_next;
(void) soabort(sp);
}
}
if (so->so_pcb == 0)
goto discard;
if (so->so_state & SS_ISCONNECTED) {
if ((so->so_state & SS_ISDISCONNECTING) == 0) {
error = sodisconnect(so);
if (error)
goto drop;
}
if (so->so_options & SO_LINGER) {
if ((so->so_state & SS_ISDISCONNECTING) &&
(so->so_state & SS_NBIO))
goto drop;
while (so->so_state & SS_ISCONNECTED) {
soconnsleep (so);
}
}
}
drop:
if (so->so_pcb) {
int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so);
if (error == 0)
error = error2;
}
discard:
if (so->so_state & SS_NOFDREF)
panic("soclose: NOFDREF");
so->so_state |= SS_NOFDREF;
sofree(so);
splx(s);
return (error);
}
 
/*
* Must be called at splnet...
*/
int
soabort(so)
struct socket *so;
{
 
return (*so->so_proto->pr_usrreqs->pru_abort)(so);
}
 
int
soaccept(so, nam)
register struct socket *so;
struct mbuf *nam;
{
int s = splnet();
int error;
 
if ((so->so_state & SS_NOFDREF) == 0)
panic("soaccept: !NOFDREF");
so->so_state &= ~SS_NOFDREF;
error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam);
splx(s);
return (error);
}
 
int
soconnect(so, nam)
register struct socket *so;
struct mbuf *nam;
{
int s;
int error;
 
if (so->so_options & SO_ACCEPTCONN)
return (EOPNOTSUPP);
s = splnet();
/*
* If protocol is connection-based, can only connect once.
* Otherwise, if connected, try to disconnect first.
* This allows user to disconnect by connecting to, e.g.,
* a null address.
*/
if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
(error = sodisconnect(so))))
error = EISCONN;
else
error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam);
splx(s);
return (error);
}
 
int
soconnect2(so1, so2)
register struct socket *so1;
struct socket *so2;
{
int s = splnet();
int error;
 
error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2);
splx(s);
return (error);
}
 
int
sodisconnect(so)
register struct socket *so;
{
int s = splnet();
int error;
 
if ((so->so_state & SS_ISCONNECTED) == 0) {
error = ENOTCONN;
goto bad;
}
if (so->so_state & SS_ISDISCONNECTING) {
error = EALREADY;
goto bad;
}
error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so);
bad:
splx(s);
return (error);
}
 
#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
/*
* Send on a socket.
* If send must go all at once and message is larger than
* send buffering, then hard error.
* Lock against other senders.
* If must go all at once and not enough room now, then
* inform user that this would block and do nothing.
* Otherwise, if nonblocking, send as much as possible.
* The data to be sent is described by "uio" if nonzero,
* otherwise by the mbuf chain "top" (which must be null
* if uio is not). Data provided in mbuf chain must be small
* enough to send all at once.
*
* Returns nonzero on error, timeout or signal; callers
* must check for short counts if EINTR/ERESTART are returned.
* Data and control buffers are freed on return.
*/
int
sosend(so, addr, uio, top, control, flags)
register struct socket *so;
struct mbuf *addr;
struct uio *uio;
struct mbuf *top;
struct mbuf *control;
int flags;
{
struct mbuf **mp;
register struct mbuf *m;
register long space, len, resid;
int clen = 0, error, s, dontroute, mlen;
int atomic = sosendallatonce(so) || top;
 
if (uio)
resid = uio->uio_resid;
else
resid = top->m_pkthdr.len;
/*
* In theory resid should be unsigned.
* However, space must be signed, as it might be less than 0
* if we over-committed, and we must use a signed comparison
* of space and resid. On the other hand, a negative resid
* causes us to loop sending 0-length segments to the protocol.
*
* Also check to make sure that MSG_EOR isn't used on SOCK_STREAM
* type sockets since that's an error.
*/
if ((resid < 0) || (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) {
error = EINVAL;
goto out;
}
 
dontroute =
(flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
(so->so_proto->pr_flags & PR_ATOMIC);
if (control)
clen = control->m_len;
#define snderr(errno) { error = errno; splx(s); goto release; }
 
restart:
error = sblock(&so->so_snd, SBLOCKWAIT(flags));
if (error)
goto out;
do {
s = splnet();
if (so->so_state & SS_CANTSENDMORE)
snderr(EPIPE);
if (so->so_error) {
error = so->so_error;
so->so_error = 0;
splx(s);
goto release;
}
if ((so->so_state & SS_ISCONNECTED) == 0) {
/*
* `sendto' and `sendmsg' is allowed on a connection-
* based socket if it supports implied connect.
* Return ENOTCONN if not connected and no address is
* supplied.
*/
if ((so->so_proto->pr_flags & PR_CONNREQUIRED) &&
(so->so_proto->pr_flags & PR_IMPLOPCL) == 0) {
if ((so->so_state & SS_ISCONFIRMING) == 0 &&
!(resid == 0 && clen != 0))
snderr(ENOTCONN);
} else if (addr == 0)
snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ?
ENOTCONN : EDESTADDRREQ);
}
space = sbspace(&so->so_snd);
if (flags & MSG_OOB)
space += 1024;
if ((atomic && resid > so->so_snd.sb_hiwat) ||
clen > so->so_snd.sb_hiwat)
snderr(EMSGSIZE);
if (space < resid + clen && uio &&
(atomic || space < so->so_snd.sb_lowat || space < clen)) {
if (so->so_state & SS_NBIO)
snderr(EWOULDBLOCK);
sbunlock(&so->so_snd);
error = sbwait(&so->so_snd);
splx(s);
if (error)
goto out;
goto restart;
}
splx(s);
mp = &top;
space -= clen;
do {
if (uio == NULL) {
/*
* Data is prepackaged in "top".
*/
resid = 0;
if (flags & MSG_EOR)
top->m_flags |= M_EOR;
} else do {
if (top == 0) {
MGETHDR(m, M_WAIT, MT_DATA);
mlen = MHLEN;
m->m_pkthdr.len = 0;
m->m_pkthdr.rcvif = (struct ifnet *)0;
} else {
MGET(m, M_WAIT, MT_DATA);
mlen = MLEN;
}
if (resid >= MINCLSIZE) {
MCLGET(m, M_WAIT);
if ((m->m_flags & M_EXT) == 0)
goto nopages;
mlen = MCLBYTES;
len = min(min(mlen, resid), space);
} else {
nopages:
len = min(min(mlen, resid), space);
/*
* For datagram protocols, leave room
* for protocol headers in first mbuf.
*/
if (atomic && top == 0 && len < mlen)
MH_ALIGN(m, len);
}
space -= len;
error = uiomove(mtod(m, caddr_t), (int)len, uio);
resid = uio->uio_resid;
m->m_len = len;
*mp = m;
top->m_pkthdr.len += len;
if (error)
goto release;
mp = &m->m_next;
if (resid <= 0) {
if (flags & MSG_EOR)
top->m_flags |= M_EOR;
break;
}
} while (space > 0 && atomic);
if (dontroute)
so->so_options |= SO_DONTROUTE;
s = splnet(); /* XXX */
error = (*so->so_proto->pr_usrreqs->pru_send)(so,
(flags & MSG_OOB) ? PRUS_OOB :
/*
* If the user set MSG_EOF, the protocol
* understands this flag and nothing left to
* send then use PRU_SEND_EOF instead of PRU_SEND.
*/
((flags & MSG_EOF) &&
(so->so_proto->pr_flags & PR_IMPLOPCL) &&
(resid <= 0)) ?
PRUS_EOF : 0,
top, addr, control);
splx(s);
if (dontroute)
so->so_options &= ~SO_DONTROUTE;
clen = 0;
control = 0;
top = 0;
mp = &top;
if (error)
goto release;
} while (resid && space > 0);
} while (resid);
 
release:
sbunlock(&so->so_snd);
out:
if (top)
m_freem(top);
if (control)
m_freem(control);
return (error);
}
 
/*
* Implement receive operations on a socket.
* We depend on the way that records are added to the sockbuf
* by sbappend*. In particular, each record (mbufs linked through m_next)
* must begin with an address if the protocol so specifies,
* followed by an optional mbuf or mbufs containing ancillary data,
* and then zero or more mbufs of data.
* In order to avoid blocking network interrupts for the entire time here,
* we splx() while doing the actual copy to user space.
* Although the sockbuf is locked, new data may still be appended,
* and thus we must maintain consistency of the sockbuf during that time.
*
* The caller may receive the data as a single mbuf chain by supplying
* an mbuf **mp0 for use in returning the chain. The uio is then used
* only for the count in uio_resid.
*/
int
soreceive(so, paddr, uio, mp0, controlp, flagsp)
register struct socket *so;
struct mbuf **paddr;
struct uio *uio;
struct mbuf **mp0;
struct mbuf **controlp;
int *flagsp;
{
register struct mbuf *m, **mp;
register int flags, len, error, s, offset;
struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
int moff, type = 0;
int orig_resid = uio->uio_resid;
 
mp = mp0;
if (paddr)
*paddr = 0;
if (controlp)
*controlp = 0;
if (flagsp)
flags = *flagsp &~ MSG_EOR;
else
flags = 0;
if (flags & MSG_OOB) {
m = m_get(M_WAIT, MT_DATA);
error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK);
if (error)
goto bad;
do {
error = uiomove(mtod(m, caddr_t),
(int) min(uio->uio_resid, m->m_len), uio);
m = m_free(m);
} while (uio->uio_resid && error == 0 && m);
bad:
if (m)
m_freem(m);
return (error);
}
if (mp)
*mp = (struct mbuf *)0;
if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
(*pr->pr_usrreqs->pru_rcvd)(so, 0);
 
restart:
error = sblock(&so->so_rcv, SBLOCKWAIT(flags));
if (error)
return (error);
s = splnet();
 
m = so->so_rcv.sb_mb;
/*
* If we have less data than requested, block awaiting more
* (subject to any timeout) if:
* 1. the current count is less than the low water mark, or
* 2. MSG_WAITALL is set, and it is possible to do the entire
* receive operation at once if we block (resid <= hiwat).
* 3. MSG_DONTWAIT is not set
* If MSG_WAITALL is set but resid is larger than the receive buffer,
* we have to do the receive in sections, and thus risk returning
* a short count if a timeout or signal occurs after we start.
*/
if (m == 0 || (((flags & MSG_DONTWAIT) == 0 &&
so->so_rcv.sb_cc < uio->uio_resid) &&
(so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) {
#ifdef DIAGNOSTIC
if (m == 0 && so->so_rcv.sb_cc)
panic("receive 1");
#endif
if (so->so_error) {
if (m)
goto dontblock;
error = so->so_error;
if ((flags & MSG_PEEK) == 0)
so->so_error = 0;
goto release;
}
if (so->so_state & SS_CANTRCVMORE) {
if (m)
goto dontblock;
else
goto release;
}
for (; m; m = m->m_next)
if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
m = so->so_rcv.sb_mb;
goto dontblock;
}
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
error = ENOTCONN;
goto release;
}
if (uio->uio_resid == 0)
goto release;
if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
error = EWOULDBLOCK;
goto release;
}
sbunlock(&so->so_rcv);
error = sbwait(&so->so_rcv);
splx(s);
if (error)
return (error);
goto restart;
}
dontblock:
nextrecord = m->m_nextpkt;
if (pr->pr_flags & PR_ADDR) {
#ifdef DIAGNOSTIC
if (m->m_type != MT_SONAME)
panic("receive 1a");
#endif
orig_resid = 0;
if (flags & MSG_PEEK) {
if (paddr)
*paddr = m_copy(m, 0, m->m_len);
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
if (paddr) {
*paddr = m;
so->so_rcv.sb_mb = m->m_next;
m->m_next = 0;
m = so->so_rcv.sb_mb;
} else {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
}
}
while (m && m->m_type == MT_CONTROL && error == 0) {
if (flags & MSG_PEEK) {
if (controlp)
*controlp = m_copy(m, 0, m->m_len);
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
if (controlp) {
if (pr->pr_domain->dom_externalize &&
mtod(m, struct cmsghdr *)->cmsg_type ==
SCM_RIGHTS)
error = (*pr->pr_domain->dom_externalize)(m);
*controlp = m;
so->so_rcv.sb_mb = m->m_next;
m->m_next = 0;
m = so->so_rcv.sb_mb;
} else {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
}
if (controlp) {
orig_resid = 0;
controlp = &(*controlp)->m_next;
}
}
if (m) {
if ((flags & MSG_PEEK) == 0)
m->m_nextpkt = nextrecord;
type = m->m_type;
if (type == MT_OOBDATA)
flags |= MSG_OOB;
}
moff = 0;
offset = 0;
while (m && uio->uio_resid > 0 && error == 0) {
if (m->m_type == MT_OOBDATA) {
if (type != MT_OOBDATA)
break;
} else if (type == MT_OOBDATA)
break;
#ifdef DIAGNOSTIC
else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
panic("receive 3");
#endif
so->so_state &= ~SS_RCVATMARK;
len = uio->uio_resid;
if (so->so_oobmark && len > so->so_oobmark - offset)
len = so->so_oobmark - offset;
if (len > m->m_len - moff)
len = m->m_len - moff;
/*
* If mp is set, just pass back the mbufs.
* Otherwise copy them out via the uio, then free.
* Sockbuf must be consistent here (points to current mbuf,
* it points to next record) when we drop priority;
* we must note any additions to the sockbuf when we
* block interrupts again.
*/
if (mp == 0) {
splx(s);
error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
s = splnet();
if (error)
goto release;
} else
uio->uio_resid -= len;
if (len == m->m_len - moff) {
if (m->m_flags & M_EOR)
flags |= MSG_EOR;
if (flags & MSG_PEEK) {
m = m->m_next;
moff = 0;
} else {
nextrecord = m->m_nextpkt;
sbfree(&so->so_rcv, m);
if (mp) {
*mp = m;
mp = &m->m_next;
so->so_rcv.sb_mb = m = m->m_next;
*mp = (struct mbuf *)0;
} else {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
if (m)
m->m_nextpkt = nextrecord;
}
} else {
if (flags & MSG_PEEK)
moff += len;
else {
if (mp)
*mp = m_copym(m, 0, len, M_WAIT);
m->m_data += len;
m->m_len -= len;
so->so_rcv.sb_cc -= len;
}
}
if (so->so_oobmark) {
if ((flags & MSG_PEEK) == 0) {
so->so_oobmark -= len;
if (so->so_oobmark == 0) {
so->so_state |= SS_RCVATMARK;
break;
}
} else {
offset += len;
if (offset == so->so_oobmark)
break;
}
}
if (flags & MSG_EOR)
break;
/*
* If the MSG_WAITALL flag is set (for non-atomic socket),
* we must not quit until "uio->uio_resid == 0" or an error
* termination. If a signal/timeout occurs, return
* with a short count but without error.
* Keep sockbuf locked against other readers.
*/
while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
!sosendallatonce(so) && !nextrecord) {
if (so->so_error || so->so_state & SS_CANTRCVMORE)
break;
error = sbwait(&so->so_rcv);
if (error) {
sbunlock(&so->so_rcv);
splx(s);
return (0);
}
m = so->so_rcv.sb_mb;
if (m)
nextrecord = m->m_nextpkt;
}
}
 
if (m && pr->pr_flags & PR_ATOMIC) {
flags |= MSG_TRUNC;
if ((flags & MSG_PEEK) == 0)
(void) sbdroprecord(&so->so_rcv);
}
if ((flags & MSG_PEEK) == 0) {
if (m == 0)
so->so_rcv.sb_mb = nextrecord;
if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
(*pr->pr_usrreqs->pru_rcvd)(so, flags);
}
if (orig_resid == uio->uio_resid && orig_resid &&
(flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
sbunlock(&so->so_rcv);
splx(s);
goto restart;
}
 
if (flagsp)
*flagsp |= flags;
release:
sbunlock(&so->so_rcv);
splx(s);
return (error);
}
 
int
soshutdown(so, how)
register struct socket *so;
register int how;
{
register struct protosw *pr = so->so_proto;
 
how++;
if (how & FREAD)
sorflush(so);
if (how & FWRITE)
return ((*pr->pr_usrreqs->pru_shutdown)(so));
return (0);
}
 
void
sorflush(so)
register struct socket *so;
{
register struct sockbuf *sb = &so->so_rcv;
register struct protosw *pr = so->so_proto;
register int s;
struct sockbuf asb;
 
sb->sb_flags |= SB_NOINTR;
(void) sblock(sb, M_WAITOK);
s = splimp();
socantrcvmore(so);
sbunlock(sb);
asb = *sb;
bzero((caddr_t)sb, sizeof (*sb));
splx(s);
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
(*pr->pr_domain->dom_dispose)(asb.sb_mb);
sbrelease(&asb);
}
 
int
sosetopt(so, level, optname, m0)
register struct socket *so;
int level, optname;
struct mbuf *m0;
{
int error = 0;
register struct mbuf *m = m0;
 
if (level != SOL_SOCKET) {
if (so->so_proto && so->so_proto->pr_ctloutput)
return ((*so->so_proto->pr_ctloutput)
(PRCO_SETOPT, so, level, optname, &m0));
error = ENOPROTOOPT;
} else {
switch (optname) {
 
case SO_LINGER:
if (m == NULL || m->m_len != sizeof (struct linger)) {
error = EINVAL;
goto bad;
}
so->so_linger = mtod(m, struct linger *)->l_linger;
/* fall thru... */
 
case SO_DEBUG:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_USELOOPBACK:
case SO_BROADCAST:
case SO_REUSEADDR:
case SO_REUSEPORT:
case SO_OOBINLINE:
case SO_TIMESTAMP:
if (m == NULL || m->m_len < sizeof (int)) {
error = EINVAL;
goto bad;
}
if (*mtod(m, int *))
so->so_options |= optname;
else
so->so_options &= ~optname;
break;
 
case SO_SNDBUF:
case SO_RCVBUF:
case SO_SNDLOWAT:
case SO_RCVLOWAT:
{
int optval;
 
if (m == NULL || m->m_len < sizeof (int)) {
error = EINVAL;
goto bad;
}
 
/*
* Values < 1 make no sense for any of these
* options, so disallow them.
*/
optval = *mtod(m, int *);
if (optval < 1) {
error = EINVAL;
goto bad;
}
 
switch (optname) {
 
case SO_SNDBUF:
case SO_RCVBUF:
if (sbreserve(optname == SO_SNDBUF ?
&so->so_snd : &so->so_rcv,
(u_long) optval) == 0) {
error = ENOBUFS;
goto bad;
}
break;
 
/*
* Make sure the low-water is never greater than
* the high-water.
*/
case SO_SNDLOWAT:
so->so_snd.sb_lowat =
(optval > so->so_snd.sb_hiwat) ?
so->so_snd.sb_hiwat : optval;
break;
case SO_RCVLOWAT:
so->so_rcv.sb_lowat =
(optval > so->so_rcv.sb_hiwat) ?
so->so_rcv.sb_hiwat : optval;
break;
}
break;
}
 
case SO_SNDTIMEO:
case SO_RCVTIMEO:
{
struct timeval *tv;
unsigned long val;
 
if (m == NULL || m->m_len < sizeof (*tv)) {
error = EINVAL;
goto bad;
}
tv = mtod(m, struct timeval *);
if (tv->tv_sec >= (ULONG_MAX - hz) / hz) {
error = EDOM;
goto bad;
}
val = tv->tv_sec * hz + tv->tv_usec / tick;
 
switch (optname) {
 
case SO_SNDTIMEO:
so->so_snd.sb_timeo = val;
break;
case SO_RCVTIMEO:
so->so_rcv.sb_timeo = val;
break;
}
break;
}
 
case SO_PRIVSTATE:
/* we don't care what the parameter is... */
so->so_state &= ~SS_PRIV;
break;
 
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
/* RTEMS addition. */
struct sockwakeup *sw;
struct sockbuf *sb;
 
if (m == NULL
|| m->m_len != sizeof (struct sockwakeup)) {
error = EINVAL;
goto bad;
}
sw = mtod(m, struct sockwakeup *);
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
sb->sb_wakeup = sw->sw_pfn;
sb->sb_wakeuparg = sw->sw_arg;
if (sw->sw_pfn)
sb->sb_flags |= SB_ASYNC;
else
sb->sb_flags &=~ SB_ASYNC;
break;
}
 
default:
error = ENOPROTOOPT;
break;
}
if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
(void) ((*so->so_proto->pr_ctloutput)
(PRCO_SETOPT, so, level, optname, &m0));
m = NULL; /* freed by protocol */
}
}
bad:
if (m)
(void) m_free(m);
return (error);
}
 
int
sogetopt(so, level, optname, mp)
register struct socket *so;
int level, optname;
struct mbuf **mp;
{
register struct mbuf *m;
 
if (level != SOL_SOCKET) {
if (so->so_proto && so->so_proto->pr_ctloutput) {
return ((*so->so_proto->pr_ctloutput)
(PRCO_GETOPT, so, level, optname, mp));
} else
return (ENOPROTOOPT);
} else {
m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = sizeof (int);
 
switch (optname) {
 
case SO_LINGER:
m->m_len = sizeof (struct linger);
mtod(m, struct linger *)->l_onoff =
so->so_options & SO_LINGER;
mtod(m, struct linger *)->l_linger = so->so_linger;
break;
 
case SO_USELOOPBACK:
case SO_DONTROUTE:
case SO_DEBUG:
case SO_KEEPALIVE:
case SO_REUSEADDR:
case SO_REUSEPORT:
case SO_BROADCAST:
case SO_OOBINLINE:
case SO_TIMESTAMP:
*mtod(m, int *) = so->so_options & optname;
break;
 
case SO_PRIVSTATE:
*mtod(m, int *) = so->so_state & SS_PRIV;
break;
 
case SO_TYPE:
*mtod(m, int *) = so->so_type;
break;
 
case SO_ERROR:
*mtod(m, int *) = so->so_error;
so->so_error = 0;
break;
 
case SO_SNDBUF:
*mtod(m, int *) = so->so_snd.sb_hiwat;
break;
 
case SO_RCVBUF:
*mtod(m, int *) = so->so_rcv.sb_hiwat;
break;
 
case SO_SNDLOWAT:
*mtod(m, int *) = so->so_snd.sb_lowat;
break;
 
case SO_RCVLOWAT:
*mtod(m, int *) = so->so_rcv.sb_lowat;
break;
 
case SO_SNDTIMEO:
case SO_RCVTIMEO:
{
unsigned long val = (optname == SO_SNDTIMEO ?
so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
 
m->m_len = sizeof(struct timeval);
mtod(m, struct timeval *)->tv_sec = val / hz;
mtod(m, struct timeval *)->tv_usec =
(val % hz) * tick;
break;
}
 
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
struct sockbuf *sb;
struct sockwakeup *sw;
 
/* RTEMS additions. */
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
m->m_len = sizeof (struct sockwakeup);
sw = mtod(m, struct sockwakeup *);
sw->sw_pfn = sb->sb_wakeup;
sw->sw_arg = sb->sb_wakeuparg;
break;
}
 
default:
(void)m_free(m);
return (ENOPROTOOPT);
}
*mp = m;
return (0);
}
}
 
void
sohasoutofband(so)
register struct socket *so;
{
#if 0 /* FIXME: For now we just ignore out of band data */
struct proc *p;
 
if (so->so_pgid < 0)
gsignal(-so->so_pgid, SIGURG);
else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
psignal(p, SIGURG);
selwakeup(&so->so_rcv.sb_sel);
#endif
}
/uipc_mbuf.c
0,0 → 1,748
/*
* Copyright (c) 1982, 1986, 1988, 1991, 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 acknowledgement:
* 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.
*
* @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
* $Id: uipc_mbuf.c,v 1.2 2001-09-27 12:01:51 chris Exp $
*/
 
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#define MBTYPES
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/domain.h>
#include <sys/protosw.h>
 
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_kern.h>
#include <vm/vm_extern.h>
 
static void mbinit __P((void *)) __attribute__ ((unused));
SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL)
 
struct mbuf *mbutl;
char *mclrefcnt;
struct mbstat mbstat;
struct mbuf *mmbfree;
union mcluster *mclfree;
int max_linkhdr;
int max_protohdr;
int max_hdr;
int max_datalen;
 
/* "number of clusters of pages" */
#define NCL_INIT 1
 
#define NMB_INIT 16
 
/*
* When MGET failes, ask protocols to free space when short of memory,
* then re-attempt to allocate an mbuf.
*/
struct mbuf *
m_retry(i, t)
int i, t;
{
register struct mbuf *m;
 
m_reclaim();
#define m_retry(i, t) (struct mbuf *)0
MGET(m, i, t);
#undef m_retry
if (m != NULL)
mbstat.m_wait++;
else
mbstat.m_drops++;
return (m);
}
 
/*
* As above; retry an MGETHDR.
*/
struct mbuf *
m_retryhdr(i, t)
int i, t;
{
register struct mbuf *m;
 
m_reclaim();
#define m_retryhdr(i, t) (struct mbuf *)0
MGETHDR(m, i, t);
#undef m_retryhdr
if (m != NULL)
mbstat.m_wait++;
else
mbstat.m_drops++;
return (m);
}
 
void
m_reclaim(void)
{
register struct domain *dp;
register struct protosw *pr;
int s = splimp();
 
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_drain)
(*pr->pr_drain)();
splx(s);
mbstat.m_drain++;
}
 
/*
* Space allocation routines.
* These are also available as macros
* for critical paths.
*/
struct mbuf *
m_get(nowait, type)
int nowait, type;
{
register struct mbuf *m;
 
MGET(m, nowait, type);
return (m);
}
 
struct mbuf *
m_gethdr(nowait, type)
int nowait, type;
{
register struct mbuf *m;
 
MGETHDR(m, nowait, type);
return (m);
}
 
struct mbuf *
m_getclr(nowait, type)
int nowait, type;
{
register struct mbuf *m;
 
MGET(m, nowait, type);
if (m == 0)
return (0);
bzero(mtod(m, caddr_t), MLEN);
return (m);
}
 
struct mbuf *
m_free(m)
struct mbuf *m;
{
register struct mbuf *n;
 
MFREE(m, n);
return (n);
}
 
void
m_freem(m)
register struct mbuf *m;
{
register struct mbuf *n;
 
if (m == NULL)
return;
do {
MFREE(m, n);
m = n;
} while (m);
}
 
/*
* Mbuffer utility routines.
*/
 
/*
* Lesser-used path for M_PREPEND:
* allocate new mbuf to prepend to chain,
* copy junk along.
*/
struct mbuf *
m_prepend(m, len, how)
register struct mbuf *m;
int len, how;
{
struct mbuf *mn;
 
MGET(mn, how, m->m_type);
if (mn == (struct mbuf *)NULL) {
m_freem(m);
return ((struct mbuf *)NULL);
}
if (m->m_flags & M_PKTHDR) {
M_COPY_PKTHDR(mn, m);
m->m_flags &= ~M_PKTHDR;
}
mn->m_next = m;
m = mn;
if (len < MHLEN)
MH_ALIGN(m, len);
m->m_len = len;
return (m);
}
 
/*
* Make a copy of an mbuf chain starting "off0" bytes from the beginning,
* continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
* The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
*/
static int MCFail;
 
struct mbuf *
m_copym(m, off0, len, wait)
register struct mbuf *m;
int off0, wait;
register int len;
{
register struct mbuf *n, **np;
register int off = off0;
struct mbuf *top;
int copyhdr = 0;
 
if (off < 0 || len < 0)
panic("m_copym");
if (off == 0 && m->m_flags & M_PKTHDR)
copyhdr = 1;
while (off > 0) {
if (m == 0)
panic("m_copym");
if (off < m->m_len)
break;
off -= m->m_len;
m = m->m_next;
}
np = &top;
top = 0;
while (len > 0) {
if (m == 0) {
if (len != M_COPYALL)
panic("m_copym");
break;
}
MGET(n, wait, m->m_type);
*np = n;
if (n == 0)
goto nospace;
if (copyhdr) {
M_COPY_PKTHDR(n, m);
if (len == M_COPYALL)
n->m_pkthdr.len -= off0;
else
n->m_pkthdr.len = len;
copyhdr = 0;
}
n->m_len = min(len, m->m_len - off);
if (m->m_flags & M_EXT) {
n->m_data = m->m_data + off;
if(!m->m_ext.ext_ref)
mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
else
(*(m->m_ext.ext_ref))(m->m_ext.ext_buf,
m->m_ext.ext_size);
n->m_ext = m->m_ext;
n->m_flags |= M_EXT;
} else
bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
(unsigned)n->m_len);
if (len != M_COPYALL)
len -= n->m_len;
off = 0;
m = m->m_next;
np = &n->m_next;
}
if (top == 0)
MCFail++;
return (top);
nospace:
m_freem(top);
MCFail++;
return (0);
}
 
/*
* Copy an entire packet, including header (which must be present).
* An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'.
*/
struct mbuf *
m_copypacket(m, how)
struct mbuf *m;
int how;
{
struct mbuf *top, *n, *o;
 
MGET(n, how, m->m_type);
top = n;
if (!n)
goto nospace;
 
M_COPY_PKTHDR(n, m);
n->m_len = m->m_len;
if (m->m_flags & M_EXT) {
n->m_data = m->m_data;
mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
n->m_ext = m->m_ext;
n->m_flags |= M_EXT;
} else {
bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
}
 
m = m->m_next;
while (m) {
MGET(o, how, m->m_type);
if (!o)
goto nospace;
 
n->m_next = o;
n = n->m_next;
 
n->m_len = m->m_len;
if (m->m_flags & M_EXT) {
n->m_data = m->m_data;
mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
n->m_ext = m->m_ext;
n->m_flags |= M_EXT;
} else {
bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
}
 
m = m->m_next;
}
return top;
nospace:
m_freem(top);
MCFail++;
return 0;
}
 
/*
* Copy data from an mbuf chain starting "off" bytes from the beginning,
* continuing for "len" bytes, into the indicated buffer.
*/
void
m_copydata(m, off, len, cp)
register struct mbuf *m;
register int off;
register int len;
caddr_t cp;
{
register unsigned count;
 
if (off < 0 || len < 0)
panic("m_copydata");
while (off > 0) {
if (m == 0)
panic("m_copydata");
if (off < m->m_len)
break;
off -= m->m_len;
m = m->m_next;
}
while (len > 0) {
if (m == 0)
panic("m_copydata");
count = min(m->m_len - off, len);
bcopy(mtod(m, caddr_t) + off, cp, count);
len -= count;
cp += count;
off = 0;
m = m->m_next;
}
}
 
/*
* Concatenate mbuf chain n to m.
* Both chains must be of the same type (e.g. MT_DATA).
* Any m_pkthdr is not updated.
*/
void
m_cat(m, n)
register struct mbuf *m, *n;
{
while (m->m_next)
m = m->m_next;
while (n) {
if (m->m_flags & M_EXT ||
m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
/* just join the two chains */
m->m_next = n;
return;
}
/* splat the data from one into the other */
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
(u_int)n->m_len);
m->m_len += n->m_len;
n = m_free(n);
}
}
 
void
m_adj(mp, req_len)
struct mbuf *mp;
int req_len;
{
register int len = req_len;
register struct mbuf *m;
register int count;
 
if ((m = mp) == NULL)
return;
if (len >= 0) {
/*
* Trim from head.
*/
while (m != NULL && len > 0) {
if (m->m_len <= len) {
len -= m->m_len;
m->m_len = 0;
m = m->m_next;
} else {
m->m_len -= len;
m->m_data += len;
len = 0;
}
}
m = mp;
if (mp->m_flags & M_PKTHDR)
m->m_pkthdr.len -= (req_len - len);
} else {
/*
* Trim from tail. Scan the mbuf chain,
* calculating its length and finding the last mbuf.
* If the adjustment only affects this mbuf, then just
* adjust and return. Otherwise, rescan and truncate
* after the remaining size.
*/
len = -len;
count = 0;
for (;;) {
count += m->m_len;
if (m->m_next == (struct mbuf *)0)
break;
m = m->m_next;
}
if (m->m_len >= len) {
m->m_len -= len;
if (mp->m_flags & M_PKTHDR)
mp->m_pkthdr.len -= len;
return;
}
count -= len;
if (count < 0)
count = 0;
/*
* Correct length for chain is "count".
* Find the mbuf with last data, adjust its length,
* and toss data from remaining mbufs on chain.
*/
m = mp;
if (m->m_flags & M_PKTHDR)
m->m_pkthdr.len = count;
for (; m; m = m->m_next) {
if (m->m_len >= count) {
m->m_len = count;
break;
}
count -= m->m_len;
}
while (m->m_next)
(m = m->m_next) ->m_len = 0;
}
}
 
/*
* Rearange an mbuf chain so that len bytes are contiguous
* and in the data area of an mbuf (so that mtod and dtom
* will work for a structure of size len). Returns the resulting
* mbuf chain on success, frees it and returns null on failure.
* If there is room, it will add up to max_protohdr-len extra bytes to the
* contiguous region in an attempt to avoid being called next time.
*/
static int MPFail;
 
struct mbuf *
m_pullup(n, len)
register struct mbuf *n;
int len;
{
register struct mbuf *m;
register int count;
int space;
 
/*
* If first mbuf has no cluster, and has room for len bytes
* without shifting current data, pullup into it,
* otherwise allocate a new mbuf to prepend to the chain.
*/
if ((n->m_flags & M_EXT) == 0 &&
n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
if (n->m_len >= len)
return (n);
m = n;
n = n->m_next;
len -= m->m_len;
} else {
if (len > MHLEN)
goto bad;
MGET(m, M_DONTWAIT, n->m_type);
if (m == 0)
goto bad;
m->m_len = 0;
if (n->m_flags & M_PKTHDR) {
M_COPY_PKTHDR(m, n);
n->m_flags &= ~M_PKTHDR;
}
}
space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
do {
count = min(min(max(len, max_protohdr), space), n->m_len);
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
(unsigned)count);
len -= count;
m->m_len += count;
n->m_len -= count;
space -= count;
if (n->m_len)
n->m_data += count;
else
n = m_free(n);
} while (len > 0 && n);
if (len > 0) {
(void) m_free(m);
goto bad;
}
m->m_next = n;
return (m);
bad:
m_freem(n);
MPFail++;
return (0);
}
 
/*
* Partition an mbuf chain in two pieces, returning the tail --
* all but the first len0 bytes. In case of failure, it returns NULL and
* attempts to restore the chain to its original state.
*/
struct mbuf *
m_split(m0, len0, wait)
register struct mbuf *m0;
int len0, wait;
{
register struct mbuf *m, *n;
unsigned len = len0, remain;
 
for (m = m0; m && len > m->m_len; m = m->m_next)
len -= m->m_len;
if (m == 0)
return (0);
remain = m->m_len - len;
if (m0->m_flags & M_PKTHDR) {
MGETHDR(n, wait, m0->m_type);
if (n == 0)
return (0);
n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
n->m_pkthdr.len = m0->m_pkthdr.len - len0;
m0->m_pkthdr.len = len0;
if (m->m_flags & M_EXT)
goto extpacket;
if (remain > MHLEN) {
/* m can't be the lead packet */
MH_ALIGN(n, 0);
n->m_next = m_split(m, len, wait);
if (n->m_next == 0) {
(void) m_free(n);
return (0);
} else
return (n);
} else
MH_ALIGN(n, remain);
} else if (remain == 0) {
n = m->m_next;
m->m_next = 0;
return (n);
} else {
MGET(n, wait, m->m_type);
if (n == 0)
return (0);
M_ALIGN(n, remain);
}
extpacket:
if (m->m_flags & M_EXT) {
n->m_flags |= M_EXT;
n->m_ext = m->m_ext;
if(!m->m_ext.ext_ref)
mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
else
(*(m->m_ext.ext_ref))(m->m_ext.ext_buf,
m->m_ext.ext_size);
m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
n->m_data = m->m_data + len;
} else {
bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
}
n->m_len = remain;
m->m_len = len;
n->m_next = m->m_next;
m->m_next = 0;
return (n);
}
/*
* Routine to copy from device local memory into mbufs.
*/
struct mbuf *
m_devget(buf, totlen, off0, ifp, copy)
char *buf;
int totlen, off0;
struct ifnet *ifp;
void (*copy) __P((char *from, caddr_t to, u_int len));
{
register struct mbuf *m;
struct mbuf *top = 0, **mp = &top;
register int off = off0, len;
register char *cp;
char *epkt;
 
cp = buf;
epkt = cp + totlen;
if (off) {
cp += off + 2 * sizeof(u_short);
totlen -= 2 * sizeof(u_short);
}
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0)
return (0);
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = totlen;
m->m_len = MHLEN;
 
while (totlen > 0) {
if (top) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0) {
m_freem(top);
return (0);
}
m->m_len = MLEN;
}
len = min(totlen, epkt - cp);
if (len >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT)
m->m_len = len = min(len, MCLBYTES);
else
len = m->m_len;
} else {
/*
* Place initial small packet/header at end of mbuf.
*/
if (len < m->m_len) {
if (top == 0 && len + max_linkhdr <= m->m_len)
m->m_data += max_linkhdr;
m->m_len = len;
} else
len = m->m_len;
}
if (copy)
copy(cp, mtod(m, caddr_t), (unsigned)len);
else
bcopy(cp, mtod(m, caddr_t), (unsigned)len);
cp += len;
*mp = m;
mp = &m->m_next;
totlen -= len;
if (cp == epkt)
cp = buf;
}
return (top);
}
 
/*
* Copy data from a buffer back into the indicated mbuf chain,
* starting "off" bytes from the beginning, extending the mbuf
* chain if necessary.
*/
void
m_copyback(m0, off, len, cp)
struct mbuf *m0;
register int off;
register int len;
caddr_t cp;
{
register int mlen;
register struct mbuf *m = m0, *n;
int totlen = 0;
 
if (m0 == 0)
return;
while (off > (mlen = m->m_len)) {
off -= mlen;
totlen += mlen;
if (m->m_next == 0) {
n = m_getclr(M_DONTWAIT, m->m_type);
if (n == 0)
goto out;
n->m_len = min(MLEN, len + off);
m->m_next = n;
}
m = m->m_next;
}
while (len > 0) {
mlen = min (m->m_len - off, len);
bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
cp += mlen;
len -= mlen;
mlen += off;
off = 0;
totlen += mlen;
if (len == 0)
break;
if (m->m_next == 0) {
n = m_get(M_DONTWAIT, m->m_type);
if (n == 0)
break;
n->m_len = min(MLEN, len);
m->m_next = n;
}
m = m->m_next;
}
out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
m->m_pkthdr.len = totlen;
}
/kern_subr.c
0,0 → 1,206
/*
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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 acknowledgement:
* 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.
*
* @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
* $Id: kern_subr.c,v 1.2 2001-09-27 12:01:51 chris Exp $
*/
 
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/queue.h>
 
int
uiomove(cp, n, uio)
register caddr_t cp;
register int n;
register struct uio *uio;
{
register struct iovec *iov;
u_int cnt;
int error;
 
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
panic("uiomove: mode");
#endif
while (n > 0 && uio->uio_resid) {
iov = uio->uio_iov;
cnt = iov->iov_len;
if (cnt == 0) {
uio->uio_iov++;
uio->uio_iovcnt--;
continue;
}
if (cnt > n)
cnt = n;
 
switch (uio->uio_segflg) {
 
case UIO_USERSPACE:
case UIO_USERISPACE:
if (uio->uio_rw == UIO_READ)
error = copyout(cp, iov->iov_base, cnt);
else
error = copyin(iov->iov_base, cp, cnt);
if (error)
return (error);
break;
 
case UIO_SYSSPACE:
if (uio->uio_rw == UIO_READ)
bcopy((caddr_t)cp, iov->iov_base, cnt);
else
bcopy(iov->iov_base, (caddr_t)cp, cnt);
break;
case UIO_NOCOPY:
break;
}
iov->iov_base += cnt;
iov->iov_len -= cnt;
uio->uio_resid -= cnt;
uio->uio_offset += cnt;
cp += cnt;
n -= cnt;
}
return (0);
}
 
#ifdef vax /* unused except by ct.c, other oddities XXX */
/*
* Get next character written in by user from uio.
*/
int
uwritec(uio)
struct uio *uio;
{
register struct iovec *iov;
register int c;
 
if (uio->uio_resid <= 0)
return (-1);
again:
if (uio->uio_iovcnt <= 0)
panic("uwritec");
iov = uio->uio_iov;
if (iov->iov_len == 0) {
uio->uio_iov++;
if (--uio->uio_iovcnt == 0)
return (-1);
goto again;
}
switch (uio->uio_segflg) {
 
case UIO_USERSPACE:
c = fubyte(iov->iov_base);
break;
 
case UIO_SYSSPACE:
c = *(u_char *) iov->iov_base;
break;
 
case UIO_USERISPACE:
c = fuibyte(iov->iov_base);
break;
}
if (c < 0)
return (-1);
iov->iov_base++;
iov->iov_len--;
uio->uio_resid--;
uio->uio_offset++;
return (c);
}
#endif /* vax */
 
/*
* General routine to allocate a hash table.
*/
void *
hashinit(elements, type, hashmask)
int elements, type;
u_long *hashmask;
{
long hashsize;
LIST_HEAD(generic, generic) *hashtbl;
int i;
 
if (elements <= 0)
panic("hashinit: bad elements");
for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
continue;
hashsize >>= 1;
hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
for (i = 0; i < hashsize; i++)
LIST_INIT(&hashtbl[i]);
*hashmask = hashsize - 1;
return (hashtbl);
}
 
#define NPRIMES 27
static int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531, 2039,
2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143, 6653,
7159, 7673, 8191, 12281, 16381, 24571, 32749 };
 
/*
* General routine to allocate a prime number sized hash table.
*/
void *
phashinit(elements, type, nentries)
int elements, type;
u_long *nentries;
{
long hashsize;
LIST_HEAD(generic, generic) *hashtbl;
int i;
 
if (elements <= 0)
panic("phashinit: bad elements");
for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
i++;
if (i == NPRIMES)
break;
hashsize = primes[i];
}
hashsize = primes[i - 1];
hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
for (i = 0; i < hashsize; i++)
LIST_INIT(&hashtbl[i]);
*nentries = hashsize;
return (hashtbl);
}
/uipc_socket2.c
0,0 → 1,965
/*
* This file has undergone several changes to reflect the
* differences between the RTEMS and FreeBSD kernels.
*/
 
/*
* Copyright (c) 1982, 1986, 1988, 1990, 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 acknowledgement:
* 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.
*
* @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93
* $Id: uipc_socket2.c,v 1.2 2001-09-27 12:01:51 chris Exp $
*/
 
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/signalvar.h>
#include <sys/sysctl.h>
 
/*
* Primitive routines for operating on sockets and socket buffers
*/
 
u_long sb_max = SB_MAX; /* XXX should be static */
SYSCTL_INT(_kern, KERN_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, "")
 
static u_long sb_efficiency = 8; /* parameter for sbreserve() */
SYSCTL_INT(_kern, OID_AUTO, sockbuf_waste_factor, CTLFLAG_RW, &sb_efficiency,
0, "");
 
/*
* Procedures to manipulate state flags of socket
* and do appropriate wakeups. Normal sequence from the
* active (originating) side is that soisconnecting() is
* called during processing of connect() call,
* resulting in an eventual call to soisconnected() if/when the
* connection is established. When the connection is torn down
* soisdisconnecting() is called during processing of disconnect() call,
* and soisdisconnected() is called when the connection to the peer
* is totally severed. The semantics of these routines are such that
* connectionless protocols can call soisconnected() and soisdisconnected()
* only, bypassing the in-progress calls when setting up a ``connection''
* takes no time.
*
* From the passive side, a socket is created with
* two queues of sockets: so_q0 for connections in progress
* and so_q for connections already made and awaiting user acceptance.
* As a protocol is preparing incoming connections, it creates a socket
* structure queued on so_q0 by calling sonewconn(). When the connection
* is established, soisconnected() is called, and transfers the
* socket structure to so_q, making it available to accept().
*
* If a socket is closed with sockets on either
* so_q0 or so_q, these sockets are dropped.
*
* If higher level protocols are implemented in
* the kernel, the wakeups done here will sometimes
* cause software-interrupt process scheduling.
*/
 
void
soisconnecting(so)
register struct socket *so;
{
 
so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= SS_ISCONNECTING;
}
 
void
soisconnected(so)
register struct socket *so;
{
register struct socket *head = so->so_head;
 
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
if (head && (so->so_state & SS_INCOMP)) {
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
so->so_state &= ~SS_INCOMP;
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
so->so_state |= SS_COMP;
sorwakeup(head);
soconnwakeup(head);
} else {
soconnwakeup(so);
sorwakeup(so);
sowwakeup(so);
}
}
 
void
soisdisconnecting(so)
register struct socket *so;
{
 
so->so_state &= ~SS_ISCONNECTING;
so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
soconnwakeup(so);
sowwakeup(so);
sorwakeup(so);
}
 
void
soisdisconnected(so)
register struct socket *so;
{
 
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
soconnwakeup(so);
sowwakeup(so);
sorwakeup(so);
}
 
/*
* Return a random connection that hasn't been serviced yet and
* is eligible for discard. There is a one in qlen chance that
* we will return a null, saying that there are no dropable
* requests. In this case, the protocol specific code should drop
* the new request. This insures fairness.
*
* This may be used in conjunction with protocol specific queue
* congestion routines.
*/
struct socket *
sodropablereq(head)
register struct socket *head;
{
register struct socket *so;
unsigned int i, j, qlen, m;
 
static int rnd;
static long old_mono_secs;
static unsigned int cur_cnt, old_cnt;
 
if ((i = (m = rtems_bsdnet_seconds_since_boot()) - old_mono_secs) != 0) {
old_mono_secs = m;
old_cnt = cur_cnt / i;
cur_cnt = 0;
}
 
so = TAILQ_FIRST(&head->so_incomp);
if (!so)
return (so);
 
qlen = head->so_incqlen;
if (++cur_cnt > qlen || old_cnt > qlen) {
rnd = (314159 * rnd + 66329) & 0xffff;
j = ((qlen + 1) * rnd) >> 16;
 
while (j-- && so)
so = TAILQ_NEXT(so, so_list);
}
 
return (so);
}
 
/*
* When an attempt at a new connection is noted on a socket
* which accepts connections, sonewconn is called. If the
* connection is possible (subject to space constraints, etc.)
* then we allocate a new structure, propoerly linked into the
* data structure of the original socket, and return this.
* Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED.
*
* Currently, sonewconn() is defined as sonewconn1() in socketvar.h
* to catch calls that are missing the (new) second parameter.
*/
struct socket *
sonewconn1(head, connstatus)
register struct socket *head;
int connstatus;
{
register struct socket *so;
 
if (head->so_qlen > 3 * head->so_qlimit / 2)
return ((struct socket *)0);
MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT);
if (so == NULL)
return ((struct socket *)0);
bzero((caddr_t)so, sizeof(*so));
so->so_head = head;
so->so_type = head->so_type;
so->so_options = head->so_options &~ SO_ACCEPTCONN;
so->so_linger = head->so_linger;
so->so_state = head->so_state | SS_NOFDREF;
so->so_proto = head->so_proto;
so->so_timeo = head->so_timeo;
so->so_pgid = head->so_pgid;
so->so_uid = head->so_uid;
(void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat);
if (connstatus) {
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
so->so_state |= SS_COMP;
} else {
TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
so->so_state |= SS_INCOMP;
head->so_incqlen++;
}
head->so_qlen++;
if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0)) {
if (so->so_state & SS_COMP) {
TAILQ_REMOVE(&head->so_comp, so, so_list);
} else {
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
}
head->so_qlen--;
(void) free((caddr_t)so, M_SOCKET);
return ((struct socket *)0);
}
if (connstatus) {
sorwakeup(head);
soconnwakeup(head);
so->so_state |= connstatus;
}
return (so);
}
 
/*
* Socantsendmore indicates that no more data will be sent on the
* socket; it would normally be applied to a socket when the user
* informs the system that no more data is to be sent, by the protocol
* code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data
* will be received, and will normally be applied to the socket by a
* protocol when it detects that the peer will send no more data.
* Data queued for reading in the socket may yet be read.
*/
 
void
socantsendmore(so)
struct socket *so;
{
 
so->so_state |= SS_CANTSENDMORE;
sowwakeup(so);
}
 
void
socantrcvmore(so)
struct socket *so;
{
 
so->so_state |= SS_CANTRCVMORE;
sorwakeup(so);
}
 
/*
* Socket buffer (struct sockbuf) utility routines.
*
* Each socket contains two socket buffers: one for sending data and
* one for receiving data. Each buffer contains a queue of mbufs,
* information about the number of mbufs and amount of data in the
* queue, and other fields allowing select() statements and notification
* on data availability to be implemented.
*
* Data stored in a socket buffer is maintained as a list of records.
* Each record is a list of mbufs chained together with the m_next
* field. Records are chained together with the m_nextpkt field. The upper
* level routine soreceive() expects the following conventions to be
* observed when placing information in the receive buffer:
*
* 1. If the protocol requires each message be preceded by the sender's
* name, then a record containing that name must be present before
* any associated data (mbuf's must be of type MT_SONAME).
* 2. If the protocol supports the exchange of ``access rights'' (really
* just additional data associated with the message), and there are
* ``rights'' to be received, then a record containing this data
* should be present (mbuf's must be of type MT_RIGHTS).
* 3. If a name or rights record exists, then it must be followed by
* a data record, perhaps of zero length.
*
* Before using a new socket structure it is first necessary to reserve
* buffer space to the socket, by calling sbreserve(). This should commit
* some of the available buffer space in the system buffer pool for the
* socket (currently, it does nothing but enforce limits). The space
* should be released by calling sbrelease() when the socket is destroyed.
*/
 
int
soreserve(so, sndcc, rcvcc)
register struct socket *so;
u_long sndcc, rcvcc;
{
 
if (sbreserve(&so->so_snd, sndcc) == 0)
goto bad;
if (sbreserve(&so->so_rcv, rcvcc) == 0)
goto bad2;
if (so->so_rcv.sb_lowat == 0)
so->so_rcv.sb_lowat = 1;
if (so->so_snd.sb_lowat == 0)
so->so_snd.sb_lowat = MCLBYTES;
if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
return (0);
bad2:
sbrelease(&so->so_snd);
bad:
return (ENOBUFS);
}
 
/*
* Allot mbufs to a sockbuf.
* Attempt to scale mbmax so that mbcnt doesn't become limiting
* if buffering efficiency is near the normal case.
*/
int
sbreserve(sb, cc)
struct sockbuf *sb;
u_long cc;
{
 
if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES))
return (0);
sb->sb_hiwat = cc;
sb->sb_mbmax = min(cc * sb_efficiency, sb_max);
if (sb->sb_lowat > sb->sb_hiwat)
sb->sb_lowat = sb->sb_hiwat;
return (1);
}
 
/*
* Free mbufs held by a socket, and reserved mbuf space.
*/
void
sbrelease(sb)
struct sockbuf *sb;
{
 
sbflush(sb);
sb->sb_hiwat = sb->sb_mbmax = 0;
}
 
/*
* Routines to add and remove
* data from an mbuf queue.
*
* The routines sbappend() or sbappendrecord() are normally called to
* append new mbufs to a socket buffer, after checking that adequate
* space is available, comparing the function sbspace() with the amount
* of data to be added. sbappendrecord() differs from sbappend() in
* that data supplied is treated as the beginning of a new record.
* To place a sender's address, optional access rights, and data in a
* socket receive buffer, sbappendaddr() should be used. To place
* access rights and data in a socket receive buffer, sbappendrights()
* should be used. In either case, the new data begins a new record.
* Note that unlike sbappend() and sbappendrecord(), these routines check
* for the caller that there will be enough space to store the data.
* Each fails if there is not enough space, or if it cannot find mbufs
* to store additional information in.
*
* Reliable protocols may use the socket send buffer to hold data
* awaiting acknowledgement. Data is normally copied from a socket
* send buffer in a protocol with m_copy for output to a peer,
* and then removing the data from the socket buffer with sbdrop()
* or sbdroprecord() when the data is acknowledged by the peer.
*/
 
/*
* Append mbuf chain m to the last record in the
* socket buffer sb. The additional space associated
* the mbuf chain is recorded in sb. Empty mbufs are
* discarded and mbufs are compacted where possible.
*/
void
sbappend(sb, m)
struct sockbuf *sb;
struct mbuf *m;
{
register struct mbuf *n;
 
if (m == 0)
return;
n = sb->sb_mb;
if (n) {
while (n->m_nextpkt)
n = n->m_nextpkt;
do {
if (n->m_flags & M_EOR) {
sbappendrecord(sb, m); /* XXXXXX!!!! */
return;
}
} while (n->m_next && (n = n->m_next));
}
sbcompress(sb, m, n);
}
 
#ifdef SOCKBUF_DEBUG
void
sbcheck(sb)
register struct sockbuf *sb;
{
register struct mbuf *m;
register int len = 0, mbcnt = 0;
 
for (m = sb->sb_mb; m; m = m->m_next) {
len += m->m_len;
mbcnt += MSIZE;
if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */
mbcnt += m->m_ext.ext_size;
if (m->m_nextpkt)
panic("sbcheck nextpkt");
}
if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc,
mbcnt, sb->sb_mbcnt);
panic("sbcheck");
}
}
#endif
 
/*
* As above, except the mbuf chain
* begins a new record.
*/
void
sbappendrecord(sb, m0)
register struct sockbuf *sb;
register struct mbuf *m0;
{
register struct mbuf *m;
 
if (m0 == 0)
return;
m = sb->sb_mb;
if (m)
while (m->m_nextpkt)
m = m->m_nextpkt;
/*
* Put the first mbuf on the queue.
* Note this permits zero length records.
*/
sballoc(sb, m0);
if (m)
m->m_nextpkt = m0;
else
sb->sb_mb = m0;
m = m0->m_next;
m0->m_next = 0;
if (m && (m0->m_flags & M_EOR)) {
m0->m_flags &= ~M_EOR;
m->m_flags |= M_EOR;
}
sbcompress(sb, m, m0);
}
 
/*
* As above except that OOB data
* is inserted at the beginning of the sockbuf,
* but after any other OOB data.
*/
void
sbinsertoob(sb, m0)
register struct sockbuf *sb;
register struct mbuf *m0;
{
register struct mbuf *m;
register struct mbuf **mp;
 
if (m0 == 0)
return;
for (mp = &sb->sb_mb; *mp ; mp = &((*mp)->m_nextpkt)) {
m = *mp;
again:
switch (m->m_type) {
 
case MT_OOBDATA:
continue; /* WANT next train */
 
case MT_CONTROL:
m = m->m_next;
if (m)
goto again; /* inspect THIS train further */
}
break;
}
/*
* Put the first mbuf on the queue.
* Note this permits zero length records.
*/
sballoc(sb, m0);
m0->m_nextpkt = *mp;
*mp = m0;
m = m0->m_next;
m0->m_next = 0;
if (m && (m0->m_flags & M_EOR)) {
m0->m_flags &= ~M_EOR;
m->m_flags |= M_EOR;
}
sbcompress(sb, m, m0);
}
 
/*
* Append address and data, and optionally, control (ancillary) data
* to the receive queue of a socket. If present,
* m0 must include a packet header with total length.
* Returns 0 if no space in sockbuf or insufficient mbufs.
*/
int
sbappendaddr(sb, asa, m0, control)
register struct sockbuf *sb;
struct sockaddr *asa;
struct mbuf *m0, *control;
{
register struct mbuf *m, *n;
int space = asa->sa_len;
 
if (m0 && (m0->m_flags & M_PKTHDR) == 0)
panic("sbappendaddr");
if (m0)
space += m0->m_pkthdr.len;
for (n = control; n; n = n->m_next) {
space += n->m_len;
if (n->m_next == 0) /* keep pointer to last control buf */
break;
}
if (space > sbspace(sb))
return (0);
if (asa->sa_len > MLEN)
return (0);
MGET(m, M_DONTWAIT, MT_SONAME);
if (m == 0)
return (0);
m->m_len = asa->sa_len;
bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len);
if (n)
n->m_next = m0; /* concatenate data to control */
else
control = m0;
m->m_next = control;
for (n = m; n; n = n->m_next)
sballoc(sb, n);
n = sb->sb_mb;
if (n) {
while (n->m_nextpkt)
n = n->m_nextpkt;
n->m_nextpkt = m;
} else
sb->sb_mb = m;
return (1);
}
 
int
sbappendcontrol(sb, m0, control)
struct sockbuf *sb;
struct mbuf *control, *m0;
{
register struct mbuf *m, *n;
int space = 0;
 
if (control == 0)
panic("sbappendcontrol");
for (m = control; ; m = m->m_next) {
space += m->m_len;
if (m->m_next == 0)
break;
}
n = m; /* save pointer to last control buffer */
for (m = m0; m; m = m->m_next)
space += m->m_len;
if (space > sbspace(sb))
return (0);
n->m_next = m0; /* concatenate data to control */
for (m = control; m; m = m->m_next)
sballoc(sb, m);
n = sb->sb_mb;
if (n) {
while (n->m_nextpkt)
n = n->m_nextpkt;
n->m_nextpkt = control;
} else
sb->sb_mb = control;
return (1);
}
 
/*
* Compress mbuf chain m into the socket
* buffer sb following mbuf n. If n
* is null, the buffer is presumed empty.
*/
void
sbcompress(sb, m, n)
register struct sockbuf *sb;
register struct mbuf *m, *n;
{
register int eor = 0;
register struct mbuf *o;
 
while (m) {
eor |= m->m_flags & M_EOR;
if (m->m_len == 0 &&
(eor == 0 ||
(((o = m->m_next) || (o = n)) &&
o->m_type == m->m_type))) {
m = m_free(m);
continue;
}
if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 &&
(n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] &&
n->m_type == m->m_type) {
bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
(unsigned)m->m_len);
n->m_len += m->m_len;
sb->sb_cc += m->m_len;
m = m_free(m);
continue;
}
if (n)
n->m_next = m;
else
sb->sb_mb = m;
sballoc(sb, m);
n = m;
m->m_flags &= ~M_EOR;
m = m->m_next;
n->m_next = 0;
}
if (eor) {
if (n)
n->m_flags |= eor;
else
printf("semi-panic: sbcompress\n");
}
}
 
/*
* Free all mbufs in a sockbuf.
* Check that all resources are reclaimed.
*/
void
sbflush(sb)
register struct sockbuf *sb;
{
 
if (sb->sb_flags & SB_LOCK)
panic("sbflush");
while (sb->sb_mbcnt)
sbdrop(sb, (int)sb->sb_cc);
if (sb->sb_cc || sb->sb_mb)
panic("sbflush 2");
}
 
/*
* Drop data from (the front of) a sockbuf.
*/
void
sbdrop(sb, len)
register struct sockbuf *sb;
register int len;
{
register struct mbuf *m, *mn;
struct mbuf *next;
 
next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
while (len > 0) {
if (m == 0) {
if (next == 0)
panic("sbdrop");
m = next;
next = m->m_nextpkt;
continue;
}
if (m->m_len > len) {
m->m_len -= len;
m->m_data += len;
sb->sb_cc -= len;
break;
}
len -= m->m_len;
sbfree(sb, m);
MFREE(m, mn);
m = mn;
}
while (m && m->m_len == 0) {
sbfree(sb, m);
MFREE(m, mn);
m = mn;
}
if (m) {
sb->sb_mb = m;
m->m_nextpkt = next;
} else
sb->sb_mb = next;
}
 
/*
* Drop a record off the front of a sockbuf
* and move the next record to the front.
*/
void
sbdroprecord(sb)
register struct sockbuf *sb;
{
register struct mbuf *m, *mn;
 
m = sb->sb_mb;
if (m) {
sb->sb_mb = m->m_nextpkt;
do {
sbfree(sb, m);
MFREE(m, mn);
m = mn;
} while (m);
}
}
 
/*
* Create a "control" mbuf containing the specified data
* with the specified type for presentation on a socket buffer.
*/
struct mbuf *
sbcreatecontrol(p, size, type, level)
caddr_t p;
register int size;
int type, level;
{
register struct cmsghdr *cp;
struct mbuf *m;
 
if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
return ((struct mbuf *) NULL);
cp = mtod(m, struct cmsghdr *);
/* XXX check size? */
(void)memcpy(CMSG_DATA(cp), p, size);
size += sizeof(*cp);
m->m_len = size;
cp->cmsg_len = size;
cp->cmsg_level = level;
cp->cmsg_type = type;
return (m);
}
 
#ifdef PRU_OLDSTYLE
/*
* The following routines mediate between the old-style `pr_usrreq'
* protocol implementations and the new-style `struct pr_usrreqs'
* calling convention.
*/
 
/* syntactic sugar */
#define nomb (struct mbuf *)0
 
static int
old_abort(struct socket *so)
{
return so->so_proto->pr_ousrreq(so, PRU_ABORT, nomb, nomb, nomb);
}
 
static int
old_accept(struct socket *so, struct mbuf *nam)
{
return so->so_proto->pr_ousrreq(so, PRU_ACCEPT, nomb, nam, nomb);
}
 
static int
old_attach(struct socket *so, int proto)
{
return so->so_proto->pr_ousrreq(so, PRU_ATTACH, nomb,
(struct mbuf *)proto, /* XXX */
nomb);
}
 
static int
old_bind(struct socket *so, struct mbuf *nam)
{
return so->so_proto->pr_ousrreq(so, PRU_BIND, nomb, nam, nomb);
}
 
static int
old_connect(struct socket *so, struct mbuf *nam)
{
return so->so_proto->pr_ousrreq(so, PRU_CONNECT, nomb, nam, nomb);
}
 
static int
old_connect2(struct socket *so1, struct socket *so2)
{
return so1->so_proto->pr_ousrreq(so1, PRU_CONNECT2, nomb,
(struct mbuf *)so2, nomb);
}
 
static int
old_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp)
{
return so->so_proto->pr_ousrreq(so, PRU_CONTROL, (struct mbuf *)cmd,
(struct mbuf *)data,
(struct mbuf *)ifp);
}
 
static int
old_detach(struct socket *so)
{
return so->so_proto->pr_ousrreq(so, PRU_DETACH, nomb, nomb, nomb);
}
 
static int
old_disconnect(struct socket *so)
{
return so->so_proto->pr_ousrreq(so, PRU_DISCONNECT, nomb, nomb, nomb);
}
 
static int
old_listen(struct socket *so)
{
return so->so_proto->pr_ousrreq(so, PRU_LISTEN, nomb, nomb, nomb);
}
 
static int
old_peeraddr(struct socket *so, struct mbuf *nam)
{
return so->so_proto->pr_ousrreq(so, PRU_PEERADDR, nomb, nam, nomb);
}
 
static int
old_rcvd(struct socket *so, int flags)
{
return so->so_proto->pr_ousrreq(so, PRU_RCVD, nomb,
(struct mbuf *)flags, /* XXX */
nomb);
}
 
static int
old_rcvoob(struct socket *so, struct mbuf *m, int flags)
{
return so->so_proto->pr_ousrreq(so, PRU_RCVOOB, m,
(struct mbuf *)flags, /* XXX */
nomb);
}
 
static int
old_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *addr,
struct mbuf *control)
{
int req;
 
if (flags & PRUS_OOB) {
req = PRU_SENDOOB;
} else if(flags & PRUS_EOF) {
req = PRU_SEND_EOF;
} else {
req = PRU_SEND;
}
return so->so_proto->pr_ousrreq(so, req, m, addr, control);
}
 
static int
old_sense(struct socket *so, struct stat *sb)
{
return so->so_proto->pr_ousrreq(so, PRU_SENSE, (struct mbuf *)sb,
nomb, nomb);
}
 
static int
old_shutdown(struct socket *so)
{
return so->so_proto->pr_ousrreq(so, PRU_SHUTDOWN, nomb, nomb, nomb);
}
 
static int
old_sockaddr(struct socket *so, struct mbuf *nam)
{
return so->so_proto->pr_ousrreq(so, PRU_SOCKADDR, nomb, nam, nomb);
}
 
struct pr_usrreqs pru_oldstyle = {
old_abort, old_accept, old_attach, old_bind, old_connect,
old_connect2, old_control, old_detach, old_disconnect,
old_listen, old_peeraddr, old_rcvd, old_rcvoob, old_send,
old_sense, old_shutdown, old_sockaddr
};
 
#endif /* PRU_OLDSTYLE */
 
/*
* Some routines that return EOPNOTSUPP for entry points that are not
* supported by a protocol. Fill in as needed.
*/
int
pru_accept_notsupp(struct socket *so, struct mbuf *nam)
{
return EOPNOTSUPP;
}
 
int
pru_connect2_notsupp(struct socket *so1, struct socket *so2)
{
return EOPNOTSUPP;
}
 
int
pru_control_notsupp(struct socket *so, int cmd, caddr_t data,
struct ifnet *ifp)
{
return EOPNOTSUPP;
}
 
int
pru_listen_notsupp(struct socket *so)
{
return EOPNOTSUPP;
}
 
int
pru_rcvd_notsupp(struct socket *so, int flags)
{
return EOPNOTSUPP;
}
 
int
pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags)
{
return EOPNOTSUPP;
}
 
/*
* This isn't really a ``null'' operation, but it's the default one
* and doesn't do anything destructive.
*/
int
pru_sense_null(struct socket *so, struct stat *sb)
{
sb->st_blksize = so->so_snd.sb_hiwat;
return 0;
}
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.