1139823Simp/*-
2157067Srwatson * Copyright (c) 1984, 1985, 1986, 1987, 1993
3157067Srwatson *	The Regents of the University of California.
4192753Srwatson * Copyright (c) 2004-2009 Robert N. M. Watson
5157067Srwatson * All rights reserved.
611819Sjulian *
711819Sjulian * Redistribution and use in source and binary forms, with or without
811819Sjulian * modification, are permitted provided that the following conditions
911819Sjulian * are met:
1011819Sjulian * 1. Redistributions of source code must retain the above copyright
1111819Sjulian *    notice, this list of conditions and the following disclaimer.
1211819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1311819Sjulian *    notice, this list of conditions and the following disclaimer in the
1411819Sjulian *    documentation and/or other materials provided with the distribution.
15165899Srwatson * 4. Neither the name of the University nor the names of its contributors
16165899Srwatson *    may be used to endorse or promote products derived from this software
17165899Srwatson *    without specific prior written permission.
18165899Srwatson *
19165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22165899Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29165899Srwatson * SUCH DAMAGE.
30165899Srwatson *
31165899Srwatson * Copyright (c) 1995, Mike Mitchell
32165899Srwatson * All rights reserved.
33165899Srwatson *
34165899Srwatson * Redistribution and use in source and binary forms, with or without
35165899Srwatson * modification, are permitted provided that the following conditions
36165899Srwatson * are met:
37165899Srwatson * 1. Redistributions of source code must retain the above copyright
38165899Srwatson *    notice, this list of conditions and the following disclaimer.
39165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright
40165899Srwatson *    notice, this list of conditions and the following disclaimer in the
41165899Srwatson *    documentation and/or other materials provided with the distribution.
4211819Sjulian * 3. All advertising materials mentioning features or use of this software
4311819Sjulian *    must display the following acknowledgement:
4411819Sjulian *	This product includes software developed by the University of
4511819Sjulian *	California, Berkeley and its contributors.
4611819Sjulian * 4. Neither the name of the University nor the names of its contributors
4711819Sjulian *    may be used to endorse or promote products derived from this software
4811819Sjulian *    without specific prior written permission.
4911819Sjulian *
5011819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5111819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5211819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5311819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5411819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5511819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5611819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5711819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5811819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5911819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6011819Sjulian * SUCH DAMAGE.
6111819Sjulian *
6212057Sjulian *	@(#)spx_usrreq.h
6311819Sjulian */
6411819Sjulian
65116189Sobrien#include <sys/cdefs.h>
66116189Sobrien__FBSDID("$FreeBSD$");
67116189Sobrien
6811819Sjulian#include <sys/param.h>
6976166Smarkm#include <sys/lock.h>
70194547Srwatson#include <sys/kernel.h>
7129024Sbde#include <sys/malloc.h>
7211819Sjulian#include <sys/mbuf.h>
7376166Smarkm#include <sys/mutex.h>
7425345Sjhay#include <sys/proc.h>
7511819Sjulian#include <sys/protosw.h>
7695759Stanimura#include <sys/signalvar.h>
7711819Sjulian#include <sys/socket.h>
7811819Sjulian#include <sys/socketvar.h>
7995759Stanimura#include <sys/sx.h>
8095759Stanimura#include <sys/systm.h>
8111819Sjulian
8211819Sjulian#include <net/route.h>
8311819Sjulian#include <netinet/tcp_fsm.h>
8411819Sjulian
8511819Sjulian#include <netipx/ipx.h>
8611819Sjulian#include <netipx/ipx_pcb.h>
8711819Sjulian#include <netipx/ipx_var.h>
8811819Sjulian#include <netipx/spx.h>
8995759Stanimura#include <netipx/spx_debug.h>
9011819Sjulian#include <netipx/spx_timer.h>
9111819Sjulian#include <netipx/spx_var.h>
9211819Sjulian
9333181Seivindstatic int	spx_use_delack = 0;
94157068Srwatsonstatic int	spxrexmtthresh = 3;
9511819Sjulian
96227293Sedstatic MALLOC_DEFINE(M_SPXREASSQ, "spxreassq", "SPX reassembly queue entry");
97191533Sed
9811819Sjulian/*
99192753Srwatson * Flesh pending queued segments on SPX close.
100192753Srwatson */
101192753Srwatsonvoid
102192753Srwatsonspx_reass_flush(struct spxpcb *cb)
103192753Srwatson{
104194547Srwatson	struct spx_q *q;
105192753Srwatson
106194547Srwatson	while ((q = LIST_FIRST(&cb->s_q)) != NULL) {
107194547Srwatson		LIST_REMOVE(q, sq_entry);
108194547Srwatson		m_freem(q->sq_msi);
109194547Srwatson		free(q, M_SPXREASSQ);
110192753Srwatson	}
111192753Srwatson}
112192753Srwatson
113192753Srwatson/*
114192753Srwatson * Initialize SPX segment reassembly queue on SPX socket open.
115192753Srwatson */
116192753Srwatsonvoid
117192753Srwatsonspx_reass_init(struct spxpcb *cb)
118192753Srwatson{
119192753Srwatson
120194547Srwatson	LIST_INIT(&cb->s_q);
121192753Srwatson}
122192753Srwatson
123192753Srwatson/*
124157094Srwatson * This is structurally similar to the tcp reassembly routine but its
125179408Srwatson * function is somewhat different: it merely queues packets up, and
126157094Srwatson * suppresses duplicates.
12711819Sjulian */
128192746Srwatsonint
129194547Srwatsonspx_reass(struct spxpcb *cb, struct mbuf *msi, struct spx *si)
13011819Sjulian{
131194547Srwatson	struct spx_q *q, *q_new, *q_temp;
132157067Srwatson	struct mbuf *m;
133157067Srwatson	struct socket *so = cb->s_ipxpcb->ipxp_socket;
13411819Sjulian	char packetp = cb->s_flags & SF_HI;
13511819Sjulian	int incr;
13611819Sjulian	char wakeup = 0;
13711819Sjulian
138139932Srwatson	IPX_LOCK_ASSERT(cb->s_ipxpcb);
139139932Srwatson
14011819Sjulian	if (si == SI(0))
14111819Sjulian		goto present;
142179408Srwatson
14311819Sjulian	/*
14411819Sjulian	 * Update our news from them.
14511819Sjulian	 */
14611819Sjulian	if (si->si_cc & SPX_SA)
14711819Sjulian		cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW);
14811819Sjulian	if (SSEQ_GT(si->si_alo, cb->s_ralo))
14911819Sjulian		cb->s_flags |= SF_WIN;
15011819Sjulian	if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
15111819Sjulian		if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) {
15211819Sjulian			spxstat.spxs_rcvdupack++;
153179408Srwatson
15411819Sjulian			/*
155157094Srwatson			 * If this is a completely duplicate ack and other
156157094Srwatson			 * conditions hold, we assume a packet has been
157157094Srwatson			 * dropped and retransmit it exactly as in
158157094Srwatson			 * tcp_input().
15911819Sjulian			 */
16011819Sjulian			if (si->si_ack != cb->s_rack ||
16111819Sjulian			    si->si_alo != cb->s_ralo)
16211819Sjulian				cb->s_dupacks = 0;
16311819Sjulian			else if (++cb->s_dupacks == spxrexmtthresh) {
16411819Sjulian				u_short onxt = cb->s_snxt;
16511819Sjulian				int cwnd = cb->s_cwnd;
16611819Sjulian
16711819Sjulian				cb->s_snxt = si->si_ack;
16811819Sjulian				cb->s_cwnd = CUNIT;
16911819Sjulian				cb->s_force = 1 + SPXT_REXMT;
170139579Srwatson				spx_output(cb, NULL);
17111819Sjulian				cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
17211819Sjulian				cb->s_rtt = 0;
17311819Sjulian				if (cwnd >= 4 * CUNIT)
17411819Sjulian					cb->s_cwnd = cwnd / 2;
17511819Sjulian				if (SSEQ_GT(onxt, cb->s_snxt))
17611819Sjulian					cb->s_snxt = onxt;
17711819Sjulian				return (1);
17811819Sjulian			}
17911819Sjulian		} else
18011819Sjulian			cb->s_dupacks = 0;
18111819Sjulian		goto update_window;
18211819Sjulian	}
18311819Sjulian	cb->s_dupacks = 0;
184157094Srwatson
18511819Sjulian	/*
186157094Srwatson	 * If our correspondent acknowledges data we haven't sent TCP would
187157094Srwatson	 * drop the packet after acking.  We'll be a little more permissive.
18811819Sjulian	 */
18911819Sjulian	if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
19011819Sjulian		spxstat.spxs_rcvacktoomuch++;
19111819Sjulian		si->si_ack = cb->s_smax + 1;
19211819Sjulian	}
19311819Sjulian	spxstat.spxs_rcvackpack++;
194157094Srwatson
19511819Sjulian	/*
196157094Srwatson	 * If transmit timer is running and timed sequence number was acked,
197157094Srwatson	 * update smoothed round trip time.  See discussion of algorithm in
198157094Srwatson	 * tcp_input.c
19911819Sjulian	 */
20011819Sjulian	if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
20111819Sjulian		spxstat.spxs_rttupdated++;
20211819Sjulian		if (cb->s_srtt != 0) {
203157067Srwatson			short delta;
20411819Sjulian			delta = cb->s_rtt - (cb->s_srtt >> 3);
20511819Sjulian			if ((cb->s_srtt += delta) <= 0)
20611819Sjulian				cb->s_srtt = 1;
20711819Sjulian			if (delta < 0)
20811819Sjulian				delta = -delta;
20911819Sjulian			delta -= (cb->s_rttvar >> 2);
21011819Sjulian			if ((cb->s_rttvar += delta) <= 0)
21111819Sjulian				cb->s_rttvar = 1;
21211819Sjulian		} else {
21311819Sjulian			/*
214157094Srwatson			 * No rtt measurement yet.
21511819Sjulian			 */
21611819Sjulian			cb->s_srtt = cb->s_rtt << 3;
21711819Sjulian			cb->s_rttvar = cb->s_rtt << 1;
21811819Sjulian		}
21911819Sjulian		cb->s_rtt = 0;
22011819Sjulian		cb->s_rxtshift = 0;
22111819Sjulian		SPXT_RANGESET(cb->s_rxtcur,
22211819Sjulian			((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
22311819Sjulian			SPXTV_MIN, SPXTV_REXMTMAX);
22411819Sjulian	}
225157094Srwatson
22611819Sjulian	/*
227157094Srwatson	 * If all outstanding data is acked, stop retransmit timer and
228157094Srwatson	 * remember to restart (more output or persist).  If there is more
229157094Srwatson	 * data to be acked, restart retransmit timer, using current
230157094Srwatson	 * (possibly backed-off) value;
23111819Sjulian	 */
23211819Sjulian	if (si->si_ack == cb->s_smax + 1) {
23311819Sjulian		cb->s_timer[SPXT_REXMT] = 0;
23411819Sjulian		cb->s_flags |= SF_RXT;
23511819Sjulian	} else if (cb->s_timer[SPXT_PERSIST] == 0)
23611819Sjulian		cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
237157094Srwatson
23811819Sjulian	/*
239157094Srwatson	 * When new data is acked, open the congestion window.  If the window
240157094Srwatson	 * gives us less than ssthresh packets in flight, open exponentially
241157094Srwatson	 * (maxseg at a time).  Otherwise open linearly (maxseg^2 / cwnd at a
242157094Srwatson	 * time).
24311819Sjulian	 */
24411819Sjulian	incr = CUNIT;
24511819Sjulian	if (cb->s_cwnd > cb->s_ssthresh)
24611819Sjulian		incr = max(incr * incr / cb->s_cwnd, 1);
24711819Sjulian	cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
248157094Srwatson
24911819Sjulian	/*
25011819Sjulian	 * Trim Acked data from output queue.
25111819Sjulian	 */
252139589Srwatson	SOCKBUF_LOCK(&so->so_snd);
25311819Sjulian	while ((m = so->so_snd.sb_mb) != NULL) {
25411819Sjulian		if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack))
255139589Srwatson			sbdroprecord_locked(&so->so_snd);
25611819Sjulian		else
25711819Sjulian			break;
25811819Sjulian	}
259139589Srwatson	sowwakeup_locked(so);
26011819Sjulian	cb->s_rack = si->si_ack;
26111819Sjulianupdate_window:
26211819Sjulian	if (SSEQ_LT(cb->s_snxt, cb->s_rack))
26311819Sjulian		cb->s_snxt = cb->s_rack;
26443311Sdillon	if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq &&
26543311Sdillon	    (SSEQ_LT(cb->s_swl2, si->si_ack))) ||
26643305Sdillon	     (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) {
26711819Sjulian		/* keep track of pure window updates */
26811819Sjulian		if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack
26911819Sjulian		    && SSEQ_LT(cb->s_ralo, si->si_alo)) {
27011819Sjulian			spxstat.spxs_rcvwinupd++;
27111819Sjulian			spxstat.spxs_rcvdupack--;
27211819Sjulian		}
27311819Sjulian		cb->s_ralo = si->si_alo;
27411819Sjulian		cb->s_swl1 = si->si_seq;
27511819Sjulian		cb->s_swl2 = si->si_ack;
27611819Sjulian		cb->s_swnd = (1 + si->si_alo - si->si_ack);
27711819Sjulian		if (cb->s_swnd > cb->s_smxw)
27811819Sjulian			cb->s_smxw = cb->s_swnd;
27911819Sjulian		cb->s_flags |= SF_WIN;
28011819Sjulian	}
281157094Srwatson
28211819Sjulian	/*
283157094Srwatson	 * If this packet number is higher than that which we have allocated
284157094Srwatson	 * refuse it, unless urgent.
28511819Sjulian	 */
28611819Sjulian	if (SSEQ_GT(si->si_seq, cb->s_alo)) {
28711819Sjulian		if (si->si_cc & SPX_SP) {
28811819Sjulian			spxstat.spxs_rcvwinprobe++;
28911819Sjulian			return (1);
29011819Sjulian		} else
29111819Sjulian			spxstat.spxs_rcvpackafterwin++;
29211819Sjulian		if (si->si_cc & SPX_OB) {
293179410Srwatson			if (SSEQ_GT(si->si_seq, cb->s_alo + 60))
294179410Srwatson				return (1); /* else queue this packet; */
29511819Sjulian		} else {
296139579Srwatson#ifdef BROKEN
297139579Srwatson			/*
298139579Srwatson			 * XXXRW: This is broken on at least one count:
299139579Srwatson			 * spx_close() will free the ipxp and related parts,
300139579Srwatson			 * which are then touched by spx_input() after the
301139579Srwatson			 * return from spx_reass().
302139579Srwatson			 */
303157067Srwatson			/*struct socket *so = cb->s_ipxpcb->ipxp_socket;
30411819Sjulian			if (so->so_state && SS_NOFDREF) {
30525652Sjhay				spx_close(cb);
30697658Stanimura			} else
30797658Stanimura				       would crash system*/
308139579Srwatson#endif
30911819Sjulian			spx_istat.notyet++;
310179410Srwatson			return (1);
31111819Sjulian		}
31211819Sjulian	}
313157094Srwatson
31411819Sjulian	/*
315157094Srwatson	 * If this is a system packet, we don't need to queue it up, and
316157094Srwatson	 * won't update acknowledge #.
31711819Sjulian	 */
318157128Srwatson	if (si->si_cc & SPX_SP)
31911819Sjulian		return (1);
320157094Srwatson
32111819Sjulian	/*
32211819Sjulian	 * We have already seen this packet, so drop.
32311819Sjulian	 */
32411819Sjulian	if (SSEQ_LT(si->si_seq, cb->s_ack)) {
32511819Sjulian		spx_istat.bdreas++;
32611819Sjulian		spxstat.spxs_rcvduppack++;
32711819Sjulian		if (si->si_seq == cb->s_ack - 1)
32811819Sjulian			spx_istat.lstdup++;
32911819Sjulian		return (1);
33011819Sjulian	}
331157094Srwatson
33211819Sjulian	/*
333157094Srwatson	 * Loop through all packets queued up to insert in appropriate
334157094Srwatson	 * sequence.
33511819Sjulian	 */
336194547Srwatson	q_new = malloc(sizeof(*q_new), M_SPXREASSQ, M_NOWAIT | M_ZERO);
337194547Srwatson	if (q_new == NULL)
338194547Srwatson		return (1);
339194547Srwatson	q_new->sq_si = si;
340194547Srwatson	q_new->sq_msi = msi;
341194547Srwatson	LIST_FOREACH(q, &cb->s_q, sq_entry) {
342194547Srwatson		if (si->si_seq == q->sq_si->si_seq) {
343194547Srwatson			free(q_new, M_SPXREASSQ);
34411819Sjulian			spxstat.spxs_rcvduppack++;
34511819Sjulian			return (1);
34611819Sjulian		}
347194547Srwatson		if (SSEQ_LT(si->si_seq, q->sq_si->si_seq)) {
34811819Sjulian			spxstat.spxs_rcvoopack++;
34911819Sjulian			break;
35011819Sjulian		}
35111819Sjulian	}
352194547Srwatson	if (q != NULL)
353194547Srwatson		LIST_INSERT_BEFORE(q, q_new, sq_entry);
354194547Srwatson	else
355194547Srwatson		LIST_INSERT_HEAD(&cb->s_q, q_new, sq_entry);
356179408Srwatson
35711819Sjulian	/*
35811819Sjulian	 * If this packet is urgent, inform process
35911819Sjulian	 */
36011819Sjulian	if (si->si_cc & SPX_OB) {
36111819Sjulian		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
36211819Sjulian		sohasoutofband(so);
36311819Sjulian		cb->s_oobflags |= SF_IOOB;
36411819Sjulian	}
36511819Sjulianpresent:
36611819Sjulian#define SPINC sizeof(struct spxhdr)
367139590Srwatson	SOCKBUF_LOCK(&so->so_rcv);
368157094Srwatson
36911819Sjulian	/*
370157094Srwatson	 * Loop through all packets queued up to update acknowledge number,
371157094Srwatson	 * and present all acknowledged data to user; if in packet interface
372157094Srwatson	 * mode, show packet headers.
37311819Sjulian	 */
374194547Srwatson	LIST_FOREACH_SAFE(q, &cb->s_q, sq_entry, q_temp) {
375194547Srwatson		struct spx *qsi;
376194547Srwatson		struct mbuf *mqsi;
377194547Srwatson
378194547Srwatson		qsi = q->sq_si;
379194547Srwatson		mqsi = q->sq_msi;
380194547Srwatson		if (qsi->si_seq == cb->s_ack) {
38111819Sjulian			cb->s_ack++;
382194547Srwatson			if (qsi->si_cc & SPX_OB) {
38311819Sjulian				cb->s_oobflags &= ~SF_IOOB;
38411819Sjulian				if (so->so_rcv.sb_cc)
38511819Sjulian					so->so_oobmark = so->so_rcv.sb_cc;
386131031Srwatson				else
387130480Srwatson					so->so_rcv.sb_state |= SBS_RCVATMARK;
38811819Sjulian			}
389194547Srwatson			LIST_REMOVE(q, sq_entry);
390194547Srwatson			free(q, M_SPXREASSQ);
39111819Sjulian			wakeup = 1;
39211819Sjulian			spxstat.spxs_rcvpack++;
39311819Sjulian#ifdef SF_NEWCALL
39411819Sjulian			if (cb->s_flags2 & SF_NEWCALL) {
395194547Srwatson				struct spxhdr *sp =
396194547Srwatson				    mtod(mqsi, struct spxhdr *);
39711819Sjulian				u_char dt = sp->spx_dt;
398194547Srwatson
39911819Sjulian				spx_newchecks[4]++;
40011819Sjulian				if (dt != cb->s_rhdr.spx_dt) {
40111819Sjulian					struct mbuf *mm =
402243882Sglebius					   m_getclr(M_NOWAIT, MT_CONTROL);
40311819Sjulian					spx_newchecks[0]++;
40411819Sjulian					if (mm != NULL) {
40511819Sjulian						u_short *s =
40611819Sjulian							mtod(mm, u_short *);
40711819Sjulian						cb->s_rhdr.spx_dt = dt;
40811819Sjulian						mm->m_len = 5; /*XXX*/
40911819Sjulian						s[0] = 5;
41011819Sjulian						s[1] = 1;
41111819Sjulian						*(u_char *)(&s[2]) = dt;
412139590Srwatson						sbappend_locked(&so->so_rcv, mm);
41311819Sjulian					}
41411819Sjulian				}
41511819Sjulian				if (sp->spx_cc & SPX_OB) {
416194547Srwatson					MCHTYPE(mqsi, MT_OOBDATA);
41711819Sjulian					spx_newchecks[1]++;
41811819Sjulian					so->so_oobmark = 0;
419130480Srwatson					so->so_rcv.sb_state &= ~SBS_RCVATMARK;
42011819Sjulian				}
42111819Sjulian				if (packetp == 0) {
422194547Srwatson					mqsi->m_data += SPINC;
423194547Srwatson					mqsi->m_len -= SPINC;
424194547Srwatson					mqsi->m_pkthdr.len -= SPINC;
42511819Sjulian				}
42611819Sjulian				if ((sp->spx_cc & SPX_EM) || packetp) {
427194547Srwatson					sbappendrecord_locked(&so->so_rcv,
428194547Srwatson					    mqsi);
42911819Sjulian					spx_newchecks[9]++;
43011819Sjulian				} else
431194547Srwatson					sbappend_locked(&so->so_rcv, mqsi);
43211819Sjulian			} else
43311819Sjulian#endif
434157128Srwatson			if (packetp)
435194547Srwatson				sbappendrecord_locked(&so->so_rcv, mqsi);
436157128Srwatson			else {
437194547Srwatson				cb->s_rhdr = *mtod(mqsi, struct spxhdr *);
438194547Srwatson				mqsi->m_data += SPINC;
439194547Srwatson				mqsi->m_len -= SPINC;
440194547Srwatson				mqsi->m_pkthdr.len -= SPINC;
441194547Srwatson				sbappend_locked(&so->so_rcv, mqsi);
44211819Sjulian			}
44311819Sjulian		  } else
44411819Sjulian			break;
44511819Sjulian	}
44697658Stanimura	if (wakeup)
447139590Srwatson		sorwakeup_locked(so);
448139590Srwatson	else
449139590Srwatson		SOCKBUF_UNLOCK(&so->so_rcv);
45011819Sjulian	return (0);
45111819Sjulian}
452