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