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