mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-18 10:35:55 +00:00
Complete move of SPX reassembly from spx_usrreq.c to spx_reass.c.
MFC after: 1 month
This commit is contained in:
parent
d1c77156d8
commit
cf5320bd29
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=192746
@ -2427,6 +2427,7 @@ netipx/ipx_pcb.c optional ipx
|
||||
netipx/ipx_proto.c optional ipx
|
||||
netipx/ipx_usrreq.c optional ipx
|
||||
netipx/spx_debug.c optional ipx
|
||||
netipx/spx_reass.c optional ipx
|
||||
netipx/spx_usrreq.c optional ipx
|
||||
netnatm/natm.c optional natm
|
||||
netnatm/natm_pcb.c optional natm
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -94,30 +94,21 @@ __FBSDID("$FreeBSD$");
|
||||
*/
|
||||
static struct mtx spx_mtx; /* Protects only spx_iss. */
|
||||
static u_short spx_iss;
|
||||
static u_short spx_newchecks[50];
|
||||
u_short spx_newchecks[50];
|
||||
static int spx_hardnosed;
|
||||
static int spx_use_delack = 0;
|
||||
static int traceallspxs = 0;
|
||||
static struct spx_istat spx_istat;
|
||||
static int spxrexmtthresh = 3;
|
||||
struct spx_istat spx_istat;
|
||||
|
||||
#define SPX_LOCK_INIT() mtx_init(&spx_mtx, "spx_mtx", NULL, MTX_DEF)
|
||||
#define SPX_LOCK() mtx_lock(&spx_mtx)
|
||||
#define SPX_UNLOCK() mtx_unlock(&spx_mtx)
|
||||
|
||||
/* Following was struct spxstat spxstat; */
|
||||
#ifndef spxstat
|
||||
#define spxstat spx_istat.newstats
|
||||
#endif
|
||||
|
||||
static const int spx_backoff[SPX_MAXRXTSHIFT+1] =
|
||||
{ 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
|
||||
|
||||
static void spx_close(struct spxpcb *cb);
|
||||
static void spx_disconnect(struct spxpcb *cb);
|
||||
static void spx_drop(struct spxpcb *cb, int errno);
|
||||
static int spx_output(struct spxpcb *cb, struct mbuf *m0);
|
||||
static int spx_reass(struct spxpcb *cb, struct spx *si);
|
||||
static void spx_setpersist(struct spxpcb *cb);
|
||||
static void spx_template(struct spxpcb *cb);
|
||||
static void spx_timers(struct spxpcb *cb, int timer);
|
||||
@ -180,25 +171,6 @@ struct pr_usrreqs spx_usrreq_sps = {
|
||||
.pru_close = spx_usr_close,
|
||||
};
|
||||
|
||||
static __inline void
|
||||
spx_insque(struct spx_q *element, struct spx_q *head)
|
||||
{
|
||||
|
||||
element->si_next = head->si_next;
|
||||
element->si_prev = head;
|
||||
head->si_next = element;
|
||||
element->si_next->si_prev = element;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
spx_remque(struct spx_q *element)
|
||||
{
|
||||
|
||||
element->si_next->si_prev = element->si_prev;
|
||||
element->si_prev->si_next = element->si_next;
|
||||
element->si_prev = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
spx_init(void)
|
||||
{
|
||||
@ -445,328 +417,7 @@ spx_input(struct mbuf *m, struct ipxpcb *ipxp)
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is structurally similar to the tcp reassembly routine but its
|
||||
* function is somewhat different: it merely queues packets up, and
|
||||
* suppresses duplicates.
|
||||
*/
|
||||
static int
|
||||
spx_reass(struct spxpcb *cb, struct spx *si)
|
||||
{
|
||||
struct spx_q *q;
|
||||
struct mbuf *m;
|
||||
struct socket *so = cb->s_ipxpcb->ipxp_socket;
|
||||
char packetp = cb->s_flags & SF_HI;
|
||||
int incr;
|
||||
char wakeup = 0;
|
||||
|
||||
IPX_LOCK_ASSERT(cb->s_ipxpcb);
|
||||
|
||||
if (si == SI(0))
|
||||
goto present;
|
||||
|
||||
/*
|
||||
* Update our news from them.
|
||||
*/
|
||||
if (si->si_cc & SPX_SA)
|
||||
cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW);
|
||||
if (SSEQ_GT(si->si_alo, cb->s_ralo))
|
||||
cb->s_flags |= SF_WIN;
|
||||
if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
|
||||
if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) {
|
||||
spxstat.spxs_rcvdupack++;
|
||||
|
||||
/*
|
||||
* If this is a completely duplicate ack and other
|
||||
* conditions hold, we assume a packet has been
|
||||
* dropped and retransmit it exactly as in
|
||||
* tcp_input().
|
||||
*/
|
||||
if (si->si_ack != cb->s_rack ||
|
||||
si->si_alo != cb->s_ralo)
|
||||
cb->s_dupacks = 0;
|
||||
else if (++cb->s_dupacks == spxrexmtthresh) {
|
||||
u_short onxt = cb->s_snxt;
|
||||
int cwnd = cb->s_cwnd;
|
||||
|
||||
cb->s_snxt = si->si_ack;
|
||||
cb->s_cwnd = CUNIT;
|
||||
cb->s_force = 1 + SPXT_REXMT;
|
||||
spx_output(cb, NULL);
|
||||
cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
|
||||
cb->s_rtt = 0;
|
||||
if (cwnd >= 4 * CUNIT)
|
||||
cb->s_cwnd = cwnd / 2;
|
||||
if (SSEQ_GT(onxt, cb->s_snxt))
|
||||
cb->s_snxt = onxt;
|
||||
return (1);
|
||||
}
|
||||
} else
|
||||
cb->s_dupacks = 0;
|
||||
goto update_window;
|
||||
}
|
||||
cb->s_dupacks = 0;
|
||||
|
||||
/*
|
||||
* If our correspondent acknowledges data we haven't sent TCP would
|
||||
* drop the packet after acking. We'll be a little more permissive.
|
||||
*/
|
||||
if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
|
||||
spxstat.spxs_rcvacktoomuch++;
|
||||
si->si_ack = cb->s_smax + 1;
|
||||
}
|
||||
spxstat.spxs_rcvackpack++;
|
||||
|
||||
/*
|
||||
* If transmit timer is running and timed sequence number was acked,
|
||||
* update smoothed round trip time. See discussion of algorithm in
|
||||
* tcp_input.c
|
||||
*/
|
||||
if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
|
||||
spxstat.spxs_rttupdated++;
|
||||
if (cb->s_srtt != 0) {
|
||||
short delta;
|
||||
delta = cb->s_rtt - (cb->s_srtt >> 3);
|
||||
if ((cb->s_srtt += delta) <= 0)
|
||||
cb->s_srtt = 1;
|
||||
if (delta < 0)
|
||||
delta = -delta;
|
||||
delta -= (cb->s_rttvar >> 2);
|
||||
if ((cb->s_rttvar += delta) <= 0)
|
||||
cb->s_rttvar = 1;
|
||||
} else {
|
||||
/*
|
||||
* No rtt measurement yet.
|
||||
*/
|
||||
cb->s_srtt = cb->s_rtt << 3;
|
||||
cb->s_rttvar = cb->s_rtt << 1;
|
||||
}
|
||||
cb->s_rtt = 0;
|
||||
cb->s_rxtshift = 0;
|
||||
SPXT_RANGESET(cb->s_rxtcur,
|
||||
((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
|
||||
SPXTV_MIN, SPXTV_REXMTMAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* If all outstanding data is acked, stop retransmit timer and
|
||||
* remember to restart (more output or persist). If there is more
|
||||
* data to be acked, restart retransmit timer, using current
|
||||
* (possibly backed-off) value;
|
||||
*/
|
||||
if (si->si_ack == cb->s_smax + 1) {
|
||||
cb->s_timer[SPXT_REXMT] = 0;
|
||||
cb->s_flags |= SF_RXT;
|
||||
} else if (cb->s_timer[SPXT_PERSIST] == 0)
|
||||
cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
|
||||
|
||||
/*
|
||||
* When new data is acked, open the congestion window. If the window
|
||||
* gives us less than ssthresh packets in flight, open exponentially
|
||||
* (maxseg at a time). Otherwise open linearly (maxseg^2 / cwnd at a
|
||||
* time).
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Trim Acked data from output queue.
|
||||
*/
|
||||
SOCKBUF_LOCK(&so->so_snd);
|
||||
while ((m = so->so_snd.sb_mb) != NULL) {
|
||||
if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack))
|
||||
sbdroprecord_locked(&so->so_snd);
|
||||
else
|
||||
break;
|
||||
}
|
||||
sowwakeup_locked(so);
|
||||
cb->s_rack = si->si_ack;
|
||||
update_window:
|
||||
if (SSEQ_LT(cb->s_snxt, cb->s_rack))
|
||||
cb->s_snxt = cb->s_rack;
|
||||
if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq &&
|
||||
(SSEQ_LT(cb->s_swl2, si->si_ack))) ||
|
||||
(cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) {
|
||||
/* keep track of pure window updates */
|
||||
if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack
|
||||
&& SSEQ_LT(cb->s_ralo, si->si_alo)) {
|
||||
spxstat.spxs_rcvwinupd++;
|
||||
spxstat.spxs_rcvdupack--;
|
||||
}
|
||||
cb->s_ralo = si->si_alo;
|
||||
cb->s_swl1 = si->si_seq;
|
||||
cb->s_swl2 = si->si_ack;
|
||||
cb->s_swnd = (1 + si->si_alo - si->si_ack);
|
||||
if (cb->s_swnd > cb->s_smxw)
|
||||
cb->s_smxw = cb->s_swnd;
|
||||
cb->s_flags |= SF_WIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this packet number is higher than that which we have allocated
|
||||
* refuse it, unless urgent.
|
||||
*/
|
||||
if (SSEQ_GT(si->si_seq, cb->s_alo)) {
|
||||
if (si->si_cc & SPX_SP) {
|
||||
spxstat.spxs_rcvwinprobe++;
|
||||
return (1);
|
||||
} else
|
||||
spxstat.spxs_rcvpackafterwin++;
|
||||
if (si->si_cc & SPX_OB) {
|
||||
if (SSEQ_GT(si->si_seq, cb->s_alo + 60))
|
||||
return (1); /* else queue this packet; */
|
||||
} else {
|
||||
#ifdef BROKEN
|
||||
/*
|
||||
* XXXRW: This is broken on at least one count:
|
||||
* spx_close() will free the ipxp and related parts,
|
||||
* which are then touched by spx_input() after the
|
||||
* return from spx_reass().
|
||||
*/
|
||||
/*struct socket *so = cb->s_ipxpcb->ipxp_socket;
|
||||
if (so->so_state && SS_NOFDREF) {
|
||||
spx_close(cb);
|
||||
} else
|
||||
would crash system*/
|
||||
#endif
|
||||
spx_istat.notyet++;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a system packet, we don't need to queue it up, and
|
||||
* won't update acknowledge #.
|
||||
*/
|
||||
if (si->si_cc & SPX_SP)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* We have already seen this packet, so drop.
|
||||
*/
|
||||
if (SSEQ_LT(si->si_seq, cb->s_ack)) {
|
||||
spx_istat.bdreas++;
|
||||
spxstat.spxs_rcvduppack++;
|
||||
if (si->si_seq == cb->s_ack - 1)
|
||||
spx_istat.lstdup++;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all packets queued up to insert in appropriate
|
||||
* sequence.
|
||||
*/
|
||||
for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
|
||||
if (si->si_seq == SI(q)->si_seq) {
|
||||
spxstat.spxs_rcvduppack++;
|
||||
return (1);
|
||||
}
|
||||
if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) {
|
||||
spxstat.spxs_rcvoopack++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spx_insque((struct spx_q *)si, q->si_prev);
|
||||
|
||||
/*
|
||||
* If this packet is urgent, inform process
|
||||
*/
|
||||
if (si->si_cc & SPX_OB) {
|
||||
cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
|
||||
sohasoutofband(so);
|
||||
cb->s_oobflags |= SF_IOOB;
|
||||
}
|
||||
present:
|
||||
#define SPINC sizeof(struct spxhdr)
|
||||
SOCKBUF_LOCK(&so->so_rcv);
|
||||
|
||||
/*
|
||||
* Loop through all packets queued up to update acknowledge number,
|
||||
* and present all acknowledged data to user; if in packet interface
|
||||
* mode, show packet headers.
|
||||
*/
|
||||
for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
|
||||
if (SI(q)->si_seq == cb->s_ack) {
|
||||
cb->s_ack++;
|
||||
m = dtom(q);
|
||||
if (SI(q)->si_cc & SPX_OB) {
|
||||
cb->s_oobflags &= ~SF_IOOB;
|
||||
if (so->so_rcv.sb_cc)
|
||||
so->so_oobmark = so->so_rcv.sb_cc;
|
||||
else
|
||||
so->so_rcv.sb_state |= SBS_RCVATMARK;
|
||||
}
|
||||
q = q->si_prev;
|
||||
spx_remque(q->si_next);
|
||||
wakeup = 1;
|
||||
spxstat.spxs_rcvpack++;
|
||||
#ifdef SF_NEWCALL
|
||||
if (cb->s_flags2 & SF_NEWCALL) {
|
||||
struct spxhdr *sp = mtod(m, struct spxhdr *);
|
||||
u_char dt = sp->spx_dt;
|
||||
spx_newchecks[4]++;
|
||||
if (dt != cb->s_rhdr.spx_dt) {
|
||||
struct mbuf *mm =
|
||||
m_getclr(M_DONTWAIT, MT_CONTROL);
|
||||
spx_newchecks[0]++;
|
||||
if (mm != NULL) {
|
||||
u_short *s =
|
||||
mtod(mm, u_short *);
|
||||
cb->s_rhdr.spx_dt = dt;
|
||||
mm->m_len = 5; /*XXX*/
|
||||
s[0] = 5;
|
||||
s[1] = 1;
|
||||
*(u_char *)(&s[2]) = dt;
|
||||
sbappend_locked(&so->so_rcv, mm);
|
||||
}
|
||||
}
|
||||
if (sp->spx_cc & SPX_OB) {
|
||||
MCHTYPE(m, MT_OOBDATA);
|
||||
spx_newchecks[1]++;
|
||||
so->so_oobmark = 0;
|
||||
so->so_rcv.sb_state &= ~SBS_RCVATMARK;
|
||||
}
|
||||
if (packetp == 0) {
|
||||
m->m_data += SPINC;
|
||||
m->m_len -= SPINC;
|
||||
m->m_pkthdr.len -= SPINC;
|
||||
}
|
||||
if ((sp->spx_cc & SPX_EM) || packetp) {
|
||||
sbappendrecord_locked(&so->so_rcv, m);
|
||||
spx_newchecks[9]++;
|
||||
} else
|
||||
sbappend_locked(&so->so_rcv, m);
|
||||
} else
|
||||
#endif
|
||||
if (packetp)
|
||||
sbappendrecord_locked(&so->so_rcv, m);
|
||||
else {
|
||||
cb->s_rhdr = *mtod(m, struct spxhdr *);
|
||||
m->m_data += SPINC;
|
||||
m->m_len -= SPINC;
|
||||
m->m_pkthdr.len -= SPINC;
|
||||
sbappend_locked(&so->so_rcv, m);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (wakeup)
|
||||
sorwakeup_locked(so);
|
||||
else
|
||||
SOCKBUF_UNLOCK(&so->so_rcv);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
spx_ctlinput(int cmd, struct sockaddr *arg_as_sa, void *dummy)
|
||||
{
|
||||
|
||||
/* Currently, nothing. */
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
spx_output(struct spxpcb *cb, struct mbuf *m0)
|
||||
{
|
||||
struct socket *so = cb->s_ipxpcb->ipxp_socket;
|
||||
|
@ -143,4 +143,17 @@ struct spx_istat {
|
||||
#define SSEQ_GT(a,b) (((short)((a)-(b))) > 0)
|
||||
#define SSEQ_GEQ(a,b) (((short)((a)-(b))) >= 0)
|
||||
|
||||
#ifdef _KERNEL
|
||||
/* Following was struct spxstat spxstat; */
|
||||
#ifndef spxstat
|
||||
#define spxstat spx_istat.newstats
|
||||
#endif
|
||||
extern struct spx_istat spx_istat;
|
||||
extern u_short spx_newchecks[50];
|
||||
|
||||
int spx_output(struct spxpcb *cb, struct mbuf *m0);
|
||||
int spx_reass(struct spxpcb *cb, struct spx *si);
|
||||
void spx_remque(struct spx_q *element);
|
||||
#endif
|
||||
|
||||
#endif /* !_NETIPX_SPX_VAR_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user