/*
- * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
*
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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.
*
- * @(#)spp_usrreq.c 7.9 (Berkeley) %G%
+ * 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.
+ *
+ * @(#)spp_usrreq.c 8.2 (Berkeley) 1/9/95
*/
-#include "param.h"
-#include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "mbuf.h"
-#include "protosw.h"
-#include "socket.h"
-#include "socketvar.h"
-#include "errno.h"
-
-#include "../net/if.h"
-#include "../net/route.h"
-#include "../netinet/tcp_fsm.h"
-
-#include "ns.h"
-#include "ns_pcb.h"
-#include "idp.h"
-#include "idp_var.h"
-#include "ns_error.h"
-#include "sp.h"
-#include "spidp.h"
-#include "spp_timer.h"
-#include "spp_var.h"
-#include "spp_debug.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/tcp_fsm.h>
+
+#include <netns/ns.h>
+#include <netns/ns_pcb.h>
+#include <netns/idp.h>
+#include <netns/idp_var.h>
+#include <netns/ns_error.h>
+#include <netns/sp.h>
+#include <netns/spidp.h>
+#include <netns/spp_timer.h>
+#include <netns/spp_var.h>
+#include <netns/spp_debug.h>
/*
* SP protocol implementation.
extern int sppconsdebug;
int spp_hardnosed;
int spp_use_delack = 0;
+u_short spp_newchecks[50];
/*ARGSUSED*/
-spp_input(m, nsp, ifp)
+spp_input(m, nsp)
register struct mbuf *m;
register struct nspcb *nsp;
- struct ifnet *ifp;
{
register struct sppcb *cb;
register struct spidp *si = mtod(m, struct spidp *);
if (so->so_options & SO_ACCEPTCONN) {
struct sppcb *ocb = cb;
- so = sonewconn(so);
+ so = sonewconn(so, 0);
if (so == 0) {
goto drop;
}
cb = nstosppcb(nsp);
cb->s_mtu = ocb->s_mtu; /* preserve sockopts */
cb->s_flags = ocb->s_flags; /* preserve sockopts */
+ cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */
cb->s_state = TCPS_LISTEN;
}
goto drop;
am->m_len = sizeof (struct sockaddr_ns);
sns = mtod(am, struct sockaddr_ns *);
+ sns->sns_len = sizeof(*sns);
sns->sns_family = AF_NS;
sns->sns_addr = si->si_sna;
laddr = nsp->nsp_laddr;
spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);
m->m_len -= sizeof (struct idp);
- m->m_off += sizeof (struct idp);
+ m->m_pkthdr.len -= sizeof (struct idp);
+ m->m_data += sizeof (struct idp);
if (spp_reass(cb, si)) {
(void) m_freem(m);
*/
incr = CUNIT;
if (cb->s_cwnd > cb->s_ssthresh)
- incr = MAX(incr * incr / cb->s_cwnd, 1);
- cb->s_cwnd = MIN(cb->s_cwnd + incr, cb->s_cwmx);
+ incr = max(incr * incr / cb->s_cwnd, 1);
+ cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
/*
* Trim Acked data from output queue.
*/
else
break;
}
- if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel)
- sowwakeup(so);
+ sowwakeup(so);
cb->s_rack = si->si_ack;
update_window:
if (SSEQ_LT(cb->s_snxt, cb->s_rack))
remque(q->si_next);
wakeup = 1;
sppstat.spps_rcvpack++;
+#ifdef SF_NEWCALL
+ if (cb->s_flags2 & SF_NEWCALL) {
+ struct sphdr *sp = mtod(m, struct sphdr *);
+ u_char dt = sp->sp_dt;
+ spp_newchecks[4]++;
+ if (dt != cb->s_rhdr.sp_dt) {
+ struct mbuf *mm =
+ m_getclr(M_DONTWAIT, MT_CONTROL);
+ spp_newchecks[0]++;
+ if (mm != NULL) {
+ u_short *s =
+ mtod(mm, u_short *);
+ cb->s_rhdr.sp_dt = dt;
+ mm->m_len = 5; /*XXX*/
+ s[0] = 5;
+ s[1] = 1;
+ *(u_char *)(&s[2]) = dt;
+ sbappend(&so->so_rcv, mm);
+ }
+ }
+ if (sp->sp_cc & SP_OB) {
+ MCHTYPE(m, MT_OOBDATA);
+ spp_newchecks[1]++;
+ so->so_oobmark = 0;
+ so->so_state &= ~SS_RCVATMARK;
+ }
+ if (packetp == 0) {
+ m->m_data += SPINC;
+ m->m_len -= SPINC;
+ m->m_pkthdr.len -= SPINC;
+ }
+ if ((sp->sp_cc & SP_EM) || packetp) {
+ sbappendrecord(&so->so_rcv, m);
+ spp_newchecks[9]++;
+ } else
+ sbappend(&so->so_rcv, m);
+ } else
+#endif
if (packetp) {
sbappendrecord(&so->so_rcv, m);
} else {
cb->s_rhdr = *mtod(m, struct sphdr *);
- m->m_off += SPINC;
+ m->m_data += SPINC;
m->m_len -= SPINC;
+ m->m_pkthdr.len -= SPINC;
sbappend(&so->so_rcv, m);
}
} else
register struct spidp *si = (struct spidp *) 0;
register struct sockbuf *sb = &so->so_snd;
int len = 0, win, rcv_win;
- short span, off;
+ short span, off, recordp = 0;
u_short alo;
int error = 0, sendalot;
#ifdef notdef
for (m = m0; m ; m = m->m_next) {
mprev = m;
len += m->m_len;
+ if (m->m_flags & M_EOR)
+ recordp = 1;
}
datalen = (cb->s_flags & SF_HO) ?
len - sizeof (struct sphdr) : len;
cb->s_cc &= ~SP_EM;
while (len > mtu) {
- m = m_copy(m0, 0, mtu);
- if (m == NULL) {
- error = ENOBUFS;
- goto bad_copy;
+ /*
+ * Here we are only being called
+ * from usrreq(), so it is OK to
+ * block.
+ */
+ m = m_copym(m0, 0, mtu, M_WAIT);
+ if (cb->s_flags & SF_NEWCALL) {
+ struct mbuf *mm = m;
+ spp_newchecks[7]++;
+ while (mm) {
+ mm->m_flags &= ~M_EOR;
+ mm = mm->m_next;
+ }
}
error = spp_output(cb, m);
if (error) {
- bad_copy:
cb->s_cc |= oldEM;
m_freem(m0);
return(error);
*/
if (len & 1) {
m = mprev;
- if (m->m_len + m->m_off < MMAXOFF)
+ if (M_TRAILINGSPACE(m) >= 1)
m->m_len++;
else {
struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
return (ENOBUFS);
}
m1->m_len = 1;
- m1->m_off = MMAXOFF - 1;
+ *(mtod(m1, u_char *)) = 0;
m->m_next = m1;
}
}
- m = m_get(M_DONTWAIT, MT_HEADER);
+ m = m_gethdr(M_DONTWAIT, MT_HEADER);
if (m == 0) {
m_freem(m0);
return (ENOBUFS);
/*
* Fill in mbuf with extended SP header
* and addresses and length put into network format.
- * Long align so prepended ip headers will work on Gould.
*/
- m->m_off = MMAXOFF - sizeof (struct spidp) - 2;
+ MH_ALIGN(m, sizeof (struct spidp));
m->m_len = sizeof (struct spidp);
m->m_next = m0;
si = mtod(m, struct spidp *);
si->si_dt = sh->sp_dt;
si->si_cc |= sh->sp_cc & SP_EM;
m0->m_len -= sizeof (*sh);
- m0->m_off += sizeof (*sh);
+ m0->m_data += sizeof (*sh);
len -= sizeof (*sh);
}
len += sizeof(*si);
+ if ((cb->s_flags2 & SF_NEWCALL) && recordp) {
+ si->si_cc |= SP_EM;
+ spp_newchecks[8]++;
+ }
if (cb->s_oobflags & SF_SOOB) {
/*
* Per jqj@cornell:
}
}
si->si_len = htons((u_short)len);
+ m->m_pkthdr.len = ((len - 1) | 1) + 1;
/*
* queue stuff up for output
*/
again:
sendalot = 0;
off = cb->s_snxt - cb->s_rack;
- win = MIN(cb->s_swnd, (cb->s_cwnd/CUNIT));
+ win = min(cb->s_swnd, (cb->s_cwnd/CUNIT));
/*
* If in persist timeout with window of 0, send a probe.
}
}
span = cb->s_seq - cb->s_rack;
- len = MIN(span, win) - off;
+ len = min(span, win) - off;
if (len < 0) {
/*
if (m == NULL) {
return (ENOBUFS);
}
- m0 = m;
si = mtod(m, struct spidp *);
if (SSEQ_LT(si->si_seq, cb->s_smax))
sppstat.spps_sndrexmitpack++;
sppstat.spps_sndprobe++;
if (cb->s_flags & SF_ACKNOW)
sppstat.spps_sndacks++;
- m = m_get(M_DONTWAIT, MT_HEADER);
- if (m == 0) {
+ m = m_gethdr(M_DONTWAIT, MT_HEADER);
+ if (m == 0)
return (ENOBUFS);
- }
/*
* Fill in mbuf with extended SP header
* and addresses and length put into network format.
- * Allign beginning of packet to long to prepend
- * ifp's on loopback, or NSIP encaspulation for fussy cpu's.
*/
- m->m_off = MMAXOFF - sizeof (struct spidp) - 2;
+ MH_ALIGN(m, sizeof (struct spidp));
m->m_len = sizeof (*si);
- m->m_next = 0;
+ m->m_pkthdr.len = sizeof (*si);
si = mtod(m, struct spidp *);
si->si_i = *cb->s_idp;
si->si_s = cb->s_shdr;
len = ntohs(si->si_len);
if (len & 1)
len++;
- si->si_sum = ns_cksum(dtom(si), len);
+ si->si_sum = ns_cksum(m, len);
} else
si->si_sum = 0xffff;
mask = SF_HO;
get_flags:
m->m_len = sizeof(short);
- m->m_off = MMAXOFF - sizeof(short);
*mtod(m, short *) = cb->s_flags & mask;
break;
case SO_MTU:
m->m_len = sizeof(u_short);
- m->m_off = MMAXOFF - sizeof(short);
*mtod(m, short *) = cb->s_mtu;
break;
case SO_LAST_HEADER:
m->m_len = sizeof(struct sphdr);
- m->m_off = MMAXOFF - sizeof(struct sphdr);
*mtod(m, struct sphdr *) = cb->s_rhdr;
break;
case SO_DEFAULT_HEADERS:
m->m_len = sizeof(struct spidp);
- m->m_off = MMAXOFF - sizeof(struct sphdr);
*mtod(m, struct sphdr *) = cb->s_shdr;
break;
cb->s_mtu = *(mtod(*value, u_short *));
break;
+#ifdef SF_NEWCALL
+ case SO_NEWCALL:
+ ok = mtod(*value, int *);
+ if (*ok) {
+ cb->s_flags2 |= SF_NEWCALL;
+ spp_newchecks[5]++;
+ } else {
+ cb->s_flags2 &= ~SF_NEWCALL;
+ spp_newchecks[6]++;
+ }
+ break;
+#endif
+
case SO_DEFAULT_HEADERS:
{
register struct sphdr *sp
}
/*ARGSUSED*/
-spp_usrreq(so, req, m, nam, rights)
+spp_usrreq(so, req, m, nam, controlp)
struct socket *so;
int req;
- struct mbuf *m, *nam, *rights;
+ struct mbuf *m, *nam, *controlp;
{
struct nspcb *nsp = sotonspcb(so);
register struct sppcb *cb;
register struct sockbuf *sb;
if (req == PRU_CONTROL)
- return (ns_control(so, (int)m, (caddr_t)nam,
- (struct ifnet *)rights));
- if (rights && rights->m_len) {
- error = EINVAL;
- goto release;
- }
+ return (ns_control(so, m, (caddr_t)nam,
+ (struct ifnet *)controlp));
if (nsp == NULL) {
if (req != PRU_ATTACH) {
error = EINVAL;
cb->s_mtu = 576 - sizeof (struct spidp);
cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
cb->s_ssthresh = cb->s_cwnd;
- cb->s_cwmx = sb->sb_mbmax * CUNIT /
+ cb->s_cwmx = sbspace(sb) * CUNIT /
(2 * sizeof (struct spidp));
/* Above is recomputed when connecting to account
for changed buffering or mtu's */
cb->s_oobflags |= SF_SOOB;
/* fall into */
case PRU_SEND:
+ if (controlp) {
+ u_short *p = mtod(controlp, u_short *);
+ spp_newchecks[2]++;
+ if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */
+ cb->s_shdr.sp_dt = *(u_char *)(&p[2]);
+ spp_newchecks[3]++;
+ }
+ m_freem(controlp);
+ }
+ controlp = NULL;
error = spp_output(cb, m);
m = NULL;
break;
if (cb && (so->so_options & SO_DEBUG || traceallspps))
spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
release:
+ if (controlp != NULL)
+ m_freem(controlp);
if (m != NULL)
m_freem(m);
splx(s);
return (error);
}
-spp_usrreq_sp(so, req, m, nam, rights)
+spp_usrreq_sp(so, req, m, nam, controlp)
struct socket *so;
int req;
- struct mbuf *m, *nam, *rights;
+ struct mbuf *m, *nam, *controlp;
{
- int error = spp_usrreq(so, req, m, nam, rights);
+ int error = spp_usrreq(so, req, m, nam, controlp);
if (req == PRU_ATTACH && error == 0) {
struct nspcb *nsp = sotonspcb(so);
cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement
of large packets */
- cb->s_cwmx = (sb->sb_mbmax * CUNIT) / (2 * sizeof(struct spidp));
- cb->s_cwmx = MAX(cb->s_cwmx, cb->s_cwnd);
+ cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp));
+ cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);
/* But allow for lots of little packets as well */
}
if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
(void) spp_usrreq(cb->s_nspcb->nsp_socket,
PRU_SLOWTIMO, (struct mbuf *)0,
- (struct mbuf *)i, (struct mbuf *)0);
+ (struct mbuf *)i, (struct mbuf *)0,
+ (struct mbuf *)0);
if (ipnxt->nsp_prev != ip)
goto tpgone;
}
* See very long discussion in tcp_timer.c about congestion
* window and sstrhesh
*/
- win = MIN(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
+ win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
if (win < 2)
win = 2;
cb->s_cwnd = CUNIT;
#ifndef lint
int SppcbSize = sizeof (struct sppcb);
int NspcbSize = sizeof (struct nspcb);
-#endif lint
+#endif /* lint */