Files
haiku-beta6/src/add-ons/kernel/network/protocols/tcp/tcp_timer.c
T
Philippe Houdoin 5de6083d95 Network stack kernel modules moved to /current tree.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@934 a95241bf-73f2-0310-859d-f6bbb57e9c96
2002-08-29 08:07:10 +00:00

183 lines
4.1 KiB
C

/* tcp_timer.c */
#ifndef _KERNEL_
#include <stdio.h>
#endif
#include "sys/protosw.h"
#include "netinet/in_pcb.h"
#include "netinet/tcp.h"
#include "netinet/tcp_timer.h"
#include "netinet/tcp_var.h"
#include "netinet/tcp_seq.h"
#include "netinet/tcp_fsm.h"
#include "core_module.h"
#include "core_funcs.h"
#ifdef _KERNEL_
#include <KernelExport.h>
#endif
extern struct core_module_info *core;
int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
{ 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
int tcp_totbackoff = 511; /* sum of tcp_backoff[] */
int tcp_keepidle = TCPTV_KEEP_IDLE;
int tcp_keepintvl = TCPTV_KEEPINTVL;
int tcp_maxpersistidle = TCPTV_KEEP_IDLE; /* max idle time in persist */
int tcp_maxidle;
void tcp_canceltimers(struct tcpcb *tp)
{
int i;
for (i=0; i < TCPT_NTIMERS; i++)
tp->t_timer[i] = 0;
}
struct tcpcb * tcp_timers(struct tcpcb *tp, int timer)
{
int rexmt;
switch (timer) {
/* TCPT_2MSL is used for
* FIN_WAIT2 timer
* TIME_WAIT
*/
case TCPT_2MSL:
if (tp->t_state != TCPS_TIME_WAIT &&
tp->t_idle <= tcp_maxidle)
tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
else
tp = tcp_close(tp);
break;
/* TCPT_PERSIST is used to wait for being told it can send
* data. The window ahs been set to 0, so no data can be
* sent, but there's data waiting to be sent. when the timer
* expires we'll force a byte to be sent (despite the window
* being 0) and reset the time...
*/
case TCPT_PERSIST:
tcpstat.tcps_persisttimeo++;
tcp_setpersist(tp);
tp->t_force = 1;
tcp_output(tp);
tp->t_force = 0;
break;
/* TCPT_KEEP is used for
* send data
* drop connection if too long idle
*/
case TCPT_KEEP:
tcpstat.tcps_keeptimeo++;
if (tp->t_state < TCPS_ESTABLISHED)
goto dropit;
if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE &&
tp->t_state <= TCPS_CLOSE_WAIT) {
if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
goto dropit;
tcpstat.tcps_keepprobe++;
tcp_respond(tp, tp->t_template, NULL, tp->rcv_nxt,
tp->snd_una - 1, 0);
tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
} else
tp->t_timer[TCPT_KEEP] = tcp_keepidle;
break;
dropit:
tcpstat.tcps_keepdrops++;
tp = tcp_drop(tp, ETIMEDOUT);
break;
/* TCPT_REXMT is the transmission timer */
case TCPT_REXMT:
if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
tp->t_rxtshift = TCP_MAXRXTSHIFT;
tcpstat.tcps_timeoutdrop++;
tp = tcp_drop(tp, tp->t_softerror ? tp->t_softerror : ETIMEDOUT);
break;
}
tcpstat.tcps_rexmttimeo++;
rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
TCPT_RANGESET(tp->t_rxtcur, rexmt, tp->t_rttmin, TCPTV_REXMTMAX);
tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
in_losing(tp->t_inpcb);
tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
tp->t_srtt = 0;
}
tp->snd_nxt = tp->snd_una;
tp->t_rtt = 0;
{
uint win = min(tp->snd_wnd, tp->snd_cwnd) / 2/ tp->t_maxseg;
if (win < 2)
win = 2;
tp->snd_cwnd = tp->t_maxseg;
tp->snd_ssthresh = win * tp->t_maxseg;
tp->t_dupacks = 0;
}
tcp_output(tp);
break;
}
return (tp);
}
void tcp_slowtimer(void *data)
{
struct inpcb *ip, *ipnxt;
struct tcpcb *tp;
int i;
tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
ip = tcb.inp_next;
if (!ip)
return;
for (; ip != &tcb; ip = ipnxt) {
ipnxt = ip->inp_next;
tp = intotcpcb(ip);
if (!tp)
continue;
for (i=0;i < TCPT_NTIMERS;i++) {
if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
tcp_userreq(tp->t_inpcb->inp_socket, PRU_SLOWTIMO, NULL,
(struct mbuf *)i, NULL);
if (ipnxt->inp_prev != ip)
goto tpgone;
}
}
tp->t_idle++;
if (tp->t_rtt)
tp->t_rtt++;
tpgone:
; /* mwcc wants a ; here, so it gets one */
}
tcp_iss += TCP_ISSINCR / PR_SLOWHZ;
tcp_now++;
return;
}
void tcp_fasttimer(void *data)
{
struct inpcb *inp;
struct tcpcb *tp;
inp = tcb.inp_next;
if (inp) {
for (; inp != &tcb; inp = inp->inp_next) {
if ((tp = (struct tcpcb*)inp->inp_ppcb) &&
(tp->t_flags & TF_DELACK)) {
tp->t_flags &= ~TF_DELACK;
tp->t_flags |= TF_ACKNOW;
tcpstat.tcps_delack++;
tcp_output(tp);
}
}
}
return;
}