Change IPX to use the pr_usrreqs structure.

This commit is contained in:
jhay 1997-04-05 20:05:11 +00:00
parent 8a34de70b7
commit 09aec948b9
5 changed files with 581 additions and 430 deletions

View File

@ -33,7 +33,7 @@
*
* @(#)ipx.h
*
* $Id$
* $Id: ipx.h,v 1.9 1997/02/22 09:41:52 peter Exp $
*/
#ifndef _NETIPX_IPX_H_
@ -158,6 +158,8 @@ struct ipx {
#ifdef KERNEL
extern struct pr_usrreqs ipx_usrreqs;
extern struct pr_usrreqs ripx_usrreqs;
extern int ipxcksum;
extern struct domain ipxdomain;
extern struct sockaddr_ipx ipx_netmask;
@ -191,13 +193,12 @@ void ipx_input __P((struct mbuf *m, struct ipxpcb *ipxp));
void ipxintr __P((void));
int ipx_output __P((struct ipxpcb *ipxp, struct mbuf *m0));
int ipx_outputfl __P((struct mbuf *m0, struct route *ro, int flags));
int ipx_raw_usrreq __P((struct socket *so, int req, struct mbuf *m,
struct mbuf *nam, struct mbuf *control));
void ipx_undo_route __P((struct route *ro));
int ipx_usrreq __P((struct socket *so, int req, struct mbuf *m,
struct mbuf *nam, struct mbuf *control));
void ipx_watch_output __P((struct mbuf *m, struct ifnet *ifp));
int ipx_peeraddr __P((struct socket *so, struct mbuf *nam));
int ipx_sockaddr __P((struct socket *so, struct mbuf *nam));
#else
#include <sys/cdefs.h>

View File

@ -33,7 +33,7 @@
*
* @(#)ipx_proto.c
*
* $Id$
* $Id: ipx_proto.c,v 1.7 1997/02/22 09:41:56 peter Exp $
*/
#include <sys/param.h>
@ -57,39 +57,45 @@ struct protosw ipxsw[] = {
{ 0, &ipxdomain, 0, 0,
0, 0, 0, 0,
0,
ipx_init, 0, 0, 0
ipx_init, 0, 0, 0,
},
{ SOCK_DGRAM, &ipxdomain, 0, PR_ATOMIC|PR_ADDR,
0, 0, ipx_ctlinput, ipx_ctloutput,
ipx_usrreq,
0, 0, 0, 0
0,
0, 0, 0, 0,
&ipx_usrreqs
},
{ SOCK_STREAM, &ipxdomain, IPXPROTO_SPX, PR_CONNREQUIRED|PR_WANTRCVD,
0, 0, spx_ctlinput, spx_ctloutput,
spx_usrreq,
spx_init, spx_fasttimo, spx_slowtimo, 0
0,
spx_init, spx_fasttimo, spx_slowtimo, 0,
&spx_usrreqs
},
{ SOCK_SEQPACKET,&ipxdomain, IPXPROTO_SPX, PR_CONNREQUIRED|PR_WANTRCVD|PR_ATOMIC,
0, 0, spx_ctlinput, spx_ctloutput,
spx_usrreq_sp,
0, 0, 0, 0
0,
0, 0, 0, 0,
&spx_usrreq_sps
},
{ SOCK_RAW, &ipxdomain, IPXPROTO_RAW, PR_ATOMIC|PR_ADDR,
0, 0, 0, ipx_ctloutput,
ipx_raw_usrreq,
0, 0, 0, 0
0,
0, 0, 0, 0,
&ripx_usrreqs
},
{ SOCK_RAW, &ipxdomain, IPXPROTO_ERROR, PR_ATOMIC|PR_ADDR,
0, 0, 0, ipx_ctloutput,
ipx_raw_usrreq,
0, 0, 0, 0
0,
0, 0, 0, 0,
&ripx_usrreqs
},
#ifdef IPTUNNEL
#if 0
{ SOCK_RAW, &ipxdomain, IPPROTO_IPX, PR_ATOMIC|PR_ADDR,
iptun_input, rip_output, iptun_ctlinput, 0,
rip_usrreq,
0,
0, 0, 0, 0,
&rip_usrreqs
},
#endif
#endif

View File

@ -33,7 +33,7 @@
*
* @(#)ipx_usrreq.c
*
* $Id$
* $Id: ipx_usrreq.c,v 1.11 1997/02/22 09:41:57 peter Exp $
*/
#include <sys/param.h>
@ -74,6 +74,33 @@ int ipxrecvspace = IPXRCVQ;
SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
&ipxrecvspace, 0, "");
static int ipx_usr_abort(struct socket *so);
static int ipx_attach(struct socket *so, int proto);
static int ipx_bind(struct socket *so, struct mbuf *nam);
static int ipx_connect(struct socket *so, struct mbuf *nam);
static int ipx_detach(struct socket *so);
static int ipx_disconnect(struct socket *so);
static int ipx_send(struct socket *so, int flags, struct mbuf *m,
struct mbuf *addr, struct mbuf *control);
static int ipx_shutdown(struct socket *so);
static int ripx_attach(struct socket *so, int proto);
struct pr_usrreqs ipx_usrreqs = {
ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind,
ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
ipx_sockaddr
};
struct pr_usrreqs ripx_usrreqs = {
ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind,
ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
ipx_sockaddr
};
/*
* This may also be called for raw listeners.
*/
@ -399,202 +426,200 @@ ipx_ctloutput(req, so, level, name, value)
return (error);
}
/*ARGSUSED*/
int
ipx_usrreq(so, req, m, nam, control)
static int
ipx_usr_abort(so)
struct socket *so;
int req;
struct mbuf *m, *nam, *control;
{
int s;
struct ipxpcb *ipxp = sotoipxpcb(so);
s = splnet();
ipx_pcbdetach(ipxp);
splx(s);
sofree(so);
soisdisconnected(so);
return (0);
}
static int
ipx_attach(so, proto)
struct socket *so;
int proto;
{
int error;
int s;
struct ipxpcb *ipxp = sotoipxpcb(so);
if (ipxp != NULL)
return (EINVAL);
s = splnet();
error = ipx_pcballoc(so, &ipxpcb);
splx(s);
if (error == 0)
error = soreserve(so, ipxsendspace, ipxrecvspace);
return (error);
}
static int
ipx_bind(so, nam)
struct socket *so;
struct mbuf *nam;
{
struct ipxpcb *ipxp = sotoipxpcb(so);
int error = 0;
if (req == PRU_CONTROL)
return (ipx_control(so, (int)m, (caddr_t)nam,
(struct ifnet *)control));
if (control && control->m_len) {
error = EINVAL;
goto release;
}
if (ipxp == NULL && req != PRU_ATTACH) {
error = EINVAL;
goto release;
}
switch (req) {
return (ipx_pcbbind(ipxp, nam));
}
case PRU_ATTACH:
if (ipxp != NULL) {
error = EINVAL;
break;
}
error = ipx_pcballoc(so, &ipxpcb);
if (error)
break;
error = soreserve(so, ipxsendspace, ipxrecvspace);
if (error)
break;
break;
static int
ipx_connect(so, nam)
struct socket *so;
struct mbuf *nam;
{
int error;
int s;
struct ipxpcb *ipxp = sotoipxpcb(so);
case PRU_DETACH:
if (ipxp == NULL) {
error = ENOTCONN;
break;
}
ipx_pcbdetach(ipxp);
break;
if (!ipx_nullhost(ipxp->ipxp_faddr))
return (EISCONN);
s = splnet();
error = ipx_pcbconnect(ipxp, nam);
splx(s);
if (error == 0)
soisconnected(so);
return (error);
}
case PRU_BIND:
error = ipx_pcbbind(ipxp, nam);
break;
static int
ipx_detach(so)
struct socket *so;
{
int s;
struct ipxpcb *ipxp = sotoipxpcb(so);
case PRU_LISTEN:
error = EOPNOTSUPP;
break;
if (ipxp == NULL)
return (ENOTCONN);
s = splnet();
ipx_pcbdetach(ipxp);
splx(s);
return (0);
}
case PRU_CONNECT:
static int
ipx_disconnect(so)
struct socket *so;
{
int s;
struct ipxpcb *ipxp = sotoipxpcb(so);
if (ipx_nullhost(ipxp->ipxp_faddr))
return (ENOTCONN);
s = splnet();
ipx_pcbdisconnect(ipxp);
splx(s);
soisdisconnected(so);
return (0);
}
int
ipx_peeraddr(so, nam)
struct socket *so;
struct mbuf *nam;
{
struct ipxpcb *ipxp = sotoipxpcb(so);
ipx_setpeeraddr(ipxp, nam);
return (0);
}
static int
ipx_send(so, flags, m, nam, control)
struct socket *so;
int flags;
struct mbuf *m;
struct mbuf *nam;
struct mbuf *control;
{
int error;
struct ipxpcb *ipxp = sotoipxpcb(so);
struct ipx_addr laddr;
int s = 0;
if (nam) {
laddr = ipxp->ipxp_laddr;
if (!ipx_nullhost(ipxp->ipxp_faddr)) {
error = EISCONN;
break;
goto send_release;
}
/*
* Must block input while temporarily connected.
*/
s = splnet();
error = ipx_pcbconnect(ipxp, nam);
if (error == 0)
soisconnected(so);
break;
case PRU_CONNECT2:
error = EOPNOTSUPP;
break;
case PRU_ACCEPT:
error = EOPNOTSUPP;
break;
case PRU_DISCONNECT:
if (error) {
splx(s);
goto send_release;
}
} else {
if (ipx_nullhost(ipxp->ipxp_faddr)) {
error = ENOTCONN;
break;
goto send_release;
}
}
error = ipx_output(ipxp, m);
m = NULL;
if (nam) {
ipx_pcbdisconnect(ipxp);
soisdisconnected(so);
break;
case PRU_SHUTDOWN:
socantsendmore(so);
break;
case PRU_SEND:
{
struct ipx_addr laddr;
int s = 0;
if (nam) {
laddr = ipxp->ipxp_laddr;
if (!ipx_nullhost(ipxp->ipxp_faddr)) {
error = EISCONN;
break;
}
/*
* Must block input while temporarily connected.
*/
s = splnet();
error = ipx_pcbconnect(ipxp, nam);
if (error) {
splx(s);
break;
}
} else {
if (ipx_nullhost(ipxp->ipxp_faddr)) {
error = ENOTCONN;
break;
}
}
error = ipx_output(ipxp, m);
m = NULL;
if (nam) {
ipx_pcbdisconnect(ipxp);
splx(s);
ipxp->ipxp_laddr.x_host = laddr.x_host;
ipxp->ipxp_laddr.x_port = laddr.x_port;
}
splx(s);
ipxp->ipxp_laddr.x_host = laddr.x_host;
ipxp->ipxp_laddr.x_port = laddr.x_port;
}
break;
case PRU_ABORT:
ipx_pcbdetach(ipxp);
sofree(so);
soisdisconnected(so);
break;
case PRU_SOCKADDR:
ipx_setsockaddr(ipxp, nam);
break;
case PRU_PEERADDR:
ipx_setpeeraddr(ipxp, nam);
break;
case PRU_SENSE:
/*
* stat: don't bother with a blocksize.
*/
return (0);
case PRU_SENDOOB:
case PRU_FASTTIMO:
case PRU_SLOWTIMO:
case PRU_PROTORCV:
case PRU_PROTOSEND:
error = EOPNOTSUPP;
break;
case PRU_CONTROL:
case PRU_RCVD:
case PRU_RCVOOB:
return (EOPNOTSUPP); /* do not free mbuf's */
default:
panic("ipx_usrreq");
}
release:
if (control != NULL)
m_freem(control);
send_release:
if (m != NULL)
m_freem(m);
return (error);
}
/*ARGSUSED*/
int
ipx_raw_usrreq(so, req, m, nam, control)
static int
ipx_shutdown(so)
struct socket *so;
int req;
struct mbuf *m, *nam, *control;
{
int error = 0;
struct ipxpcb *ipxp = sotoipxpcb(so);
/*extern struct ipxpcb ipxrawpcb;*//*XXX*//*JRE*/
switch (req) {
case PRU_ATTACH:
if (!(so->so_state & SS_PRIV) || (ipxp != NULL)) {
error = EINVAL;
break;
}
error = ipx_pcballoc(so, &ipxrawpcb);
if (error)
break;
error = soreserve(so, ipxsendspace, ipxrecvspace);
if (error)
break;
ipxp = sotoipxpcb(so);
ipxp->ipxp_faddr.x_host = ipx_broadhost;
ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
break;
default:
error = ipx_usrreq(so, req, m, nam, control);
}
return (error);
socantsendmore(so);
return (0);
}
int
ipx_sockaddr(so, nam)
struct socket *so;
struct mbuf *nam;
{
struct ipxpcb *ipxp = sotoipxpcb(so);
ipx_setsockaddr(ipxp, nam);
return (0);
}
static int
ripx_attach(so, proto)
struct socket *so;
int proto;
{
int error = 0;
int s;
struct ipxpcb *ipxp = sotoipxpcb(so);
if (!(so->so_state & SS_PRIV) || (ipxp != NULL))
return (EINVAL);
s = splnet();
error = ipx_pcballoc(so, &ipxrawpcb);
splx(s);
if (error)
return (error);
error = soreserve(so, ipxsendspace, ipxrecvspace);
if (error)
return (error);
ipxp = sotoipxpcb(so);
ipxp->ipxp_faddr.x_host = ipx_broadhost;
ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
return (error);
}

View File

@ -33,7 +33,7 @@
*
* @(#)spx.h
*
* $Id$
* $Id: spx.h,v 1.9 1997/02/22 09:41:58 peter Exp $
*/
#ifndef _NETIPX_SPX_H_
@ -169,6 +169,9 @@ struct spxpcb {
#ifdef KERNEL
extern struct pr_usrreqs spx_usrreqs;
extern struct pr_usrreqs spx_usrreq_sps;
void spx_abort __P((struct ipxpcb *ipxp));
struct spxpcb *
spx_close __P((struct spxpcb *cb));
@ -192,10 +195,6 @@ struct spxpcb *
spx_timers __P((struct spxpcb *cb, int timer));
struct spxpcb *
spx_usrclosed __P((struct spxpcb *cb));
int spx_usrreq __P((struct socket *so, int req, struct mbuf *m,
struct mbuf *nam, struct mbuf *controlp));
int spx_usrreq_sp __P((struct socket *so, int req, struct mbuf *m,
struct mbuf *nam, struct mbuf *controlp));
#endif /* KERNEL */

View File

@ -33,7 +33,7 @@
*
* @(#)spx_usrreq.h
*
* $Id$
* $Id: spx_usrreq.c,v 1.10 1997/02/22 09:42:00 peter Exp $
*/
#include <sys/param.h>
@ -72,6 +72,37 @@ u_short spx_newchecks[50];
struct spx_istat spx_istat;
u_short spx_iss;
static int spx_usr_abort(struct socket *so);
static int spx_accept(struct socket *so, struct mbuf *nam);
static int spx_attach(struct socket *so, int proto);
static int spx_bind(struct socket *so, struct mbuf *nam);
static int spx_connect(struct socket *so, struct mbuf *nam);
static int spx_detach(struct socket *so);
static int spx_usr_disconnect(struct socket *so);
static int spx_listen(struct socket *so);
static int spx_rcvd(struct socket *so, int flags);
static int spx_rcvoob(struct socket *so, struct mbuf *m, int flags);
static int spx_send(struct socket *so, int flags, struct mbuf *m,
struct mbuf *addr, struct mbuf *control);
static int spx_shutdown(struct socket *so);
static int spx_sp_attach(struct socket *so, int proto);
struct pr_usrreqs spx_usrreqs = {
spx_usr_abort, spx_accept, spx_attach, spx_bind,
spx_connect, pru_connect2_notsupp, ipx_control, spx_detach,
spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd,
spx_rcvoob, spx_send, pru_sense_null, spx_shutdown,
ipx_sockaddr
};
struct pr_usrreqs spx_usrreq_sps = {
spx_usr_abort, spx_accept, spx_sp_attach, spx_bind,
spx_connect, pru_connect2_notsupp, ipx_control, spx_detach,
spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd,
spx_rcvoob, spx_send, pru_sense_null, spx_shutdown,
ipx_sockaddr
};
void
spx_init()
{
@ -1266,252 +1297,319 @@ spx_ctloutput(req, so, level, name, value)
return (error);
}
/*ARGSUSED*/
int
spx_usrreq(so, req, m, nam, controlp)
static int
spx_usr_abort(so)
struct socket *so;
int req;
struct mbuf *m, *nam, *controlp;
{
struct ipxpcb *ipxp = sotoipxpcb(so);
register struct spxpcb *cb = NULL;
int s = splnet();
int error = 0, ostate;
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
s = splnet();
spx_drop(cb, ECONNABORTED);
splx(s);
return (0);
}
/*
* Accept a connection. Essentially all the work is
* done at higher levels; just return the address
* of the peer, storing through addr.
*/
static int
spx_accept(so, nam)
struct socket *so;
struct mbuf *nam;
{
struct ipxpcb *ipxp;
struct sockaddr_ipx *sipx;
ipxp = sotoipxpcb(so);
sipx = mtod(nam, struct sockaddr_ipx *);
nam->m_len = sizeof (struct sockaddr_ipx);
sipx->sipx_family = AF_IPX;
sipx->sipx_addr = ipxp->ipxp_faddr;
return (0);
}
static int
spx_attach(so, proto)
struct socket *so;
int proto;
{
int error;
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
struct mbuf *mm;
register struct sockbuf *sb;
struct sockbuf *sb;
if (req == PRU_CONTROL)
return (ipx_control(so, (int)m, (caddr_t)nam,
(struct ifnet *)controlp));
if (ipxp == NULL) {
if (req != PRU_ATTACH) {
error = EINVAL;
goto release;
}
} else
cb = ipxtospxpcb(ipxp);
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
ostate = cb ? cb->s_state : 0;
switch (req) {
case PRU_ATTACH:
if (ipxp != NULL) {
error = EISCONN;
break;
}
error = ipx_pcballoc(so, &ipxpcb);
if (ipxp != NULL)
return (EISCONN);
s = splnet();
error = ipx_pcballoc(so, &ipxpcb);
if (error)
goto spx_attach_end;
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
error = soreserve(so, (u_long) 3072, (u_long) 3072);
if (error)
break;
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
error = soreserve(so, (u_long) 3072, (u_long) 3072);
if (error)
break;
}
ipxp = sotoipxpcb(so);
goto spx_attach_end;
}
ipxp = sotoipxpcb(so);
mm = m_getclr(M_DONTWAIT, MT_PCB);
sb = &so->so_snd;
mm = m_getclr(M_DONTWAIT, MT_PCB);
sb = &so->so_snd;
if (mm == NULL) {
error = ENOBUFS;
break;
}
cb = mtod(mm, struct spxpcb *);
mm = m_getclr(M_DONTWAIT, MT_HEADER);
if (mm == NULL) {
(void) m_free(dtom(m));
error = ENOBUFS;
break;
}
cb->s_ipx = mtod(mm, struct ipx *);
if (mm == NULL) {
error = ENOBUFS;
goto spx_attach_end;
}
cb = mtod(mm, struct spxpcb *);
mm = m_getclr(M_DONTWAIT, MT_HEADER);
if (mm == NULL) {
m_freem(dtom(cb));
error = ENOBUFS;
goto spx_attach_end;
}
cb->s_ipx = mtod(mm, struct ipx *);
cb->s_state = TCPS_LISTEN;
cb->s_smax = -1;
cb->s_swl1 = -1;
cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
cb->s_ipxpcb = ipxp;
cb->s_mtu = 576 - sizeof (struct spx);
cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
cb->s_ssthresh = cb->s_cwnd;
cb->s_cwmx = sbspace(sb) * CUNIT /
(2 * sizeof (struct spx));
/* Above is recomputed when connecting to account
for changed buffering or mtu's */
cb->s_rtt = SPXTV_SRTTBASE;
cb->s_rttvar = SPXTV_SRTTDFLT << 2;
SPXT_RANGESET(cb->s_rxtcur,
((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1,
SPXTV_MIN, SPXTV_REXMTMAX);
ipxp->ipxp_pcb = (caddr_t) cb;
spx_attach_end:
splx(s);
return (error);
}
static int
spx_bind(so, nam)
struct socket *so;
struct mbuf *nam;
{
struct ipxpcb *ipxp;
ipxp = sotoipxpcb(so);
return (ipx_pcbbind(ipxp, nam));
}
/*
* Initiate connection to peer.
* Enter SYN_SENT state, and mark socket as connecting.
* Start keep-alive timer, setup prototype header,
* Send initial system packet requesting connection.
*/
static int
spx_connect(so, nam)
struct socket *so;
struct mbuf *nam;
{
int error;
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
s = splnet();
if (ipxp->ipxp_lport == 0) {
error = ipx_pcbbind(ipxp, (struct mbuf *)0);
if (error)
goto spx_connect_end;
}
error = ipx_pcbconnect(ipxp, nam);
if (error)
goto spx_connect_end;
soisconnecting(so);
spxstat.spxs_connattempt++;
cb->s_state = TCPS_SYN_SENT;
cb->s_did = 0;
spx_template(cb);
cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
cb->s_force = 1 + SPXTV_KEEP;
/*
* Other party is required to respond to
* the port I send from, but he is not
* required to answer from where I am sending to,
* so allow wildcarding.
* original port I am sending to is still saved in
* cb->s_dport.
*/
ipxp->ipxp_fport = 0;
error = spx_output(cb, (struct mbuf *) 0);
spx_connect_end:
splx(s);
return (error);
}
static int
spx_detach(so)
struct socket *so;
{
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
if (ipxp == NULL)
return (ENOTCONN);
s = splnet();
if (cb->s_state > TCPS_LISTEN)
spx_disconnect(cb);
else
spx_close(cb);
splx(s);
return (0);
}
/*
* We may decide later to implement connection closing
* handshaking at the spx level optionally.
* here is the hook to do it:
*/
static int
spx_usr_disconnect(so)
struct socket *so;
{
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
s = splnet();
spx_disconnect(cb);
splx(s);
return (0);
}
static int
spx_listen(so)
struct socket *so;
{
int error;
struct ipxpcb *ipxp;
struct spxpcb *cb;
error = 0;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
if (ipxp->ipxp_lport == 0)
error = ipx_pcbbind(ipxp, (struct mbuf *)0);
if (error == 0)
cb->s_state = TCPS_LISTEN;
cb->s_smax = -1;
cb->s_swl1 = -1;
cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
cb->s_ipxpcb = ipxp;
cb->s_mtu = 576 - sizeof (struct spx);
cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
cb->s_ssthresh = cb->s_cwnd;
cb->s_cwmx = sbspace(sb) * CUNIT /
(2 * sizeof (struct spx));
/* Above is recomputed when connecting to account
for changed buffering or mtu's */
cb->s_rtt = SPXTV_SRTTBASE;
cb->s_rttvar = SPXTV_SRTTDFLT << 2;
SPXT_RANGESET(cb->s_rxtcur,
((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1,
SPXTV_MIN, SPXTV_REXMTMAX);
ipxp->ipxp_pcb = (caddr_t) cb;
break;
return (error);
}
case PRU_DETACH:
if (ipxp == NULL) {
error = ENOTCONN;
break;
}
if (cb->s_state > TCPS_LISTEN)
cb = spx_disconnect(cb);
else
cb = spx_close(cb);
break;
/*
* After a receive, possibly send acknowledgment
* updating allocation.
*/
static int
spx_rcvd(so, flags)
struct socket *so;
int flags;
{
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
case PRU_BIND:
error = ipx_pcbbind(ipxp, nam);
break;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
case PRU_LISTEN:
if (ipxp->ipxp_lport == 0)
error = ipx_pcbbind(ipxp, (struct mbuf *)0);
if (error == 0)
cb->s_state = TCPS_LISTEN;
break;
s = splnet();
cb->s_flags |= SF_RVD;
spx_output(cb, (struct mbuf *) 0);
cb->s_flags &= ~SF_RVD;
splx(s);
return (0);
}
/*
* Initiate connection to peer.
* Enter SYN_SENT state, and mark socket as connecting.
* Start keep-alive timer, setup prototype header,
* Send initial system packet requesting connection.
*/
case PRU_CONNECT:
if (ipxp->ipxp_lport == 0) {
error = ipx_pcbbind(ipxp, (struct mbuf *)0);
if (error)
break;
}
error = ipx_pcbconnect(ipxp, nam);
if (error)
break;
soisconnecting(so);
spxstat.spxs_connattempt++;
cb->s_state = TCPS_SYN_SENT;
cb->s_did = 0;
spx_template(cb);
cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
cb->s_force = 1 + SPXTV_KEEP;
/*
* Other party is required to respond to
* the port I send from, but he is not
* required to answer from where I am sending to,
* so allow wildcarding.
* original port I am sending to is still saved in
* cb->s_dport.
*/
ipxp->ipxp_fport = 0;
error = spx_output(cb, (struct mbuf *) 0);
break;
static int
spx_rcvoob(so, m, flags)
struct socket *so;
struct mbuf *m;
int flags;
{
struct ipxpcb *ipxp;
struct spxpcb *cb;
case PRU_CONNECT2:
error = EOPNOTSUPP;
break;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
/*
* We may decide later to implement connection closing
* handshaking at the spx level optionally.
* here is the hook to do it:
*/
case PRU_DISCONNECT:
cb = spx_disconnect(cb);
break;
if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
(so->so_state & SS_RCVATMARK)) {
m->m_len = 1;
*mtod(m, caddr_t) = cb->s_iobc;
return (0);
}
return (EINVAL);
}
/*
* Accept a connection. Essentially all the work is
* done at higher levels; just return the address
* of the peer, storing through addr.
*/
case PRU_ACCEPT: {
struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
static int
spx_send(so, flags, m, addr, controlp)
struct socket *so;
int flags;
struct mbuf *m;
struct mbuf *addr;
struct mbuf *controlp;
{
int error;
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
nam->m_len = sizeof (struct sockaddr_ipx);
sipx->sipx_family = AF_IPX;
sipx->sipx_addr = ipxp->ipxp_faddr;
break;
}
error = 0;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
case PRU_SHUTDOWN:
socantsendmore(so);
cb = spx_usrclosed(cb);
if (cb)
error = spx_output(cb, (struct mbuf *) 0);
break;
/*
* After a receive, possibly send acknowledgment
* updating allocation.
*/
case PRU_RCVD:
cb->s_flags |= SF_RVD;
(void) spx_output(cb, (struct mbuf *) 0);
cb->s_flags &= ~SF_RVD;
break;
case PRU_ABORT:
(void) spx_drop(cb, ECONNABORTED);
break;
case PRU_SENSE:
case PRU_CONTROL:
m = NULL;
error = EOPNOTSUPP;
break;
case PRU_RCVOOB:
if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
(so->so_state & SS_RCVATMARK)) {
m->m_len = 1;
*mtod(m, caddr_t) = cb->s_iobc;
break;
}
error = EINVAL;
break;
case PRU_SENDOOB:
s = splnet();
if (flags & PRUS_OOB) {
if (sbspace(&so->so_snd) < -512) {
error = ENOBUFS;
break;
goto spx_send_end;
}
cb->s_oobflags |= SF_SOOB;
/* fall into */
case PRU_SEND:
if (controlp) {
u_short *p = mtod(controlp, u_short *);
spx_newchecks[2]++;
if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */
cb->s_shdr.spx_dt = *(u_char *)(&p[2]);
spx_newchecks[3]++;
}
m_freem(controlp);
}
controlp = NULL;
error = spx_output(cb, m);
m = NULL;
break;
case PRU_SOCKADDR:
ipx_setsockaddr(ipxp, nam);
break;
case PRU_PEERADDR:
ipx_setpeeraddr(ipxp, nam);
break;
case PRU_SLOWTIMO:
cb = spx_timers(cb, (int)nam);
req |= ((int)nam) << 8;
break;
case PRU_FASTTIMO:
case PRU_PROTORCV:
case PRU_PROTOSEND:
error = EOPNOTSUPP;
break;
default:
panic("spx_usrreq");
}
if (cb && (so->so_options & SO_DEBUG || traceallspxs))
spx_trace(SA_USER, (u_char)ostate, cb, (struct spx *)0, req);
release:
if (controlp) {
u_short *p = mtod(controlp, u_short *);
spx_newchecks[2]++;
if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */
cb->s_shdr.spx_dt = *(u_char *)(&p[2]);
spx_newchecks[3]++;
}
m_freem(controlp);
}
controlp = NULL;
error = spx_output(cb, m);
m = NULL;
spx_send_end:
if (controlp != NULL)
m_freem(controlp);
if (m != NULL)
@ -1520,16 +1618,40 @@ spx_usrreq(so, req, m, nam, controlp)
return (error);
}
int
spx_usrreq_sp(so, req, m, nam, controlp)
struct socket *so;
int req;
struct mbuf *m, *nam, *controlp;
static int
spx_shutdown(so)
struct socket *so;
{
int error = spx_usrreq(so, req, m, nam, controlp);
int error;
int s;
struct ipxpcb *ipxp;
struct spxpcb *cb;
if (req == PRU_ATTACH && error == 0) {
struct ipxpcb *ipxp = sotoipxpcb(so);
error = 0;
ipxp = sotoipxpcb(so);
cb = ipxtospxpcb(ipxp);
s = splnet();
socantsendmore(so);
cb = spx_usrclosed(cb);
if (cb)
error = spx_output(cb, (struct mbuf *) 0);
splx(s);
return (error);
}
static int
spx_sp_attach(so, proto)
struct socket *so;
int proto;
{
int error;
struct ipxpcb *ipxp;
struct spxpcb *cb;
error = spx_attach(so, proto);
if (error == 0) {
ipxp = sotoipxpcb(so);
((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |=
(SF_HI | SF_HO | SF_PI);
}
@ -1698,9 +1820,7 @@ spx_slowtimo()
goto tpgone;
for (i = 0; i < SPXT_NTIMERS; i++) {
if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
(void) spx_usrreq(cb->s_ipxpcb->ipxp_socket,
PRU_SLOWTIMO, (struct mbuf *)0,
(struct mbuf *)i, (struct mbuf *)0);
spx_timers(cb, i);
if (ipnxt->ipxp_prev != ip)
goto tpgone;
}