/* tcp_usrreq.c 1.14 81/10/26 */
#include "../bbnnet/net.h"
#include "../bbnnet/mbuf.h"
#include "../bbnnet/tcp.h"
#include "../bbnnet/ip.h"
#include "../bbnnet/imp.h"
#include "../bbnnet/ucb.h"
#include "../bbnnet/fsm.h"
* Search through tcb's and update active timers.
for (tp
= netcb
.n_tcb_head
; tp
!= NULL
; tp
= tp
->t_tcb_next
) {
if (tp
->t_init
!= 0 && --tp
->t_init
== 0)
tcp_usrreq(ISTIMER
, TINIT
, tp
, 0);
if (tp
->t_rexmt
!= 0 && --tp
->t_rexmt
== 0)
tcp_usrreq(ISTIMER
, TREXMT
, tp
, 0);
if (tp
->t_rexmttl
!= 0 && --tp
->t_rexmttl
== 0)
tcp_usrreq(ISTIMER
, TREXMTTL
, tp
, 0);
if (tp
->t_persist
!= 0 && --tp
->t_persist
== 0)
tcp_usrreq(ISTIMER
, TPERSIST
, tp
, 0);
if (tp
->t_finack
!= 0 && --tp
->t_finack
== 0)
tcp_usrreq(ISTIMER
, TFINACK
, tp
, 0);
netcb
.n_iss
+= ISSINCR
; /* increment iss */
timeout(tcp_timeo
, 0, hz
); /* reschedule every second */
tcp_usrreq(input
, timertype
, tp
, mp
)
tp
->tc_flags
&= ~TC_NET_KEEP
;
acounts
[nstate
][input
]++;
if ((tp
->t_ucb
->uc_flags
& UDEBUG
) || tcpconsdebug
) {
tdb_setup(tp
, (struct th
*)0, input
, &tdb
);
switch (tcp_fstab
[nstate
][input
]) {
printf("tcp: bad state: tcb=%x state=%d input=%d\n",
tp
->tc_flags
|= TC_SND_FIN
;
tp
->tc_flags
|= TC_USR_CLOSED
;
case TIMERS
: /* 14,17,34,35,36,37,38 */
nstate
= tcp_timers(tp
, timertype
);
case FW1_SYR
: /* 24,25 */
tp
->tc_flags
|= TC_SND_FIN
;
tp
->tc_flags
|= TC_USR_CLOSED
;
case SSS_SND
: /* 40,41 */
nstate
= sss_send(tp
, mp
);
send_ctl(tp
); /* send new window */
tp
->tc_flags
|= TC_SND_RST
;
to_user(tp
->t_ucb
, UCLSERR
);
t_open(tp
, mode
) /* set up a tcb for a connection */
if (netcb
.n_tcb_head
== NULL
) {
tp
->t_tcb_next
= netcb
.n_tcb_head
;
netcb
.n_tcb_head
->t_tcb_prev
= tp
;
/* initialize non-zero tcb fields */
tp
->t_rcv_next
= (struct th
*)tp
;
tp
->t_rcv_prev
= (struct th
*)tp
;
tp
->snd_end
= tp
->seq_fin
= tp
->snd_nxt
= tp
->snd_hi
=
tp
->snd_una
= tp
->iss
= netcb
.n_iss
;
tp
->snd_off
= tp
->iss
+ 1;
netcb
.n_iss
+= (ISSINCR
>> 1) + 1;
/* set timeout for open */
tp
->t_init
= (up
->uc_timeo
!= 0 ? up
->uc_timeo
:
(mode
== ACTIVE
? T_INIT
: 0));
up
->uc_timeo
= 0; /* overlays uc_ssize */
tp
->t_init
= tp
->t_rexmt
= tp
->t_rexmttl
= tp
->t_persist
=
if (tp
->t_tcb_prev
== NULL
)
netcb
.n_tcb_head
= tp
->t_tcb_next
;
tp
->t_tcb_prev
->t_tcb_next
= tp
->t_tcb_next
;
if (tp
->t_tcb_next
== NULL
)
netcb
.n_tcb_tail
= tp
->t_tcb_prev
;
tp
->t_tcb_next
->t_tcb_prev
= tp
->t_tcb_prev
;
/* free all data on receive and send buffers */
for (t
= tp
->t_rcv_next
; t
!= (struct th
*)tp
; t
= t
->t_next
)
if (up
->uc_rbuf
!= NULL
) {
if (up
->uc_sbuf
!= NULL
) {
for (m
= tp
->t_rcv_unack
; m
!= NULL
; m
= m
->m_act
) {
/* lower buffer allocation and decrement host entry */
netcb
.n_lowat
-= up
->uc_snd
+ up
->uc_rcv
+ 2;
netcb
.n_hiwat
= 2 * netcb
.n_lowat
;
if (up
->uc_host
!= NULL
) {
/* if user has initiated close (via close call), delete ucb
entry, otherwise just wakeup so user can issue close call */
if (tp
->tc_flags
&TC_USR_ABORT
)
register struct mbuf
*m
, *n
;
register struct ucb
*up
= tp
->t_ucb
;
for (m
= n
= m0
; m
!= NULL
; m
= m
->m_next
) {
if ((m
= up
->uc_sbuf
) == NULL
)
while (m
->m_next
!= NULL
) {
if (m
->m_off
<= MMAXOFF
) {
off
= m
->m_off
+ m
->m_len
;
while (n
&& n
->m_off
<= MMAXOFF
&&
(MMAXOFF
- off
) >= n
->m_len
) {
bcopy((caddr_t
)((int)n
+ n
->m_off
),
(caddr_t
)((int)m
+ off
), n
->m_len
);
if (up
->uc_flags
& UURG
) {
tp
->tc_flags
|= TC_SND_URG
;
tcp_timers(tp
, timertype
)
case TINIT
: /* initialization timer */
if ((tp
->tc_flags
&TC_SYN_ACKED
) == 0) { /* 35 */
case TFINACK
: /* fin-ack timer */
* We can be sure our ACK of foreign FIN was rcvd,
* and can close if no data left for user.
t_close(tp
, UCLOSED
); /* 14 */
return (RCV_WAIT
); /* 17 */
tp
->tc_flags
|= TC_WAITED_2_ML
;
case TREXMT
: /* retransmission timer */
if (tp
->t_rexmt_val
> tp
->snd_una
) { /* 34 */
* Set up for a retransmission, increase rexmt time
* in case of multiple retransmissions.
tp
->snd_nxt
= tp
->snd_una
;
tp
->tc_flags
|= TC_REXMT
;
tp
->t_xmtime
= tp
->t_xmtime
<< 1;
if (tp
->t_xmtime
> T_REMAX
)
case TREXMTTL
: /* retransmit too long */
if (tp
->t_rtl_val
> tp
->snd_una
) /* 36 */
to_user(tp
->t_ucb
, URXTIMO
);
* If user has already closed, abort the connection.
if (tp
->tc_flags
& TC_USR_CLOSED
) {
case TPERSIST
: /* persist timer */
* Force a byte send through closed window.
tp
->tc_flags
|= TC_FORCE_ONE
;
/* THIS ROUTINE IS A CROCK */
psignal(up
->uc_proc
, SIGURG
);
register struct tcp_debug
*tdp
;
printf("TCP(%x) %s x %s",
tdp
->td_tcb
, tcpstates
[tdp
->td_old
], tcpinputs
[tdp
->td_inp
]);
if (tdp
->td_inp
== ISTIMER
)
printf("(%s)", tcptimers
[tdp
->td_tim
]);
tcpstates
[(tdp
->td_new
> 0) ? tdp
->td_new
: tdp
->td_old
]);
/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
printf(" sno %x ano %x win %d len %d flags %x",
tdp
->td_sno
, tdp
->td_ano
, tdp
->td_wno
, tdp
->td_lno
, tdp
->td_flg
);