2 * Copyright (c) 1984, 1985, 1986, 1987, 1993
3 * The Regents of the University of California.
4 * Copyright (c) 2004-2009 Robert N. M. Watson
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * Copyright (c) 1995, Mike Mitchell
32 * All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 #include <sys/cdefs.h>
66 __FBSDID("$FreeBSD$");
68 #include <sys/param.h>
70 #include <sys/malloc.h>
72 #include <sys/mutex.h>
74 #include <sys/protosw.h>
75 #include <sys/signalvar.h>
76 #include <sys/socket.h>
77 #include <sys/socketvar.h>
79 #include <sys/systm.h>
81 #include <net/route.h>
82 #include <netinet/tcp_fsm.h>
84 #include <netipx/ipx.h>
85 #include <netipx/ipx_pcb.h>
86 #include <netipx/ipx_var.h>
87 #include <netipx/spx.h>
88 #include <netipx/spx_debug.h>
89 #include <netipx/spx_timer.h>
90 #include <netipx/spx_var.h>
92 static int spx_use_delack = 0;
93 static int spxrexmtthresh = 3;
96 spx_insque(struct spx_q *element, struct spx_q *head)
99 element->si_next = head->si_next;
100 element->si_prev = head;
101 head->si_next = element;
102 element->si_next->si_prev = element;
106 spx_remque(struct spx_q *element)
109 element->si_next->si_prev = element->si_prev;
110 element->si_prev->si_next = element->si_next;
111 element->si_prev = NULL;
115 * Flesh pending queued segments on SPX close.
118 spx_reass_flush(struct spxpcb *cb)
124 while (s != &(cb->s_q)) {
133 * Initialize SPX segment reassembly queue on SPX socket open.
136 spx_reass_init(struct spxpcb *cb)
139 cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
143 * This is structurally similar to the tcp reassembly routine but its
144 * function is somewhat different: it merely queues packets up, and
145 * suppresses duplicates.
148 spx_reass(struct spxpcb *cb, struct spx *si)
152 struct socket *so = cb->s_ipxpcb->ipxp_socket;
153 char packetp = cb->s_flags & SF_HI;
157 IPX_LOCK_ASSERT(cb->s_ipxpcb);
163 * Update our news from them.
165 if (si->si_cc & SPX_SA)
166 cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW);
167 if (SSEQ_GT(si->si_alo, cb->s_ralo))
168 cb->s_flags |= SF_WIN;
169 if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
170 if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) {
171 spxstat.spxs_rcvdupack++;
174 * If this is a completely duplicate ack and other
175 * conditions hold, we assume a packet has been
176 * dropped and retransmit it exactly as in
179 if (si->si_ack != cb->s_rack ||
180 si->si_alo != cb->s_ralo)
182 else if (++cb->s_dupacks == spxrexmtthresh) {
183 u_short onxt = cb->s_snxt;
184 int cwnd = cb->s_cwnd;
186 cb->s_snxt = si->si_ack;
188 cb->s_force = 1 + SPXT_REXMT;
189 spx_output(cb, NULL);
190 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
192 if (cwnd >= 4 * CUNIT)
193 cb->s_cwnd = cwnd / 2;
194 if (SSEQ_GT(onxt, cb->s_snxt))
205 * If our correspondent acknowledges data we haven't sent TCP would
206 * drop the packet after acking. We'll be a little more permissive.
208 if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
209 spxstat.spxs_rcvacktoomuch++;
210 si->si_ack = cb->s_smax + 1;
212 spxstat.spxs_rcvackpack++;
215 * If transmit timer is running and timed sequence number was acked,
216 * update smoothed round trip time. See discussion of algorithm in
219 if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
220 spxstat.spxs_rttupdated++;
221 if (cb->s_srtt != 0) {
223 delta = cb->s_rtt - (cb->s_srtt >> 3);
224 if ((cb->s_srtt += delta) <= 0)
228 delta -= (cb->s_rttvar >> 2);
229 if ((cb->s_rttvar += delta) <= 0)
233 * No rtt measurement yet.
235 cb->s_srtt = cb->s_rtt << 3;
236 cb->s_rttvar = cb->s_rtt << 1;
240 SPXT_RANGESET(cb->s_rxtcur,
241 ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
242 SPXTV_MIN, SPXTV_REXMTMAX);
246 * If all outstanding data is acked, stop retransmit timer and
247 * remember to restart (more output or persist). If there is more
248 * data to be acked, restart retransmit timer, using current
249 * (possibly backed-off) value;
251 if (si->si_ack == cb->s_smax + 1) {
252 cb->s_timer[SPXT_REXMT] = 0;
253 cb->s_flags |= SF_RXT;
254 } else if (cb->s_timer[SPXT_PERSIST] == 0)
255 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
258 * When new data is acked, open the congestion window. If the window
259 * gives us less than ssthresh packets in flight, open exponentially
260 * (maxseg at a time). Otherwise open linearly (maxseg^2 / cwnd at a
264 if (cb->s_cwnd > cb->s_ssthresh)
265 incr = max(incr * incr / cb->s_cwnd, 1);
266 cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
269 * Trim Acked data from output queue.
271 SOCKBUF_LOCK(&so->so_snd);
272 while ((m = so->so_snd.sb_mb) != NULL) {
273 if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack))
274 sbdroprecord_locked(&so->so_snd);
278 sowwakeup_locked(so);
279 cb->s_rack = si->si_ack;
281 if (SSEQ_LT(cb->s_snxt, cb->s_rack))
282 cb->s_snxt = cb->s_rack;
283 if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq &&
284 (SSEQ_LT(cb->s_swl2, si->si_ack))) ||
285 (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) {
286 /* keep track of pure window updates */
287 if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack
288 && SSEQ_LT(cb->s_ralo, si->si_alo)) {
289 spxstat.spxs_rcvwinupd++;
290 spxstat.spxs_rcvdupack--;
292 cb->s_ralo = si->si_alo;
293 cb->s_swl1 = si->si_seq;
294 cb->s_swl2 = si->si_ack;
295 cb->s_swnd = (1 + si->si_alo - si->si_ack);
296 if (cb->s_swnd > cb->s_smxw)
297 cb->s_smxw = cb->s_swnd;
298 cb->s_flags |= SF_WIN;
302 * If this packet number is higher than that which we have allocated
303 * refuse it, unless urgent.
305 if (SSEQ_GT(si->si_seq, cb->s_alo)) {
306 if (si->si_cc & SPX_SP) {
307 spxstat.spxs_rcvwinprobe++;
310 spxstat.spxs_rcvpackafterwin++;
311 if (si->si_cc & SPX_OB) {
312 if (SSEQ_GT(si->si_seq, cb->s_alo + 60))
313 return (1); /* else queue this packet; */
317 * XXXRW: This is broken on at least one count:
318 * spx_close() will free the ipxp and related parts,
319 * which are then touched by spx_input() after the
320 * return from spx_reass().
322 /*struct socket *so = cb->s_ipxpcb->ipxp_socket;
323 if (so->so_state && SS_NOFDREF) {
334 * If this is a system packet, we don't need to queue it up, and
335 * won't update acknowledge #.
337 if (si->si_cc & SPX_SP)
341 * We have already seen this packet, so drop.
343 if (SSEQ_LT(si->si_seq, cb->s_ack)) {
345 spxstat.spxs_rcvduppack++;
346 if (si->si_seq == cb->s_ack - 1)
352 * Loop through all packets queued up to insert in appropriate
355 for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
356 if (si->si_seq == SI(q)->si_seq) {
357 spxstat.spxs_rcvduppack++;
360 if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) {
361 spxstat.spxs_rcvoopack++;
365 spx_insque((struct spx_q *)si, q->si_prev);
368 * If this packet is urgent, inform process
370 if (si->si_cc & SPX_OB) {
371 cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
373 cb->s_oobflags |= SF_IOOB;
376 #define SPINC sizeof(struct spxhdr)
377 SOCKBUF_LOCK(&so->so_rcv);
380 * Loop through all packets queued up to update acknowledge number,
381 * and present all acknowledged data to user; if in packet interface
382 * mode, show packet headers.
384 for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) {
385 if (SI(q)->si_seq == cb->s_ack) {
388 if (SI(q)->si_cc & SPX_OB) {
389 cb->s_oobflags &= ~SF_IOOB;
390 if (so->so_rcv.sb_cc)
391 so->so_oobmark = so->so_rcv.sb_cc;
393 so->so_rcv.sb_state |= SBS_RCVATMARK;
396 spx_remque(q->si_next);
398 spxstat.spxs_rcvpack++;
400 if (cb->s_flags2 & SF_NEWCALL) {
401 struct spxhdr *sp = mtod(m, struct spxhdr *);
402 u_char dt = sp->spx_dt;
404 if (dt != cb->s_rhdr.spx_dt) {
406 m_getclr(M_DONTWAIT, MT_CONTROL);
411 cb->s_rhdr.spx_dt = dt;
412 mm->m_len = 5; /*XXX*/
415 *(u_char *)(&s[2]) = dt;
416 sbappend_locked(&so->so_rcv, mm);
419 if (sp->spx_cc & SPX_OB) {
420 MCHTYPE(m, MT_OOBDATA);
423 so->so_rcv.sb_state &= ~SBS_RCVATMARK;
428 m->m_pkthdr.len -= SPINC;
430 if ((sp->spx_cc & SPX_EM) || packetp) {
431 sbappendrecord_locked(&so->so_rcv, m);
434 sbappend_locked(&so->so_rcv, m);
438 sbappendrecord_locked(&so->so_rcv, m);
440 cb->s_rhdr = *mtod(m, struct spxhdr *);
443 m->m_pkthdr.len -= SPINC;
444 sbappend_locked(&so->so_rcv, m);
450 sorwakeup_locked(so);
452 SOCKBUF_UNLOCK(&so->so_rcv);