spx_reass.c revision 192746
112891Swpaul/*-
212891Swpaul * Copyright (c) 1984, 1985, 1986, 1987, 1993
312891Swpaul *	The Regents of the University of California.
412891Swpaul * Copyright (c) 2004-2006 Robert N. M. Watson
512891Swpaul * All rights reserved.
612891Swpaul *
712891Swpaul * Redistribution and use in source and binary forms, with or without
812891Swpaul * modification, are permitted provided that the following conditions
912891Swpaul * are met:
1012891Swpaul * 1. Redistributions of source code must retain the above copyright
1112891Swpaul *    notice, this list of conditions and the following disclaimer.
1212891Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1312891Swpaul *    notice, this list of conditions and the following disclaimer in the
1412891Swpaul *    documentation and/or other materials provided with the distribution.
1512891Swpaul * 4. Neither the name of the University nor the names of its contributors
1612891Swpaul *    may be used to endorse or promote products derived from this software
1712891Swpaul *    without specific prior written permission.
1812891Swpaul *
1912891Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2012891Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2112891Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2212891Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2312891Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2412891Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2512891Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2612891Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2712891Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2812891Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2912891Swpaul * SUCH DAMAGE.
3012891Swpaul *
3112891Swpaul * Copyright (c) 1995, Mike Mitchell
3212891Swpaul * All rights reserved.
3312891Swpaul *
3430827Scharnier * Redistribution and use in source and binary forms, with or without
3530827Scharnier * modification, are permitted provided that the following conditions
3650479Speter * are met:
3730827Scharnier * 1. Redistributions of source code must retain the above copyright
3830827Scharnier *    notice, this list of conditions and the following disclaimer.
3914248Swpaul * 2. Redistributions in binary form must reproduce the above copyright
4012891Swpaul *    notice, this list of conditions and the following disclaimer in the
4114240Swpaul *    documentation and/or other materials provided with the distribution.
4214240Swpaul * 3. All advertising materials mentioning features or use of this software
4318586Swpaul *    must display the following acknowledgement:
4412891Swpaul *	This product includes software developed by the University of
4515426Swpaul *	California, Berkeley and its contributors.
4615426Swpaul * 4. Neither the name of the University nor the names of its contributors
4712891Swpaul *    may be used to endorse or promote products derived from this software
4812891Swpaul *    without specific prior written permission.
4912891Swpaul *
5012891Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5115426Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5212891Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5314240Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5412891Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5512891Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5612891Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5712891Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5812891Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5912891Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6012891Swpaul * SUCH DAMAGE.
6112891Swpaul *
6214262Swpaul *	@(#)spx_usrreq.h
6396221Sdes */
6496221Sdes
6596221Sdes#include <sys/cdefs.h>
6696221Sdes__FBSDID("$FreeBSD: head/sys/netipx/spx_reass.c 192746 2009-05-25 09:28:54Z rwatson $");
6796221Sdes
6896221Sdes#include <sys/param.h>
6996221Sdes#include <sys/lock.h>
7096221Sdes#include <sys/malloc.h>
7196221Sdes#include <sys/mbuf.h>
7296221Sdes#include <sys/mutex.h>
7396221Sdes#include <sys/proc.h>
7496221Sdes#include <sys/protosw.h>
7596221Sdes#include <sys/signalvar.h>
7696221Sdes#include <sys/socket.h>
7796221Sdes#include <sys/socketvar.h>
7896221Sdes#include <sys/sx.h>
7996221Sdes#include <sys/systm.h>
8096221Sdes
8196221Sdes#include <net/route.h>
8296221Sdes#include <netinet/tcp_fsm.h>
8396221Sdes
8496221Sdes#include <netipx/ipx.h>
8596221Sdes#include <netipx/ipx_pcb.h>
8696221Sdes#include <netipx/ipx_var.h>
8796221Sdes#include <netipx/spx.h>
8896221Sdes#include <netipx/spx_debug.h>
8996221Sdes#include <netipx/spx_timer.h>
9096221Sdes#include <netipx/spx_var.h>
9114262Swpaul
9214240Swpaulstatic int	spx_use_delack = 0;
9390298Sdesstatic int	spxrexmtthresh = 3;
9490298Sdes
9514240Swpaulstatic __inline void
9614240Swpaulspx_insque(struct spx_q *element, struct spx_q *head)
9714240Swpaul{
9814240Swpaul
9914240Swpaul	element->si_next = head->si_next;
10014240Swpaul	element->si_prev = head;
10114240Swpaul	head->si_next = element;
10214240Swpaul	element->si_next->si_prev = element;
10314240Swpaul}
10414240Swpaul
10514240Swpaulvoid
10614240Swpaulspx_remque(struct spx_q *element)
10714240Swpaul{
10812891Swpaul
10914240Swpaul	element->si_next->si_prev = element->si_prev;
11014240Swpaul	element->si_prev->si_next = element->si_next;
11114240Swpaul	element->si_prev = NULL;
11214240Swpaul}
11390298Sdes
11490298Sdes/*
11514240Swpaul * This is structurally similar to the tcp reassembly routine but its
11614240Swpaul * function is somewhat different: it merely queues packets up, and
11714240Swpaul * suppresses duplicates.
11814240Swpaul */
11914240Swpaulint
12014240Swpaulspx_reass(struct spxpcb *cb, struct spx *si)
12114240Swpaul{
12214240Swpaul	struct spx_q *q;
12314240Swpaul	struct mbuf *m;
12414240Swpaul	struct socket *so = cb->s_ipxpcb->ipxp_socket;
12514240Swpaul	char packetp = cb->s_flags & SF_HI;
12690297Sdes	int incr;
12715426Swpaul	char wakeup = 0;
12815426Swpaul
12915426Swpaul	IPX_LOCK_ASSERT(cb->s_ipxpcb);
13014240Swpaul
13114240Swpaul	if (si == SI(0))
13214240Swpaul		goto present;
13314240Swpaul
13414240Swpaul	/*
13514240Swpaul	 * Update our news from them.
13614240Swpaul	 */
13714240Swpaul	if (si->si_cc & SPX_SA)
13814302Sadam		cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW);
13914240Swpaul	if (SSEQ_GT(si->si_alo, cb->s_ralo))
14014240Swpaul		cb->s_flags |= SF_WIN;
14114240Swpaul	if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
14214240Swpaul		if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) {
14314240Swpaul			spxstat.spxs_rcvdupack++;
14414240Swpaul
14514240Swpaul			/*
14614240Swpaul			 * If this is a completely duplicate ack and other
14714240Swpaul			 * conditions hold, we assume a packet has been
14814240Swpaul			 * dropped and retransmit it exactly as in
14990297Sdes			 * tcp_input().
15014240Swpaul			 */
15114240Swpaul			if (si->si_ack != cb->s_rack ||
15237681Sdes			    si->si_alo != cb->s_ralo)
15337681Sdes				cb->s_dupacks = 0;
15414240Swpaul			else if (++cb->s_dupacks == spxrexmtthresh) {
15514240Swpaul				u_short onxt = cb->s_snxt;
15614240Swpaul				int cwnd = cb->s_cwnd;
15714240Swpaul
15814240Swpaul				cb->s_snxt = si->si_ack;
15914240Swpaul				cb->s_cwnd = CUNIT;
16014240Swpaul				cb->s_force = 1 + SPXT_REXMT;
16114240Swpaul				spx_output(cb, NULL);
16214240Swpaul				cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
16314240Swpaul				cb->s_rtt = 0;
16414240Swpaul				if (cwnd >= 4 * CUNIT)
16514240Swpaul					cb->s_cwnd = cwnd / 2;
16614240Swpaul				if (SSEQ_GT(onxt, cb->s_snxt))
16714240Swpaul					cb->s_snxt = onxt;
16814240Swpaul				return (1);
16914240Swpaul			}
17014240Swpaul		} else
17114240Swpaul			cb->s_dupacks = 0;
17214240Swpaul		goto update_window;
17314240Swpaul	}
17414240Swpaul	cb->s_dupacks = 0;
17514240Swpaul
17614240Swpaul	/*
17714240Swpaul	 * If our correspondent acknowledges data we haven't sent TCP would
17814240Swpaul	 * drop the packet after acking.  We'll be a little more permissive.
17914240Swpaul	 */
18090297Sdes	if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
18114240Swpaul		spxstat.spxs_rcvacktoomuch++;
18214240Swpaul		si->si_ack = cb->s_smax + 1;
18314240Swpaul	}
18414240Swpaul	spxstat.spxs_rcvackpack++;
18512891Swpaul
18612891Swpaul	/*
18712891Swpaul	 * If transmit timer is running and timed sequence number was acked,
18812891Swpaul	 * update smoothed round trip time.  See discussion of algorithm in
18912891Swpaul	 * tcp_input.c
19012891Swpaul	 */
19112891Swpaul	if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
19212891Swpaul		spxstat.spxs_rttupdated++;
19312891Swpaul		if (cb->s_srtt != 0) {
19412891Swpaul			short delta;
19514240Swpaul			delta = cb->s_rtt - (cb->s_srtt >> 3);
19614240Swpaul			if ((cb->s_srtt += delta) <= 0)
19715426Swpaul				cb->s_srtt = 1;
19814240Swpaul			if (delta < 0)
19914240Swpaul				delta = -delta;
20014240Swpaul			delta -= (cb->s_rttvar >> 2);
20115426Swpaul			if ((cb->s_rttvar += delta) <= 0)
20214240Swpaul				cb->s_rttvar = 1;
20372091Sasmodai		} else {
20414240Swpaul			/*
20512891Swpaul			 * No rtt measurement yet.
20614240Swpaul			 */
20714240Swpaul			cb->s_srtt = cb->s_rtt << 3;
20814240Swpaul			cb->s_rttvar = cb->s_rtt << 1;
20915426Swpaul		}
21012891Swpaul		cb->s_rtt = 0;
21112891Swpaul		cb->s_rxtshift = 0;
21212891Swpaul		SPXT_RANGESET(cb->s_rxtcur,
21312891Swpaul			((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
21412891Swpaul			SPXTV_MIN, SPXTV_REXMTMAX);
21519161Swpaul	}
21690298Sdes
21790298Sdes	/*
21819161Swpaul	 * If all outstanding data is acked, stop retransmit timer and
21990298Sdes	 * remember to restart (more output or persist).  If there is more
22090298Sdes	 * data to be acked, restart retransmit timer, using current
22119161Swpaul	 * (possibly backed-off) value;
22212891Swpaul	 */
22312891Swpaul	if (si->si_ack == cb->s_smax + 1) {
22412891Swpaul		cb->s_timer[SPXT_REXMT] = 0;
22516044Swpaul		cb->s_flags |= SF_RXT;
22614240Swpaul	} else if (cb->s_timer[SPXT_PERSIST] == 0)
22714240Swpaul		cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
22812891Swpaul
22996221Sdes	/*
23016118Swpaul	 * When new data is acked, open the congestion window.  If the window
23112891Swpaul	 * gives us less than ssthresh packets in flight, open exponentially
23216118Swpaul	 * (maxseg at a time).  Otherwise open linearly (maxseg^2 / cwnd at a
23396221Sdes	 * time).
23496221Sdes	 */
23596221Sdes	incr = CUNIT;
23616118Swpaul	if (cb->s_cwnd > cb->s_ssthresh)
23716118Swpaul		incr = max(incr * incr / cb->s_cwnd, 1);
23816118Swpaul	cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
23916118Swpaul
24016118Swpaul	/*
24116118Swpaul	 * Trim Acked data from output queue.
24214262Swpaul	 */
24312891Swpaul	SOCKBUF_LOCK(&so->so_snd);
24412891Swpaul	while ((m = so->so_snd.sb_mb) != NULL) {
24512891Swpaul		if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack))
24630827Scharnier			sbdroprecord_locked(&so->so_snd);
24714262Swpaul		else
24812891Swpaul			break;
24912891Swpaul	}
25030827Scharnier	sowwakeup_locked(so);
25112891Swpaul	cb->s_rack = si->si_ack;
25212891Swpaulupdate_window:
25312891Swpaul	if (SSEQ_LT(cb->s_snxt, cb->s_rack))
25412891Swpaul		cb->s_snxt = cb->s_rack;
25518586Swpaul	if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq &&
25618586Swpaul	    (SSEQ_LT(cb->s_swl2, si->si_ack))) ||
25718586Swpaul	     (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) {
25818586Swpaul		/* keep track of pure window updates */
25918586Swpaul		if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack
26021366Swpaul		    && SSEQ_LT(cb->s_ralo, si->si_alo)) {
26118586Swpaul			spxstat.spxs_rcvwinupd++;
26219161Swpaul			spxstat.spxs_rcvdupack--;
26319161Swpaul		}
26419161Swpaul		cb->s_ralo = si->si_alo;
26514240Swpaul		cb->s_swl1 = si->si_seq;
26619161Swpaul		cb->s_swl2 = si->si_ack;
26718586Swpaul		cb->s_swnd = (1 + si->si_alo - si->si_ack);
26818586Swpaul		if (cb->s_swnd > cb->s_smxw)
26918586Swpaul			cb->s_smxw = cb->s_swnd;
27018586Swpaul		cb->s_flags |= SF_WIN;
27118586Swpaul	}
27230827Scharnier
27318586Swpaul	/*
27412891Swpaul	 * If this packet number is higher than that which we have allocated
27512891Swpaul	 * refuse it, unless urgent.
27612891Swpaul	 */
27712891Swpaul	if (SSEQ_GT(si->si_seq, cb->s_alo)) {
27812891Swpaul		if (si->si_cc & SPX_SP) {
27930827Scharnier			spxstat.spxs_rcvwinprobe++;
28014240Swpaul			return (1);
28114240Swpaul		} else
28214240Swpaul			spxstat.spxs_rcvpackafterwin++;
28390297Sdes		if (si->si_cc & SPX_OB) {
28414240Swpaul			if (SSEQ_GT(si->si_seq, cb->s_alo + 60))
28514240Swpaul				return (1); /* else queue this packet; */
28614240Swpaul		} else {
28714240Swpaul#ifdef BROKEN
28814240Swpaul			/*
28914240Swpaul			 * XXXRW: This is broken on at least one count:
29014240Swpaul			 * spx_close() will free the ipxp and related parts,
29114240Swpaul			 * which are then touched by spx_input() after the
29212891Swpaul			 * return from spx_reass().
29314240Swpaul			 */
29414240Swpaul			/*struct socket *so = cb->s_ipxpcb->ipxp_socket;
29514240Swpaul			if (so->so_state && SS_NOFDREF) {
29614240Swpaul				spx_close(cb);
29714240Swpaul			} else
29814262Swpaul				       would crash system*/
29914240Swpaul#endif
30014240Swpaul			spx_istat.notyet++;
30112891Swpaul			return (1);
30212891Swpaul		}
30312891Swpaul	}
30412891Swpaul
30512891Swpaul	/*
30612891Swpaul	 * If this is a system packet, we don't need to queue it up, and
30790298Sdes	 * won't update acknowledge #.
30890298Sdes	 */
30912891Swpaul	if (si->si_cc & SPX_SP)
31012891Swpaul		return (1);
31112891Swpaul
31212891Swpaul	/*
31312891Swpaul	 * We have already seen this packet, so drop.
31412891Swpaul	 */
31514240Swpaul	if (SSEQ_LT(si->si_seq, cb->s_ack)) {
31612891Swpaul		spx_istat.bdreas++;
31712891Swpaul		spxstat.spxs_rcvduppack++;
31812891Swpaul		if (si->si_seq == cb->s_ack - 1)
31912891Swpaul			spx_istat.lstdup++;
32012891Swpaul		return (1);
32112891Swpaul	}
32212891Swpaul
32315426Swpaul	/*
32412891Swpaul	 * Loop through all packets queued up to insert in appropriate
32512891Swpaul	 * sequence.
326	 */
327	for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
328		if (si->si_seq == SI(q)->si_seq) {
329			spxstat.spxs_rcvduppack++;
330			return (1);
331		}
332		if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) {
333			spxstat.spxs_rcvoopack++;
334			break;
335		}
336	}
337	spx_insque((struct spx_q *)si, q->si_prev);
338
339	/*
340	 * If this packet is urgent, inform process
341	 */
342	if (si->si_cc & SPX_OB) {
343		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
344		sohasoutofband(so);
345		cb->s_oobflags |= SF_IOOB;
346	}
347present:
348#define SPINC sizeof(struct spxhdr)
349	SOCKBUF_LOCK(&so->so_rcv);
350
351	/*
352	 * Loop through all packets queued up to update acknowledge number,
353	 * and present all acknowledged data to user; if in packet interface
354	 * mode, show packet headers.
355	 */
356	for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
357		  if (SI(q)->si_seq == cb->s_ack) {
358			cb->s_ack++;
359			m = dtom(q);
360			if (SI(q)->si_cc & SPX_OB) {
361				cb->s_oobflags &= ~SF_IOOB;
362				if (so->so_rcv.sb_cc)
363					so->so_oobmark = so->so_rcv.sb_cc;
364				else
365					so->so_rcv.sb_state |= SBS_RCVATMARK;
366			}
367			q = q->si_prev;
368			spx_remque(q->si_next);
369			wakeup = 1;
370			spxstat.spxs_rcvpack++;
371#ifdef SF_NEWCALL
372			if (cb->s_flags2 & SF_NEWCALL) {
373				struct spxhdr *sp = mtod(m, struct spxhdr *);
374				u_char dt = sp->spx_dt;
375				spx_newchecks[4]++;
376				if (dt != cb->s_rhdr.spx_dt) {
377					struct mbuf *mm =
378					   m_getclr(M_DONTWAIT, MT_CONTROL);
379					spx_newchecks[0]++;
380					if (mm != NULL) {
381						u_short *s =
382							mtod(mm, u_short *);
383						cb->s_rhdr.spx_dt = dt;
384						mm->m_len = 5; /*XXX*/
385						s[0] = 5;
386						s[1] = 1;
387						*(u_char *)(&s[2]) = dt;
388						sbappend_locked(&so->so_rcv, mm);
389					}
390				}
391				if (sp->spx_cc & SPX_OB) {
392					MCHTYPE(m, MT_OOBDATA);
393					spx_newchecks[1]++;
394					so->so_oobmark = 0;
395					so->so_rcv.sb_state &= ~SBS_RCVATMARK;
396				}
397				if (packetp == 0) {
398					m->m_data += SPINC;
399					m->m_len -= SPINC;
400					m->m_pkthdr.len -= SPINC;
401				}
402				if ((sp->spx_cc & SPX_EM) || packetp) {
403					sbappendrecord_locked(&so->so_rcv, m);
404					spx_newchecks[9]++;
405				} else
406					sbappend_locked(&so->so_rcv, m);
407			} else
408#endif
409			if (packetp)
410				sbappendrecord_locked(&so->so_rcv, m);
411			else {
412				cb->s_rhdr = *mtod(m, struct spxhdr *);
413				m->m_data += SPINC;
414				m->m_len -= SPINC;
415				m->m_pkthdr.len -= SPINC;
416				sbappend_locked(&so->so_rcv, m);
417			}
418		  } else
419			break;
420	}
421	if (wakeup)
422		sorwakeup_locked(so);
423	else
424		SOCKBUF_UNLOCK(&so->so_rcv);
425	return (0);
426}
427