]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netns/spp_usrreq.c
2178f9a1966cb29fcc5984505c145a812f428bdd
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1984, 1985, 1986, 1987, 1993
24 * The Regents of the University of California. All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * @(#)spp_usrreq.c 8.1 (Berkeley) 6/10/93
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/malloc.h>
61 #include <sys/protosw.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/errno.h>
68 #include <net/route.h>
69 #include <netinet/tcp_fsm.h>
72 #include <netns/ns_pcb.h>
73 #include <netns/idp.h>
74 #include <netns/idp_var.h>
75 #include <netns/ns_error.h>
77 #include <netns/spidp.h>
78 #include <netns/spp_timer.h>
79 #include <netns/spp_var.h>
80 #include <netns/spp_debug.h>
83 * SP protocol implementation.
88 spp_iss
= 1; /* WRONG !! should fish it out of TODR */
90 struct spidp spp_savesi
;
92 extern int sppconsdebug
;
94 int spp_use_delack
= 0;
95 u_short spp_newchecks
[50];
99 register struct mbuf
*m
;
100 register struct nspcb
*nsp
;
102 register struct sppcb
*cb
;
103 register struct spidp
*si
= mtod(m
, struct spidp
*);
104 register struct socket
*so
;
109 sppstat
.spps_rcvtotal
++;
111 panic("No nspcb in spp_input\n");
116 if (cb
== 0) goto bad
;
118 if (m
->m_len
< sizeof(*si
)) {
119 if ((m
= m_pullup(m
, sizeof(*si
))) == 0) {
120 sppstat
.spps_rcvshort
++;
123 si
= mtod(m
, struct spidp
*);
125 si
->si_seq
= ntohs(si
->si_seq
);
126 si
->si_ack
= ntohs(si
->si_ack
);
127 si
->si_alo
= ntohs(si
->si_alo
);
129 so
= nsp
->nsp_socket
;
130 if (so
->so_options
& SO_DEBUG
|| traceallspps
) {
131 ostate
= cb
->s_state
;
134 if (so
->so_options
& SO_ACCEPTCONN
) {
135 struct sppcb
*ocb
= cb
;
137 so
= sonewconn(so
, 0);
142 * This is ugly, but ....
144 * Mark socket as temporary until we're
145 * committed to keeping it. The code at
146 * ``drop'' and ``dropwithreset'' check the
147 * flag dropsocket to see if the temporary
148 * socket created here should be discarded.
149 * We mark the socket as discardable until
150 * we're committed to it below in TCPS_LISTEN.
153 nsp
= (struct nspcb
*)so
->so_pcb
;
154 nsp
->nsp_laddr
= si
->si_dna
;
156 cb
->s_mtu
= ocb
->s_mtu
; /* preserve sockopts */
157 cb
->s_flags
= ocb
->s_flags
; /* preserve sockopts */
158 cb
->s_flags2
= ocb
->s_flags2
; /* preserve sockopts */
159 cb
->s_state
= TCPS_LISTEN
;
163 * Packet received on connection.
164 * reset idle time and keep-alive timer;
167 cb
->s_timer
[SPPT_KEEP
] = SPPTV_KEEP
;
169 switch (cb
->s_state
) {
173 register struct sockaddr_ns
*sns
;
174 struct ns_addr laddr
;
177 * If somebody here was carying on a conversation
178 * and went away, and his pen pal thinks he can
179 * still talk, we get the misdirected packet.
181 if (spp_hardnosed
&& (si
->si_did
!= 0 || si
->si_seq
!= 0)) {
185 am
= m_get(M_DONTWAIT
, MT_SONAME
);
188 am
->m_len
= sizeof (struct sockaddr_ns
);
189 sns
= mtod(am
, struct sockaddr_ns
*);
190 sns
->sns_len
= sizeof(*sns
);
191 sns
->sns_family
= AF_NS
;
192 sns
->sns_addr
= si
->si_sna
;
193 laddr
= nsp
->nsp_laddr
;
194 if (ns_nullhost(laddr
))
195 nsp
->nsp_laddr
= si
->si_dna
;
196 if (ns_pcbconnect(nsp
, am
)) {
197 nsp
->nsp_laddr
= laddr
;
204 dropsocket
= 0; /* committed to socket */
205 cb
->s_did
= si
->si_sid
;
206 cb
->s_rack
= si
->si_ack
;
207 cb
->s_ralo
= si
->si_alo
;
208 #define THREEWAYSHAKE
210 cb
->s_state
= TCPS_SYN_RECEIVED
;
211 cb
->s_force
= 1 + SPPT_KEEP
;
212 sppstat
.spps_accepts
++;
213 cb
->s_timer
[SPPT_KEEP
] = SPPTV_KEEP
;
217 * This state means that we have heard a response
218 * to our acceptance of their connection
219 * It is probably logically unnecessary in this
222 case TCPS_SYN_RECEIVED
: {
223 if (si
->si_did
!=cb
->s_sid
) {
228 nsp
->nsp_fport
= si
->si_sport
;
229 cb
->s_timer
[SPPT_REXMT
] = 0;
230 cb
->s_timer
[SPPT_KEEP
] = SPPTV_KEEP
;
232 cb
->s_state
= TCPS_ESTABLISHED
;
233 sppstat
.spps_accepts
++;
238 * This state means that we have gotten a response
239 * to our attempt to establish a connection.
240 * We fill in the data from the other side,
241 * telling us which port to respond to, instead of the well-
242 * known one we might have sent to in the first place.
243 * We also require that this is a response to our
247 if (si
->si_did
!=cb
->s_sid
) {
251 sppstat
.spps_connects
++;
252 cb
->s_did
= si
->si_sid
;
253 cb
->s_rack
= si
->si_ack
;
254 cb
->s_ralo
= si
->si_alo
;
255 cb
->s_dport
= nsp
->nsp_fport
= si
->si_sport
;
256 cb
->s_timer
[SPPT_REXMT
] = 0;
257 cb
->s_flags
|= SF_ACKNOW
;
259 cb
->s_state
= TCPS_ESTABLISHED
;
260 /* Use roundtrip time of connection request for initial rtt */
262 cb
->s_srtt
= cb
->s_rtt
<< 3;
263 cb
->s_rttvar
= cb
->s_rtt
<< 1;
264 SPPT_RANGESET(cb
->s_rxtcur
,
265 ((cb
->s_srtt
>> 2) + cb
->s_rttvar
) >> 1,
266 SPPTV_MIN
, SPPTV_REXMTMAX
);
270 if (so
->so_options
& SO_DEBUG
|| traceallspps
)
271 spp_trace(SA_INPUT
, (u_char
)ostate
, cb
, &spp_savesi
, 0);
273 m
->m_len
-= sizeof (struct idp
);
274 m
->m_pkthdr
.len
-= sizeof (struct idp
);
275 m
->m_data
+= sizeof (struct idp
);
277 if (spp_reass(cb
, si
)) {
280 if (cb
->s_force
|| (cb
->s_flags
& (SF_ACKNOW
|SF_WIN
|SF_RXT
)))
281 (void) spp_output(cb
, (struct mbuf
*)0);
282 cb
->s_flags
&= ~(SF_WIN
|SF_RXT
);
288 si
->si_seq
= ntohs(si
->si_seq
);
289 si
->si_ack
= ntohs(si
->si_ack
);
290 si
->si_alo
= ntohs(si
->si_alo
);
291 ns_error(dtom(si
), NS_ERR_NOSOCK
, 0);
292 if (cb
->s_nspcb
->nsp_socket
->so_options
& SO_DEBUG
|| traceallspps
)
293 spp_trace(SA_DROP
, (u_char
)ostate
, cb
, &spp_savesi
, 0);
298 if (cb
== 0 || cb
->s_nspcb
->nsp_socket
->so_options
& SO_DEBUG
||
300 spp_trace(SA_DROP
, (u_char
)ostate
, cb
, &spp_savesi
, 0);
304 int spprexmtthresh
= 3;
307 * This is structurally similar to the tcp reassembly routine
308 * but its function is somewhat different: It merely queues
309 * packets up, and suppresses duplicates.
312 register struct sppcb
*cb
;
313 register struct spidp
*si
;
315 register struct spidp_q
*q
;
316 register struct mbuf
*m
;
317 register struct socket
*so
= cb
->s_nspcb
->nsp_socket
;
318 char packetp
= cb
->s_flags
& SF_HI
;
325 * Update our news from them.
327 if (si
->si_cc
& SP_SA
)
328 cb
->s_flags
|= (spp_use_delack
? SF_DELACK
: SF_ACKNOW
);
329 if (SSEQ_GT(si
->si_alo
, cb
->s_ralo
))
330 cb
->s_flags
|= SF_WIN
;
331 if (SSEQ_LEQ(si
->si_ack
, cb
->s_rack
)) {
332 if ((si
->si_cc
& SP_SP
) && cb
->s_rack
!= (cb
->s_smax
+ 1)) {
333 sppstat
.spps_rcvdupack
++;
335 * If this is a completely duplicate ack
336 * and other conditions hold, we assume
337 * a packet has been dropped and retransmit
338 * it exactly as in tcp_input().
340 if (si
->si_ack
!= cb
->s_rack
||
341 si
->si_alo
!= cb
->s_ralo
)
343 else if (++cb
->s_dupacks
== spprexmtthresh
) {
344 u_short onxt
= cb
->s_snxt
;
345 int cwnd
= cb
->s_cwnd
;
347 cb
->s_snxt
= si
->si_ack
;
349 cb
->s_force
= 1 + SPPT_REXMT
;
350 (void) spp_output(cb
, (struct mbuf
*)0);
351 cb
->s_timer
[SPPT_REXMT
] = cb
->s_rxtcur
;
353 if (cwnd
>= 4 * CUNIT
)
354 cb
->s_cwnd
= cwnd
/ 2;
355 if (SSEQ_GT(onxt
, cb
->s_snxt
))
365 * If our correspondent acknowledges data we haven't sent
366 * TCP would drop the packet after acking. We'll be a little
369 if (SSEQ_GT(si
->si_ack
, (cb
->s_smax
+ 1))) {
370 sppstat
.spps_rcvacktoomuch
++;
371 si
->si_ack
= cb
->s_smax
+ 1;
373 sppstat
.spps_rcvackpack
++;
375 * If transmit timer is running and timed sequence
376 * number was acked, update smoothed round trip time.
377 * See discussion of algorithm in tcp_input.c
379 if (cb
->s_rtt
&& SSEQ_GT(si
->si_ack
, cb
->s_rtseq
)) {
380 sppstat
.spps_rttupdated
++;
381 if (cb
->s_srtt
!= 0) {
382 register short delta
;
383 delta
= cb
->s_rtt
- (cb
->s_srtt
>> 3);
384 if ((cb
->s_srtt
+= delta
) <= 0)
388 delta
-= (cb
->s_rttvar
>> 2);
389 if ((cb
->s_rttvar
+= delta
) <= 0)
393 * No rtt measurement yet
395 cb
->s_srtt
= cb
->s_rtt
<< 3;
396 cb
->s_rttvar
= cb
->s_rtt
<< 1;
400 SPPT_RANGESET(cb
->s_rxtcur
,
401 ((cb
->s_srtt
>> 2) + cb
->s_rttvar
) >> 1,
402 SPPTV_MIN
, SPPTV_REXMTMAX
);
405 * If all outstanding data is acked, stop retransmit
406 * timer and remember to restart (more output or persist).
407 * If there is more data to be acked, restart retransmit
408 * timer, using current (possibly backed-off) value;
410 if (si
->si_ack
== cb
->s_smax
+ 1) {
411 cb
->s_timer
[SPPT_REXMT
] = 0;
412 cb
->s_flags
|= SF_RXT
;
413 } else if (cb
->s_timer
[SPPT_PERSIST
] == 0)
414 cb
->s_timer
[SPPT_REXMT
] = cb
->s_rxtcur
;
416 * When new data is acked, open the congestion window.
417 * If the window gives us less than ssthresh packets
418 * in flight, open exponentially (maxseg at a time).
419 * Otherwise open linearly (maxseg^2 / cwnd at a time).
422 if (cb
->s_cwnd
> cb
->s_ssthresh
)
423 incr
= max(incr
* incr
/ cb
->s_cwnd
, 1);
424 cb
->s_cwnd
= min(cb
->s_cwnd
+ incr
, cb
->s_cwmx
);
426 * Trim Acked data from output queue.
428 while ((m
= so
->so_snd
.sb_mb
) != NULL
) {
429 if (SSEQ_LT((mtod(m
, struct spidp
*))->si_seq
, si
->si_ack
))
430 sbdroprecord(&so
->so_snd
);
435 cb
->s_rack
= si
->si_ack
;
437 if (SSEQ_LT(cb
->s_snxt
, cb
->s_rack
))
438 cb
->s_snxt
= cb
->s_rack
;
439 if (SSEQ_LT(cb
->s_swl1
, si
->si_seq
) || cb
->s_swl1
== si
->si_seq
&&
440 (SSEQ_LT(cb
->s_swl2
, si
->si_ack
) ||
441 cb
->s_swl2
== si
->si_ack
&& SSEQ_LT(cb
->s_ralo
, si
->si_alo
))) {
442 /* keep track of pure window updates */
443 if ((si
->si_cc
& SP_SP
) && cb
->s_swl2
== si
->si_ack
444 && SSEQ_LT(cb
->s_ralo
, si
->si_alo
)) {
445 sppstat
.spps_rcvwinupd
++;
446 sppstat
.spps_rcvdupack
--;
448 cb
->s_ralo
= si
->si_alo
;
449 cb
->s_swl1
= si
->si_seq
;
450 cb
->s_swl2
= si
->si_ack
;
451 cb
->s_swnd
= (1 + si
->si_alo
- si
->si_ack
);
452 if (cb
->s_swnd
> cb
->s_smxw
)
453 cb
->s_smxw
= cb
->s_swnd
;
454 cb
->s_flags
|= SF_WIN
;
457 * If this packet number is higher than that which
458 * we have allocated refuse it, unless urgent
460 if (SSEQ_GT(si
->si_seq
, cb
->s_alo
)) {
461 if (si
->si_cc
& SP_SP
) {
462 sppstat
.spps_rcvwinprobe
++;
465 sppstat
.spps_rcvpackafterwin
++;
466 if (si
->si_cc
& SP_OB
) {
467 if (SSEQ_GT(si
->si_seq
, cb
->s_alo
+ 60)) {
468 ns_error(dtom(si
), NS_ERR_FULLUP
, 0);
470 } /* else queue this packet; */
472 /*register struct socket *so = cb->s_nspcb->nsp_socket;
473 if (so->so_state && SS_NOFDREF) {
474 ns_error(dtom(si), NS_ERR_NOSOCK, 0);
479 ns_error(dtom(si
), NS_ERR_FULLUP
, 0);
484 * If this is a system packet, we don't need to
485 * queue it up, and won't update acknowledge #
487 if (si
->si_cc
& SP_SP
) {
491 * We have already seen this packet, so drop.
493 if (SSEQ_LT(si
->si_seq
, cb
->s_ack
)) {
495 sppstat
.spps_rcvduppack
++;
496 if (si
->si_seq
== cb
->s_ack
- 1)
501 * Loop through all packets queued up to insert in
502 * appropriate sequence.
504 for (q
= cb
->s_q
.si_next
; q
!=&cb
->s_q
; q
= q
->si_next
) {
505 if (si
->si_seq
== SI(q
)->si_seq
) {
506 sppstat
.spps_rcvduppack
++;
509 if (SSEQ_LT(si
->si_seq
, SI(q
)->si_seq
)) {
510 sppstat
.spps_rcvoopack
++;
514 insque(si
, q
->si_prev
);
516 * If this packet is urgent, inform process
518 if (si
->si_cc
& SP_OB
) {
519 cb
->s_iobc
= ((char *)si
)[1 + sizeof(*si
)];
521 cb
->s_oobflags
|= SF_IOOB
;
524 #define SPINC sizeof(struct sphdr)
526 * Loop through all packets queued up to update acknowledge
527 * number, and present all acknowledged data to user;
528 * If in packet interface mode, show packet headers.
530 for (q
= cb
->s_q
.si_next
; q
!=&cb
->s_q
; q
= q
->si_next
) {
531 if (SI(q
)->si_seq
== cb
->s_ack
) {
534 if (SI(q
)->si_cc
& SP_OB
) {
535 cb
->s_oobflags
&= ~SF_IOOB
;
536 if (so
->so_rcv
.sb_cc
)
537 so
->so_oobmark
= so
->so_rcv
.sb_cc
;
539 so
->so_state
|= SS_RCVATMARK
;
540 postevent(so
, 0, EV_OOB
);
545 sppstat
.spps_rcvpack
++;
547 if (cb
->s_flags2
& SF_NEWCALL
) {
548 struct sphdr
*sp
= mtod(m
, struct sphdr
*);
549 u_char dt
= sp
->sp_dt
;
551 if (dt
!= cb
->s_rhdr
.sp_dt
) {
553 m_getclr(M_DONTWAIT
, MT_CONTROL
);
558 cb
->s_rhdr
.sp_dt
= dt
;
559 mm
->m_len
= 5; /*XXX*/
562 *(u_char
*)(&s
[2]) = dt
;
563 sbappend(&so
->so_rcv
, mm
);
566 if (sp
->sp_cc
& SP_OB
) {
567 MCHTYPE(m
, MT_OOBDATA
);
570 so
->so_state
&= ~SS_RCVATMARK
;
575 m
->m_pkthdr
.len
-= SPINC
;
577 if ((sp
->sp_cc
& SP_EM
) || packetp
) {
578 sbappendrecord(&so
->so_rcv
, m
);
581 sbappend(&so
->so_rcv
, m
);
585 sbappendrecord(&so
->so_rcv
, m
);
587 cb
->s_rhdr
= *mtod(m
, struct sphdr
*);
590 m
->m_pkthdr
.len
-= SPINC
;
591 sbappend(&so
->so_rcv
, m
);
596 if (wakeup
) sorwakeup(so
);
600 spp_ctlinput(cmd
, arg
)
605 extern u_char nsctlerrmap
[];
606 extern spp_abort(), spp_quench();
607 extern struct nspcb
*idp_drop();
608 struct ns_errp
*errp
;
610 struct sockaddr_ns
*sns
;
613 if (cmd
< 0 || cmd
> PRC_NCMDS
)
615 type
= NS_ERR_UNREACH_HOST
;
624 case PRC_HOSTUNREACH
:
625 sns
= (struct sockaddr_ns
*)arg
;
626 if (sns
->sns_family
!= AF_NS
)
632 errp
= (struct ns_errp
*)arg
;
633 na
= &errp
->ns_err_idp
.idp_dna
;
634 type
= errp
->ns_err_num
;
635 type
= ntohs((u_short
)type
);
639 case NS_ERR_UNREACH_HOST
:
640 ns_pcbnotify(na
, (int)nsctlerrmap
[cmd
], spp_abort
, (long) 0);
645 nsp
= ns_pcblookup(na
, errp
->ns_err_idp
.idp_sna
.x_port
,
649 (void) spp_drop((struct sppcb
*)nsp
->nsp_pcb
,
650 (int)nsctlerrmap
[cmd
]);
652 (void) idp_drop(nsp
, (int)nsctlerrmap
[cmd
]);
657 ns_pcbnotify(na
, 0, spp_quench
, (long) 0);
661 * When a source quench is received, close congestion window
662 * to one packet. We will gradually open it again as we proceed.
667 struct sppcb
*cb
= nstosppcb(nsp
);
676 register struct nspcb
*nsp
;
678 register struct sppcb
*cb
= (struct sppcb
*)(nsp
->nsp_pcb
);
679 register struct mbuf
*m
;
680 register struct spidp
*si
;
684 struct mbuf
*firstbad
, *m0
;
688 * The notification that we have sent
689 * too much is bad news -- we will
690 * have to go through queued up so far
691 * splitting ones which are too big and
692 * reassigning sequence numbers and checksums.
693 * we should then retransmit all packets from
694 * one above the offending packet to the last one
695 * we had sent (or our allocation)
696 * then the offending one so that the any queued
697 * data at our destination will be discarded.
699 ep
= (struct ns_errp
*)nsp
->nsp_notify_param
;
700 sb
= &nsp
->nsp_socket
->so_snd
;
701 cb
->s_mtu
= ep
->ns_err_param
;
702 badseq
= SI(&ep
->ns_err_idp
)->si_seq
;
703 for (m
= sb
->sb_mb
; m
; m
= m
->m_act
) {
704 si
= mtod(m
, struct spidp
*);
705 if (si
->si_seq
== badseq
)
711 /* calculate length */
712 for (m0
= m
, len
= 0; m
; m
= m
->m_next
)
714 if (len
> cb
->s_mtu
) {
723 register struct sppcb
*cb
;
726 struct socket
*so
= cb
->s_nspcb
->nsp_socket
;
727 register struct mbuf
*m
;
728 register struct spidp
*si
= (struct spidp
*) 0;
729 register struct sockbuf
*sb
= &so
->so_snd
;
730 int len
= 0, win
, rcv_win
;
731 short span
, off
, recordp
= 0;
733 int error
= 0, sendalot
;
744 * Make sure that packet isn't too big.
746 for (m
= m0
; m
; m
= m
->m_next
) {
749 if (m
->m_flags
& M_EOR
)
752 datalen
= (cb
->s_flags
& SF_HO
) ?
753 len
- sizeof (struct sphdr
) : len
;
755 if (cb
->s_flags
& SF_PI
) {
759 int oldEM
= cb
->s_cc
& SP_EM
;
764 * Here we are only being called
765 * from usrreq(), so it is OK to
768 m
= m_copym(m0
, 0, mtu
, M_WAIT
);
769 if (cb
->s_flags
& SF_NEWCALL
) {
773 mm
->m_flags
&= ~M_EOR
;
777 error
= spp_output(cb
, m
);
790 * Force length even, by adding a "garbage byte" if
795 if (M_TRAILINGSPACE(m
) >= 1)
798 struct mbuf
*m1
= m_get(M_DONTWAIT
, MT_DATA
);
805 *(mtod(m1
, u_char
*)) = 0;
809 m
= m_gethdr(M_DONTWAIT
, MT_HEADER
);
815 * Fill in mbuf with extended SP header
816 * and addresses and length put into network format.
818 MH_ALIGN(m
, sizeof (struct spidp
));
819 m
->m_len
= sizeof (struct spidp
);
821 si
= mtod(m
, struct spidp
*);
822 si
->si_i
= *cb
->s_idp
;
823 si
->si_s
= cb
->s_shdr
;
824 if ((cb
->s_flags
& SF_PI
) && (cb
->s_flags
& SF_HO
)) {
825 register struct sphdr
*sh
;
826 if (m0
->m_len
< sizeof (*sh
)) {
827 if((m0
= m_pullup(m0
, sizeof(*sh
))) == NULL
) {
834 sh
= mtod(m0
, struct sphdr
*);
835 si
->si_dt
= sh
->sp_dt
;
836 si
->si_cc
|= sh
->sp_cc
& SP_EM
;
837 m0
->m_len
-= sizeof (*sh
);
838 m0
->m_data
+= sizeof (*sh
);
842 if ((cb
->s_flags2
& SF_NEWCALL
) && recordp
) {
846 if (cb
->s_oobflags
& SF_SOOB
) {
849 * make sure OB packets convey exactly 1 byte.
850 * If the packet is 1 byte or larger, we
851 * have already guaranted there to be at least
852 * one garbage byte for the checksum, and
853 * extra bytes shouldn't hurt!
855 if (len
> sizeof(*si
)) {
857 len
= (1 + sizeof(*si
));
860 si
->si_len
= htons((u_short
)len
);
861 m
->m_pkthdr
.len
= ((len
- 1) | 1) + 1;
863 * queue stuff up for output
865 sbappendrecord(sb
, m
);
869 idle
= (cb
->s_smax
== (cb
->s_rack
- 1));
873 off
= cb
->s_snxt
- cb
->s_rack
;
874 win
= min(cb
->s_swnd
, (cb
->s_cwnd
/CUNIT
));
877 * If in persist timeout with window of 0, send a probe.
878 * Otherwise, if window is small but nonzero
879 * and timer expired, send what we can and go into
882 if (cb
->s_force
== 1 + SPPT_PERSIST
) {
884 cb
->s_timer
[SPPT_PERSIST
] = 0;
888 span
= cb
->s_seq
- cb
->s_rack
;
889 len
= min(span
, win
) - off
;
893 * Window shrank after we went into it.
894 * If window shrank to 0, cancel pending
895 * restransmission and pull s_snxt back
896 * to (closed) window. We will enter persist
897 * state below. If the widndow didn't close completely,
898 * just wait for an ACK.
902 cb
->s_timer
[SPPT_REXMT
] = 0;
903 cb
->s_snxt
= cb
->s_rack
;
908 rcv_win
= sbspace(&so
->so_rcv
);
911 * Send if we owe peer an ACK.
913 if (cb
->s_oobflags
& SF_SOOB
) {
915 * must transmit this out of band packet
917 cb
->s_oobflags
&= ~ SF_SOOB
;
919 sppstat
.spps_sndurg
++;
922 if (cb
->s_flags
& SF_ACKNOW
)
924 if (cb
->s_state
< TCPS_ESTABLISHED
)
927 * Silly window can't happen in spp.
928 * Code from tcp deleted.
933 * Compare available window to amount of window
934 * known to peer (as advertised window less
935 * next expected input.) If the difference is at least two
936 * packets or at least 35% of the mximum possible window,
937 * then want to send a window update to peer.
940 u_short delta
= 1 + cb
->s_alo
- cb
->s_ack
;
941 int adv
= rcv_win
- (delta
* cb
->s_mtu
);
943 if ((so
->so_rcv
.sb_cc
== 0 && adv
>= (2 * cb
->s_mtu
)) ||
944 (100 * adv
/ so
->so_rcv
.sb_hiwat
>= 35)) {
945 sppstat
.spps_sndwinup
++;
946 cb
->s_flags
|= SF_ACKNOW
;
952 * Many comments from tcp_output.c are appropriate here
954 * If send window is too small, there is data to transmit, and no
955 * retransmit or persist is pending, then go to persist state.
956 * If nothing happens soon, send when timer expires:
957 * if window is nonzero, transmit what we can,
958 * otherwise send a probe.
960 if (so
->so_snd
.sb_cc
&& cb
->s_timer
[SPPT_REXMT
] == 0 &&
961 cb
->s_timer
[SPPT_PERSIST
] == 0) {
966 * No reason to send a packet, just return.
973 * Find requested packet.
977 cb
->s_want
= cb
->s_snxt
;
978 for (m
= sb
->sb_mb
; m
; m
= m
->m_act
) {
979 si
= mtod(m
, struct spidp
*);
980 if (SSEQ_LEQ(cb
->s_snxt
, si
->si_seq
))
985 if (si
->si_seq
== cb
->s_snxt
)
988 sppstat
.spps_sndvoid
++, si
= 0;
996 alo
= cb
->s_ack
- 1 + (rcv_win
/ ((short)cb
->s_mtu
));
997 if (SSEQ_LT(alo
, cb
->s_alo
))
1002 * must make a copy of this packet for
1003 * idp_output to monkey with
1005 m
= m_copy(dtom(si
), 0, (int)M_COPYALL
);
1009 si
= mtod(m
, struct spidp
*);
1010 if (SSEQ_LT(si
->si_seq
, cb
->s_smax
))
1011 sppstat
.spps_sndrexmitpack
++;
1013 sppstat
.spps_sndpack
++;
1014 } else if (cb
->s_force
|| cb
->s_flags
& SF_ACKNOW
) {
1016 * Must send an acknowledgement or a probe
1019 sppstat
.spps_sndprobe
++;
1020 if (cb
->s_flags
& SF_ACKNOW
)
1021 sppstat
.spps_sndacks
++;
1022 m
= m_gethdr(M_DONTWAIT
, MT_HEADER
);
1026 * Fill in mbuf with extended SP header
1027 * and addresses and length put into network format.
1029 MH_ALIGN(m
, sizeof (struct spidp
));
1030 m
->m_len
= sizeof (*si
);
1031 m
->m_pkthdr
.len
= sizeof (*si
);
1032 si
= mtod(m
, struct spidp
*);
1033 si
->si_i
= *cb
->s_idp
;
1034 si
->si_s
= cb
->s_shdr
;
1035 si
->si_seq
= cb
->s_smax
+ 1;
1036 si
->si_len
= htons(sizeof (*si
));
1040 if (so
->so_options
& SO_DEBUG
|| traceallspps
)
1041 spp_trace(SA_OUTPUT
, cb
->s_state
, cb
, si
, 0);
1045 * Stuff checksum and output datagram.
1047 if ((si
->si_cc
& SP_SP
) == 0) {
1048 if (cb
->s_force
!= (1 + SPPT_PERSIST
) ||
1049 cb
->s_timer
[SPPT_PERSIST
] == 0) {
1051 * If this is a new packet and we are not currently
1052 * timing anything, time this one.
1054 if (SSEQ_LT(cb
->s_smax
, si
->si_seq
)) {
1055 cb
->s_smax
= si
->si_seq
;
1056 if (cb
->s_rtt
== 0) {
1057 sppstat
.spps_segstimed
++;
1058 cb
->s_rtseq
= si
->si_seq
;
1063 * Set rexmt timer if not currently set,
1064 * Initial value for retransmit timer is smoothed
1065 * round-trip time + 2 * round-trip time variance.
1066 * Initialize shift counter which is used for backoff
1067 * of retransmit time.
1069 if (cb
->s_timer
[SPPT_REXMT
] == 0 &&
1070 cb
->s_snxt
!= cb
->s_rack
) {
1071 cb
->s_timer
[SPPT_REXMT
] = cb
->s_rxtcur
;
1072 if (cb
->s_timer
[SPPT_PERSIST
]) {
1073 cb
->s_timer
[SPPT_PERSIST
] = 0;
1077 } else if (SSEQ_LT(cb
->s_smax
, si
->si_seq
)) {
1078 cb
->s_smax
= si
->si_seq
;
1080 } else if (cb
->s_state
< TCPS_ESTABLISHED
) {
1082 cb
->s_rtt
= 1; /* Time initial handshake */
1083 if (cb
->s_timer
[SPPT_REXMT
] == 0)
1084 cb
->s_timer
[SPPT_REXMT
] = cb
->s_rxtcur
;
1088 * Do not request acks when we ack their data packets or
1089 * when we do a gratuitous window update.
1091 if (((si
->si_cc
& SP_SP
) == 0) || cb
->s_force
)
1093 si
->si_seq
= htons(si
->si_seq
);
1094 si
->si_alo
= htons(alo
);
1095 si
->si_ack
= htons(cb
->s_ack
);
1099 len
= ntohs(si
->si_len
);
1102 si
->si_sum
= ns_cksum(m
, len
);
1104 si
->si_sum
= 0xffff;
1107 if (so
->so_options
& SO_DEBUG
|| traceallspps
)
1108 spp_trace(SA_OUTPUT
, cb
->s_state
, cb
, si
, 0);
1110 if (so
->so_options
& SO_DONTROUTE
)
1111 error
= ns_output(m
, (struct route
*)0, NS_ROUTETOIF
);
1113 error
= ns_output(m
, &cb
->s_nspcb
->nsp_route
, 0);
1118 sppstat
.spps_sndtotal
++;
1120 * Data sent (as far as we can tell).
1121 * If this advertises a larger window than any other segment,
1122 * then remember the size of the advertized window.
1123 * Any pending ACK has now been sent.
1126 cb
->s_flags
&= ~(SF_ACKNOW
|SF_DELACK
);
1127 if (SSEQ_GT(alo
, cb
->s_alo
))
1135 int spp_do_persist_panics
= 0;
1138 register struct sppcb
*cb
;
1140 register t
= ((cb
->s_srtt
>> 2) + cb
->s_rttvar
) >> 1;
1141 extern int spp_backoff
[];
1143 if (cb
->s_timer
[SPPT_REXMT
] && spp_do_persist_panics
)
1144 panic("spp_output REXMT");
1146 * Start/restart persistance timer.
1148 SPPT_RANGESET(cb
->s_timer
[SPPT_PERSIST
],
1149 t
*spp_backoff
[cb
->s_rxtshift
],
1150 SPPTV_PERSMIN
, SPPTV_PERSMAX
);
1151 if (cb
->s_rxtshift
< SPP_MAXRXTSHIFT
)
1155 spp_ctloutput(req
, so
, level
, name
, value
)
1159 struct mbuf
**value
;
1161 register struct mbuf
*m
;
1162 struct nspcb
*nsp
= sotonspcb(so
);
1163 register struct sppcb
*cb
;
1164 int mask
, error
= 0;
1166 if (level
!= NSPROTO_SPP
) {
1167 /* This will have to be changed when we do more general
1168 stacking of protocols */
1169 return (idp_ctloutput(req
, so
, level
, name
, value
));
1175 cb
= nstosppcb(nsp
);
1182 m
= m_get(M_DONTWAIT
, MT_DATA
);
1187 case SO_HEADERS_ON_INPUT
:
1191 case SO_HEADERS_ON_OUTPUT
:
1194 m
->m_len
= sizeof(short);
1195 *mtod(m
, short *) = cb
->s_flags
& mask
;
1199 m
->m_len
= sizeof(u_short
);
1200 *mtod(m
, short *) = cb
->s_mtu
;
1203 case SO_LAST_HEADER
:
1204 m
->m_len
= sizeof(struct sphdr
);
1205 *mtod(m
, struct sphdr
*) = cb
->s_rhdr
;
1208 case SO_DEFAULT_HEADERS
:
1209 m
->m_len
= sizeof(struct spidp
);
1210 *mtod(m
, struct sphdr
*) = cb
->s_shdr
;
1220 if (value
== 0 || *value
== 0) {
1227 case SO_HEADERS_ON_INPUT
:
1231 case SO_HEADERS_ON_OUTPUT
:
1234 if (cb
->s_flags
& SF_PI
) {
1235 ok
= mtod(*value
, int *);
1237 cb
->s_flags
|= mask
;
1239 cb
->s_flags
&= ~mask
;
1240 } else error
= EINVAL
;
1244 cb
->s_mtu
= *(mtod(*value
, u_short
*));
1249 ok
= mtod(*value
, int *);
1251 cb
->s_flags2
|= SF_NEWCALL
;
1254 cb
->s_flags2
&= ~SF_NEWCALL
;
1260 case SO_DEFAULT_HEADERS
:
1262 register struct sphdr
*sp
1263 = mtod(*value
, struct sphdr
*);
1264 cb
->s_dt
= sp
->sp_dt
;
1265 cb
->s_cc
= sp
->sp_cc
& SP_EM
;
1280 spp_usrreq(so
, req
, m
, nam
, controlp
)
1283 struct mbuf
*m
, *nam
, *controlp
;
1285 struct nspcb
*nsp
= sotonspcb(so
);
1286 register struct sppcb
*cb
;
1288 int error
= 0, ostate
;
1290 register struct sockbuf
*sb
;
1292 if (req
== PRU_CONTROL
)
1293 return (ns_control(so
, (int)m
, (caddr_t
)nam
,
1294 (struct ifnet
*)controlp
));
1296 if (req
!= PRU_ATTACH
) {
1301 cb
= nstosppcb(nsp
);
1303 ostate
= cb
? cb
->s_state
: 0;
1312 error
= ns_pcballoc(so
, &nspcb
);
1315 if (so
->so_snd
.sb_hiwat
== 0 || so
->so_rcv
.sb_hiwat
== 0) {
1316 error
= soreserve(so
, (u_long
) 3072, (u_long
) 3072);
1320 nsp
= sotonspcb(so
);
1322 mm
= m_getclr(M_DONTWAIT
, MT_PCB
);
1329 cb
= mtod(mm
, struct sppcb
*);
1330 mm
= m_getclr(M_DONTWAIT
, MT_HEADER
);
1332 (void) m_free(dtom(m
));
1336 cb
->s_idp
= mtod(mm
, struct idp
*);
1337 cb
->s_state
= TCPS_LISTEN
;
1340 cb
->s_q
.si_next
= cb
->s_q
.si_prev
= &cb
->s_q
;
1342 cb
->s_mtu
= 576 - sizeof (struct spidp
);
1343 cb
->s_cwnd
= sbspace(sb
) * CUNIT
/ cb
->s_mtu
;
1344 cb
->s_ssthresh
= cb
->s_cwnd
;
1345 cb
->s_cwmx
= sbspace(sb
) * CUNIT
/
1346 (2 * sizeof (struct spidp
));
1347 /* Above is recomputed when connecting to account
1348 for changed buffering or mtu's */
1349 cb
->s_rtt
= SPPTV_SRTTBASE
;
1350 cb
->s_rttvar
= SPPTV_SRTTDFLT
<< 2;
1351 SPPT_RANGESET(cb
->s_rxtcur
,
1352 ((SPPTV_SRTTBASE
>> 2) + (SPPTV_SRTTDFLT
<< 2)) >> 1,
1353 SPPTV_MIN
, SPPTV_REXMTMAX
);
1354 nsp
->nsp_pcb
= (caddr_t
) cb
;
1362 if (cb
->s_state
> TCPS_LISTEN
)
1363 cb
= spp_disconnect(cb
);
1369 error
= ns_pcbbind(nsp
, nam
);
1373 if (nsp
->nsp_lport
== 0)
1374 error
= ns_pcbbind(nsp
, (struct mbuf
*)0);
1376 cb
->s_state
= TCPS_LISTEN
;
1380 * Initiate connection to peer.
1381 * Enter SYN_SENT state, and mark socket as connecting.
1382 * Start keep-alive timer, setup prototype header,
1383 * Send initial system packet requesting connection.
1386 if (nsp
->nsp_lport
== 0) {
1387 error
= ns_pcbbind(nsp
, (struct mbuf
*)0);
1391 error
= ns_pcbconnect(nsp
, nam
);
1395 sppstat
.spps_connattempt
++;
1396 cb
->s_state
= TCPS_SYN_SENT
;
1399 cb
->s_timer
[SPPT_KEEP
] = SPPTV_KEEP
;
1400 cb
->s_force
= 1 + SPPTV_KEEP
;
1402 * Other party is required to respond to
1403 * the port I send from, but he is not
1404 * required to answer from where I am sending to,
1405 * so allow wildcarding.
1406 * original port I am sending to is still saved in
1410 error
= spp_output(cb
, (struct mbuf
*) 0);
1418 * We may decide later to implement connection closing
1419 * handshaking at the spp level optionally.
1420 * here is the hook to do it:
1422 case PRU_DISCONNECT
:
1423 cb
= spp_disconnect(cb
);
1427 * Accept a connection. Essentially all the work is
1428 * done at higher levels; just return the address
1429 * of the peer, storing through addr.
1432 struct sockaddr_ns
*sns
= mtod(nam
, struct sockaddr_ns
*);
1434 nam
->m_len
= sizeof (struct sockaddr_ns
);
1435 sns
->sns_family
= AF_NS
;
1436 sns
->sns_addr
= nsp
->nsp_faddr
;
1442 cb
= spp_usrclosed(cb
);
1444 error
= spp_output(cb
, (struct mbuf
*) 0);
1448 * After a receive, possibly send acknowledgment
1449 * updating allocation.
1452 cb
->s_flags
|= SF_RVD
;
1453 (void) spp_output(cb
, (struct mbuf
*) 0);
1454 cb
->s_flags
&= ~SF_RVD
;
1458 (void) spp_drop(cb
, ECONNABORTED
);
1468 if ((cb
->s_oobflags
& SF_IOOB
) || so
->so_oobmark
||
1469 (so
->so_state
& SS_RCVATMARK
)) {
1471 *mtod(m
, caddr_t
) = cb
->s_iobc
;
1478 if (sbspace(&so
->so_snd
) < -512) {
1482 cb
->s_oobflags
|= SF_SOOB
;
1486 u_short
*p
= mtod(controlp
, u_short
*);
1488 if ((p
[0] == 5) && p
[1] == 1) { /* XXXX, for testing */
1489 cb
->s_shdr
.sp_dt
= *(u_char
*)(&p
[2]);
1495 error
= spp_output(cb
, m
);
1500 ns_setsockaddr(nsp
, nam
);
1504 ns_setpeeraddr(nsp
, nam
);
1508 cb
= spp_timers(cb
, (int)nam
);
1509 req
|= ((int)nam
) << 8;
1521 if (cb
&& (so
->so_options
& SO_DEBUG
|| traceallspps
))
1522 spp_trace(SA_USER
, (u_char
)ostate
, cb
, (struct spidp
*)0, req
);
1524 if (controlp
!= NULL
)
1532 spp_usrreq_sp(so
, req
, m
, nam
, controlp
)
1535 struct mbuf
*m
, *nam
, *controlp
;
1537 int error
= spp_usrreq(so
, req
, m
, nam
, controlp
);
1539 if (req
== PRU_ATTACH
&& error
== 0) {
1540 struct nspcb
*nsp
= sotonspcb(so
);
1541 ((struct sppcb
*)nsp
->nsp_pcb
)->s_flags
|=
1542 (SF_HI
| SF_HO
| SF_PI
);
1548 * Create template to be used to send spp packets on a connection.
1549 * Called after host entry created, fills
1550 * in a skeletal spp header (choosing connection id),
1551 * minimizing the amount of work necessary when the connection is used.
1554 register struct sppcb
*cb
;
1556 register struct nspcb
*nsp
= cb
->s_nspcb
;
1557 register struct idp
*idp
= cb
->s_idp
;
1558 register struct sockbuf
*sb
= &(nsp
->nsp_socket
->so_snd
);
1560 idp
->idp_pt
= NSPROTO_SPP
;
1561 idp
->idp_sna
= nsp
->nsp_laddr
;
1562 idp
->idp_dna
= nsp
->nsp_faddr
;
1563 cb
->s_sid
= htons(spp_iss
);
1564 spp_iss
+= SPP_ISSINCR
/2;
1566 cb
->s_cwnd
= (sbspace(sb
) * CUNIT
) / cb
->s_mtu
;
1567 cb
->s_ssthresh
= cb
->s_cwnd
; /* Try to expand fast to full complement
1569 cb
->s_cwmx
= (sbspace(sb
) * CUNIT
) / (2 * sizeof(struct spidp
));
1570 cb
->s_cwmx
= max(cb
->s_cwmx
, cb
->s_cwnd
);
1571 /* But allow for lots of little packets as well */
1575 * Close a SPIP control block:
1576 * discard spp control block itself
1577 * discard ns protocol control block
1578 * wake up any sleepers
1582 register struct sppcb
*cb
;
1584 register struct spidp_q
*s
;
1585 struct nspcb
*nsp
= cb
->s_nspcb
;
1586 struct socket
*so
= nsp
->nsp_socket
;
1587 register struct mbuf
*m
;
1589 s
= cb
->s_q
.si_next
;
1590 while (s
!= &(cb
->s_q
)) {
1592 m
= dtom(s
->si_prev
);
1596 (void) m_free(dtom(cb
->s_idp
));
1597 (void) m_free(dtom(cb
));
1599 soisdisconnected(so
);
1601 sppstat
.spps_closed
++;
1602 return ((struct sppcb
*)0);
1605 * Someday we may do level 3 handshaking
1606 * to close a connection or send a xerox style error.
1607 * For now, just close.
1611 register struct sppcb
*cb
;
1613 return (spp_close(cb
));
1617 register struct sppcb
*cb
;
1619 return (spp_close(cb
));
1622 * Drop connection, reporting
1623 * the specified error.
1627 register struct sppcb
*cb
;
1630 struct socket
*so
= cb
->s_nspcb
->nsp_socket
;
1633 * someday, in the xerox world
1634 * we will generate error protocol packets
1635 * announcing that the socket has gone away.
1637 if (TCPS_HAVERCVDSYN(cb
->s_state
)) {
1638 sppstat
.spps_drops
++;
1639 cb
->s_state
= TCPS_CLOSED
;
1640 /*(void) tcp_output(cb);*/
1642 sppstat
.spps_conndrops
++;
1643 so
->so_error
= errno
;
1644 return (spp_close(cb
));
1651 (void) spp_close((struct sppcb
*)nsp
->nsp_pcb
);
1654 int spp_backoff
[SPP_MAXRXTSHIFT
+1] =
1655 { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
1657 * Fast timeout routine for processing delayed acks
1661 register struct nspcb
*nsp
;
1662 register struct sppcb
*cb
;
1665 nsp
= nspcb
.nsp_next
;
1667 for (; nsp
!= &nspcb
; nsp
= nsp
->nsp_next
)
1668 if ((cb
= (struct sppcb
*)nsp
->nsp_pcb
) &&
1669 (cb
->s_flags
& SF_DELACK
)) {
1670 cb
->s_flags
&= ~SF_DELACK
;
1671 cb
->s_flags
|= SF_ACKNOW
;
1672 sppstat
.spps_delack
++;
1673 (void) spp_output(cb
, (struct mbuf
*) 0);
1679 * spp protocol timeout routine called every 500 ms.
1680 * Updates the timers in all active pcb's and
1681 * causes finite state machine actions if timers expire.
1685 register struct nspcb
*ip
, *ipnxt
;
1686 register struct sppcb
*cb
;
1691 * Search through tcb's and update active timers.
1693 ip
= nspcb
.nsp_next
;
1698 while (ip
!= &nspcb
) {
1700 ipnxt
= ip
->nsp_next
;
1703 for (i
= 0; i
< SPPT_NTIMERS
; i
++) {
1704 if (cb
->s_timer
[i
] && --cb
->s_timer
[i
] == 0) {
1705 (void) spp_usrreq(cb
->s_nspcb
->nsp_socket
,
1706 PRU_SLOWTIMO
, (struct mbuf
*)0,
1707 (struct mbuf
*)i
, (struct mbuf
*)0,
1709 if (ipnxt
->nsp_prev
!= ip
)
1719 spp_iss
+= SPP_ISSINCR
/PR_SLOWHZ
; /* increment iss */
1723 * SPP timer processing.
1726 spp_timers(cb
, timer
)
1727 register struct sppcb
*cb
;
1733 cb
->s_force
= 1 + timer
;
1737 * 2 MSL timeout in shutdown went off. TCP deletes connection
1741 printf("spp: SPPT_2MSL went off for no reason\n");
1742 cb
->s_timer
[timer
] = 0;
1746 * Retransmission timer went off. Message has not
1747 * been acked within retransmit interval. Back off
1748 * to a longer retransmit interval and retransmit one packet.
1751 if (++cb
->s_rxtshift
> SPP_MAXRXTSHIFT
) {
1752 cb
->s_rxtshift
= SPP_MAXRXTSHIFT
;
1753 sppstat
.spps_timeoutdrop
++;
1754 cb
= spp_drop(cb
, ETIMEDOUT
);
1757 sppstat
.spps_rexmttimeo
++;
1758 rexmt
= ((cb
->s_srtt
>> 2) + cb
->s_rttvar
) >> 1;
1759 rexmt
*= spp_backoff
[cb
->s_rxtshift
];
1760 SPPT_RANGESET(cb
->s_rxtcur
, rexmt
, SPPTV_MIN
, SPPTV_REXMTMAX
);
1761 cb
->s_timer
[SPPT_REXMT
] = cb
->s_rxtcur
;
1763 * If we have backed off fairly far, our srtt
1764 * estimate is probably bogus. Clobber it
1765 * so we'll take the next rtt measurement as our srtt;
1766 * move the current srtt into rttvar to keep the current
1767 * retransmit times until then.
1769 if (cb
->s_rxtshift
> SPP_MAXRXTSHIFT
/ 4 ) {
1770 cb
->s_rttvar
+= (cb
->s_srtt
>> 2);
1773 cb
->s_snxt
= cb
->s_rack
;
1775 * If timing a packet, stop the timer.
1779 * See very long discussion in tcp_timer.c about congestion
1780 * window and sstrhesh
1782 win
= min(cb
->s_swnd
, (cb
->s_cwnd
/CUNIT
)) / 2;
1786 cb
->s_ssthresh
= win
* CUNIT
;
1787 (void) spp_output(cb
, (struct mbuf
*) 0);
1791 * Persistance timer into zero window.
1792 * Force a probe to be sent.
1795 sppstat
.spps_persisttimeo
++;
1797 (void) spp_output(cb
, (struct mbuf
*) 0);
1801 * Keep-alive timer went off; send something
1802 * or drop connection if idle for too long.
1805 sppstat
.spps_keeptimeo
++;
1806 if (cb
->s_state
< TCPS_ESTABLISHED
)
1808 if (cb
->s_nspcb
->nsp_socket
->so_options
& SO_KEEPALIVE
) {
1809 if (cb
->s_idle
>= SPPTV_MAXIDLE
)
1811 sppstat
.spps_keepprobe
++;
1812 (void) spp_output(cb
, (struct mbuf
*) 0);
1815 cb
->s_timer
[SPPT_KEEP
] = SPPTV_KEEP
;
1818 sppstat
.spps_keepdrops
++;
1819 cb
= spp_drop(cb
, ETIMEDOUT
);
1825 int SppcbSize
= sizeof (struct sppcb
);
1826 int NspcbSize
= sizeof (struct nspcb
);