/* tcp_usrreq.c 1.31 81/11/20 */
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../net/inet_pcb.h"
#include "../net/inet_systm.h"
#include "../net/ip_var.h"
#include "../net/tcp_fsm.h"
#include "../net/tcp_var.h"
#include "/usr/include/errno.h"
tcb
.inp_next
= tcb
.inp_prev
= &tcb
;
* Tcp finite state machine entries for timer and user generated
* requests. These routines raise the ipl to that of the network
* to prevent reentry. In particluar, this requires that the software
* clock interrupt have lower priority than the network so that
* we can enter the network from timeout routines without improperly
* nesting the interrupt stack.
* Tcp protocol timeout routine called every 500 ms.
* Updates the timers in all active tcb's and
* causes finite state machine actions if timers expire.
register struct inpcb
*ip
;
register struct tcpcb
*tp
;
* Search through tcb's and update active timers.
for (ip
= tcb
.inp_next
; ip
!= &tcb
; ip
= ip
->inp_next
) {
for (i
= 0; i
< TNTIMERS
; i
++) {
(void) tcp_usrreq(tp
->t_inpcb
->inp_socket
,
PRU_SLOWTIMO
, (struct mbuf
*)0,
tcp_iss
+= ISSINCR
/2; /* increment iss */
* Cancel all timers for tcp tp.
register short *tmp
= &tp
->t_init
;
for (i
= 0; i
< TNTIMERS
; i
++)
struct tcpcb
*tcp_newtcpcb();
* Process a TCP user request for tcp tb. If this is a send request
* then m is the mbuf chain of send data. If this is a timer expiration
* (called from the software clock routine), then timertype tells which timer.
tcp_usrreq(so
, req
, m
, addr
)
register struct inpcb
*inp
= sotoinpcb(so
);
register struct tcpcb
*tp
;
* Make sure attached. If not,
* only PRU_ATTACH is valid.
tcp_acounts
[nstate
][req
]++;
if (((tp
->t_socket
->so_options
& SO_DEBUG
) || tcpconsdebug
)) {
tdb_setup(tp
, (struct tcpiphdr
*)0, req
, &tdb
);
tp
->tc_flags
&= ~TC_NET_KEEP
;
error
= in_pcballoc(so
, &tcb
, 2048, 2048, (struct sockaddr_in
*)addr
);
inp
= (struct inpcb
*)so
->so_pcb
;
inp
->inp_ppcb
= (caddr_t
)tp
;
if (so
->so_options
& SO_ACCEPTCONN
)
if (tp
->t_state
!= 0 && tp
->t_state
!= CLOSED
)
error
= in_pcbsetpeer(inp
, (struct sockaddr_in
*)addr
);
if ((tp
->tc_flags
& TC_FIN_RCVD
) == 0)
tp
->tc_flags
|= TC_SND_FIN
;
tp
->tc_flags
|= TC_USR_CLOSED
;
tp
->tc_flags
|= TC_SND_FIN
;
tp
->tc_flags
|= TC_USR_CLOSED
;
nstate
= nstate
!= CLOSE_WAIT
? FIN_W1
: LAST_ACK
;
if (nstate
< ESTAB
|| nstate
== CLOSED
)
if ((tp
->tc_flags
&TC_FIN_RCVD
) &&
(tp
->tc_flags
&TC_USR_CLOSED
) == 0 &&
if (nstate
== RCV_WAIT
&& rcv_empty(tp
))
nstate
= tcp_timers(tp
, (int)addr
);
printf("tcp: bad state: tcb=%x state=%d input=%d\n",
struct mbuf
*m
= m_getclr(0);
register struct tcpcb
*tp
;
tp
= mtod(m
, struct tcpcb
*);
* Make empty reassembly queue.
tp
->seg_next
= tp
->seg_prev
= (struct tcpiphdr
*)tp
;
* Initialize sequence numbers and round trip retransmit timer.
tp
->snd_end
= tp
->seq_fin
= tp
->snd_nxt
= tp
->snd_hi
= tp
->snd_una
=
tp
->snd_off
= tp
->iss
+ 1;
tcp_iss
+= (ISSINCR
>> 1) + 1;
register struct tcpcb
*tp
;
register struct tcpiphdr
*t
;
for (; t
!= (struct tcpiphdr
*)tp
; t
= (struct tcpiphdr
*)t
->ti_next
)
(void) m_free(dtom(tp
->t_template
));
register struct tcpcb
*tp
;
tp
->tc_flags
|= TC_SND_RST
;
soisdisconnected(tp
->t_inpcb
->inp_socket
);
* Send data queue headed by m0 into the protocol.
register struct tcpcb
*tp
;
register struct socket
*so
= tp
->t_inpcb
->inp_socket
;
sbappend(&so
->so_snd
, m0
);
if (tp
->t_options
& TO_EOL
)
tp
->snd_end
= tp
->snd_off
+ so
->so_snd
.sb_cc
;
if (tp
->t_options
& TO_URG
) {
tp
->snd_urp
= tp
->snd_off
+ so
->so_snd
.sb_cc
+ 1;
tp
->tc_flags
|= TC_SND_URG
;
* TCP timer went off processing.
tcp_timers(tp
, timertype
)
register struct tcpcb
*tp
;
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.
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 so 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 */
tcp_error(tp
, EIO
); /* 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
;
struct socket
*so
= tp
->t_inpcb
->inp_socket
;
* TCP debugging utility subroutines.
* THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
tdb_setup(tp
, n
, input
, tdp
)
register struct tcpiphdr
*n
;
register struct tcp_debug
*tdp
;
tdp
->td_old
= tp
->t_state
;
tdp
->td_ano
= n
->ti_ackno
;
tdp
->td_flg
= n
->ti_flags
;
tdp
->td_sno
= tdp
->td_ano
= tdp
->td_wno
= tdp
->td_lno
=
tcp_debug
[tdbx
++ % TDBSIZE
] = *tdp
;
register struct tcp_debug
*tdp
;
printf("%x ", ((int)tdp
->td_tcb
)&0xffffff);
if (tdp
->td_inp
== INSEND
) {
printf("SEND #%x", tdp
->td_sno
);
tdp
->td_lno
= ntohs(tdp
->td_lno
);
tdp
->td_wno
= ntohs(tdp
->td_wno
);
if (tdp
->td_inp
== INRECV
)
printf("RCV #%x ", tdp
->td_sno
);
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(" len=%d", tdp
->td_lno
);
printf(" win=%d", tdp
->td_wno
);
if (tdp
->td_flg
& TH_FIN
) printf(" FIN");
if (tdp
->td_flg
& TH_SYN
) printf(" SYN");
if (tdp
->td_flg
& TH_RST
) printf(" RST");
if (tdp
->td_flg
& TH_EOL
) printf(" EOL");
if (tdp
->td_flg
& TH_ACK
) printf(" ACK %x", tdp
->td_ano
);
if (tdp
->td_flg
& TH_URG
) printf(" URG");