2005-08-09 20:14:34 -07:00
/*
* net / dccp / timer . c
2006-12-10 16:01:18 -02:00
*
2005-08-09 20:14:34 -07:00
* An implementation of the DCCP protocol
* Arnaldo Carvalho de Melo < acme @ conectiva . com . br >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/dccp.h>
# include <linux/skbuff.h>
# include "dccp.h"
2006-11-13 13:23:52 -02:00
/* sysctl variables governing numbers of retransmission attempts */
int sysctl_dccp_request_retries __read_mostly = TCP_SYN_RETRIES ;
int sysctl_dccp_retries1 __read_mostly = TCP_RETR1 ;
int sysctl_dccp_retries2 __read_mostly = TCP_RETR2 ;
2005-08-09 20:14:34 -07:00
static void dccp_write_err ( struct sock * sk )
{
sk - > sk_err = sk - > sk_err_soft ? : ETIMEDOUT ;
sk - > sk_error_report ( sk ) ;
2006-03-20 19:25:24 -08:00
dccp_send_reset ( sk , DCCP_RESET_CODE_ABORTED ) ;
2005-08-09 20:14:34 -07:00
dccp_done ( sk ) ;
DCCP_INC_STATS_BH ( DCCP_MIB_ABORTONTIMEOUT ) ;
}
/* A write timeout has occurred. Process the after effects. */
static int dccp_write_timeout ( struct sock * sk )
{
const struct inet_connection_sock * icsk = inet_csk ( sk ) ;
int retry_until ;
if ( sk - > sk_state = = DCCP_REQUESTING | | sk - > sk_state = = DCCP_PARTOPEN ) {
if ( icsk - > icsk_retransmits ! = 0 )
dst_negative_advice ( & sk - > sk_dst_cache ) ;
2006-11-13 13:23:52 -02:00
retry_until = icsk - > icsk_syn_retries ?
: sysctl_dccp_request_retries ;
2005-08-09 20:14:34 -07:00
} else {
2006-11-13 13:23:52 -02:00
if ( icsk - > icsk_retransmits > = sysctl_dccp_retries1 ) {
2005-08-13 20:34:54 -03:00
/* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu
black hole detection . : - (
2005-08-09 20:14:34 -07:00
It is place to make it . It is not made . I do not want
to make it . It is disguisting . It does not work in any
case . Let me to cite the same draft , which requires for
us to implement this :
" The one security concern raised by this memo is that ICMP black holes
are often caused by over - zealous security administrators who block
all ICMP messages . It is vitally important that those who design and
deploy security systems understand the impact of strict filtering on
upper - layer protocols . The safest web site in the world is worthless
if most TCP implementations cannot transfer data from it . It would
be far nicer to have all of the black holes fixed rather than fixing
all of the TCP implementations . "
2007-02-09 23:24:38 +09:00
Golden words : - ) .
2005-08-09 20:14:34 -07:00
*/
dst_negative_advice ( & sk - > sk_dst_cache ) ;
}
2006-11-13 13:23:52 -02:00
retry_until = sysctl_dccp_retries2 ;
2005-08-09 20:14:34 -07:00
/*
* FIXME : see tcp_write_timout and tcp_out_of_resources
*/
}
if ( icsk - > icsk_retransmits > = retry_until ) {
/* Has it gone just too far? */
dccp_write_err ( sk ) ;
return 1 ;
}
return 0 ;
}
/*
* The DCCP retransmit timer .
*/
static void dccp_retransmit_timer ( struct sock * sk )
{
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
[DCCP]: Initial feature negotiation implementation
Still needs more work, but boots and doesn't crashes, even
does some negotiation!
18:38:52.174934 127.0.0.1.43458 > 127.0.0.1.5001: request <change_l ack_ratio 2, change_r ccid 2, change_l ccid 2>
18:38:52.218526 127.0.0.1.5001 > 127.0.0.1.43458: response <nop, nop, change_l ack_ratio 2, confirm_r ccid 2 2, confirm_l ccid 2 2, confirm_r ack_ratio 2>
18:38:52.185398 127.0.0.1.43458 > 127.0.0.1.5001: <nop, confirm_r ack_ratio 2, ack_vector0 0x00, elapsed_time 212>
:-)
Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-20 17:43:56 -08:00
/* retransmit timer is used for feature negotiation throughout
* connection . In this case , no packet is re - transmitted , but rather an
2006-11-13 13:07:51 -02:00
* ack is generated and pending changes are placed into its options .
[DCCP]: Initial feature negotiation implementation
Still needs more work, but boots and doesn't crashes, even
does some negotiation!
18:38:52.174934 127.0.0.1.43458 > 127.0.0.1.5001: request <change_l ack_ratio 2, change_r ccid 2, change_l ccid 2>
18:38:52.218526 127.0.0.1.5001 > 127.0.0.1.43458: response <nop, nop, change_l ack_ratio 2, confirm_r ccid 2 2, confirm_l ccid 2 2, confirm_r ack_ratio 2>
18:38:52.185398 127.0.0.1.43458 > 127.0.0.1.5001: <nop, confirm_r ack_ratio 2, ack_vector0 0x00, elapsed_time 212>
:-)
Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-20 17:43:56 -08:00
*/
if ( sk - > sk_send_head = = NULL ) {
dccp_pr_debug ( " feat negotiation retransmit timeout %p \n " , sk ) ;
if ( sk - > sk_state = = DCCP_OPEN )
dccp_send_ack ( sk ) ;
goto backoff ;
}
2005-08-09 20:14:34 -07:00
/*
* sk - > sk_send_head has to have one skb with
* DCCP_SKB_CB ( skb ) - > dccpd_type set to one of the retransmittable DCCP
2006-11-13 13:07:51 -02:00
* packet types . The only packets eligible for retransmission are :
2006-12-10 16:01:18 -02:00
* - - Requests in client - REQUEST state ( sec . 8.1 .1 )
* - - Acks in client - PARTOPEN state ( sec . 8.1 .5 )
* - - CloseReq in server - CLOSEREQ state ( sec . 8.3 )
* - - Close in node - CLOSING state ( sec . 8.3 ) */
2005-08-09 20:14:34 -07:00
BUG_TRAP ( sk - > sk_send_head ! = NULL ) ;
2006-12-10 16:01:18 -02:00
/*
2005-08-09 20:14:34 -07:00
* More than than 4 MSL ( 8 minutes ) has passed , a RESET ( aborted ) was
* sent , no need to retransmit , this sock is dead .
*/
if ( dccp_write_timeout ( sk ) )
goto out ;
/*
* We want to know the number of packets retransmitted , not the
* total number of retransmissions of clones of original packets .
*/
if ( icsk - > icsk_retransmits = = 0 )
DCCP_INC_STATS_BH ( DCCP_MIB_TIMEOUTS ) ;
if ( dccp_retransmit_skb ( sk , sk - > sk_send_head ) < 0 ) {
/*
* Retransmission failed because of local congestion ,
* do not backoff .
*/
if ( icsk - > icsk_retransmits = = 0 )
icsk - > icsk_retransmits = 1 ;
inet_csk_reset_xmit_timer ( sk , ICSK_TIME_RETRANS ,
min ( icsk - > icsk_rto ,
TCP_RESOURCE_PROBE_INTERVAL ) ,
2005-08-13 20:34:54 -03:00
DCCP_RTO_MAX ) ;
2005-08-09 20:14:34 -07:00
goto out ;
}
[DCCP]: Initial feature negotiation implementation
Still needs more work, but boots and doesn't crashes, even
does some negotiation!
18:38:52.174934 127.0.0.1.43458 > 127.0.0.1.5001: request <change_l ack_ratio 2, change_r ccid 2, change_l ccid 2>
18:38:52.218526 127.0.0.1.5001 > 127.0.0.1.43458: response <nop, nop, change_l ack_ratio 2, confirm_r ccid 2 2, confirm_l ccid 2 2, confirm_r ack_ratio 2>
18:38:52.185398 127.0.0.1.43458 > 127.0.0.1.5001: <nop, confirm_r ack_ratio 2, ack_vector0 0x00, elapsed_time 212>
:-)
Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-20 17:43:56 -08:00
backoff :
2005-08-09 20:14:34 -07:00
icsk - > icsk_backoff + + ;
icsk - > icsk_retransmits + + ;
icsk - > icsk_rto = min ( icsk - > icsk_rto < < 1 , DCCP_RTO_MAX ) ;
2005-08-13 20:34:54 -03:00
inet_csk_reset_xmit_timer ( sk , ICSK_TIME_RETRANS , icsk - > icsk_rto ,
DCCP_RTO_MAX ) ;
2006-11-13 13:23:52 -02:00
if ( icsk - > icsk_retransmits > sysctl_dccp_retries1 )
2005-08-09 20:14:34 -07:00
__sk_dst_reset ( sk ) ;
out : ;
}
static void dccp_write_timer ( unsigned long data )
{
struct sock * sk = ( struct sock * ) data ;
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
int event = 0 ;
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) ) {
/* Try again later */
2005-08-13 20:34:54 -03:00
sk_reset_timer ( sk , & icsk - > icsk_retransmit_timer ,
jiffies + ( HZ / 20 ) ) ;
2005-08-09 20:14:34 -07:00
goto out ;
}
if ( sk - > sk_state = = DCCP_CLOSED | | ! icsk - > icsk_pending )
goto out ;
if ( time_after ( icsk - > icsk_timeout , jiffies ) ) {
2005-08-13 20:34:54 -03:00
sk_reset_timer ( sk , & icsk - > icsk_retransmit_timer ,
icsk - > icsk_timeout ) ;
2005-08-09 20:14:34 -07:00
goto out ;
}
event = icsk - > icsk_pending ;
icsk - > icsk_pending = 0 ;
switch ( event ) {
case ICSK_TIME_RETRANS :
dccp_retransmit_timer ( sk ) ;
break ;
}
out :
bh_unlock_sock ( sk ) ;
sock_put ( sk ) ;
}
/*
* Timer for listening sockets
*/
static void dccp_response_timer ( struct sock * sk )
{
2005-08-13 20:34:54 -03:00
inet_csk_reqsk_queue_prune ( sk , TCP_SYNQ_INTERVAL , DCCP_TIMEOUT_INIT ,
DCCP_RTO_MAX ) ;
2005-08-09 20:14:34 -07:00
}
static void dccp_keepalive_timer ( unsigned long data )
{
struct sock * sk = ( struct sock * ) data ;
/* Only process if socket is not in use. */
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) ) {
2006-12-10 16:01:18 -02:00
/* Try again later. */
2005-08-09 20:14:34 -07:00
inet_csk_reset_keepalive_timer ( sk , HZ / 20 ) ;
goto out ;
}
if ( sk - > sk_state = = DCCP_LISTEN ) {
dccp_response_timer ( sk ) ;
goto out ;
}
out :
bh_unlock_sock ( sk ) ;
sock_put ( sk ) ;
}
2006-11-13 13:26:51 -02:00
/* This is the same as tcp_delack_timer, sans prequeue & mem_reclaim stuff */
static void dccp_delack_timer ( unsigned long data )
{
struct sock * sk = ( struct sock * ) data ;
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) ) {
/* Try again later. */
icsk - > icsk_ack . blocked = 1 ;
NET_INC_STATS_BH ( LINUX_MIB_DELAYEDACKLOCKED ) ;
sk_reset_timer ( sk , & icsk - > icsk_delack_timer ,
jiffies + TCP_DELACK_MIN ) ;
goto out ;
}
if ( sk - > sk_state = = DCCP_CLOSED | |
! ( icsk - > icsk_ack . pending & ICSK_ACK_TIMER ) )
goto out ;
if ( time_after ( icsk - > icsk_ack . timeout , jiffies ) ) {
sk_reset_timer ( sk , & icsk - > icsk_delack_timer ,
icsk - > icsk_ack . timeout ) ;
goto out ;
}
icsk - > icsk_ack . pending & = ~ ICSK_ACK_TIMER ;
if ( inet_csk_ack_scheduled ( sk ) ) {
if ( ! icsk - > icsk_ack . pingpong ) {
/* Delayed ACK missed: inflate ATO. */
icsk - > icsk_ack . ato = min ( icsk - > icsk_ack . ato < < 1 ,
icsk - > icsk_rto ) ;
} else {
/* Delayed ACK missed: leave pingpong mode and
* deflate ATO .
*/
icsk - > icsk_ack . pingpong = 0 ;
icsk - > icsk_ack . ato = TCP_ATO_MIN ;
}
dccp_send_ack ( sk ) ;
NET_INC_STATS_BH ( LINUX_MIB_DELAYEDACKS ) ;
}
out :
bh_unlock_sock ( sk ) ;
sock_put ( sk ) ;
}
2007-03-09 13:47:58 -08:00
/* Transmit-delay timer: used by the CCIDs to delay actual send time */
2007-03-24 21:01:31 -07:00
static void dccp_write_xmit_timer ( unsigned long data )
2007-03-09 13:47:58 -08:00
{
struct sock * sk = ( struct sock * ) data ;
struct dccp_sock * dp = dccp_sk ( sk ) ;
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) )
sk_reset_timer ( sk , & dp - > dccps_xmit_timer , jiffies + 1 ) ;
else
dccp_write_xmit ( sk , 0 ) ;
bh_unlock_sock ( sk ) ;
sock_put ( sk ) ;
}
static void dccp_init_write_xmit_timer ( struct sock * sk )
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
init_timer ( & dp - > dccps_xmit_timer ) ;
dp - > dccps_xmit_timer . data = ( unsigned long ) sk ;
dp - > dccps_xmit_timer . function = dccp_write_xmit_timer ;
}
2006-11-13 13:26:51 -02:00
void dccp_init_xmit_timers ( struct sock * sk )
{
2007-03-09 13:47:58 -08:00
dccp_init_write_xmit_timer ( sk ) ;
2006-11-13 13:26:51 -02:00
inet_csk_init_xmit_timers ( sk , & dccp_write_timer , & dccp_delack_timer ,
& dccp_keepalive_timer ) ;
}
2007-09-25 22:40:13 -07:00
static ktime_t dccp_timestamp_seed ;
/**
* dccp_timestamp - 10 s of microseconds time source
* Returns the number of 10 s of microseconds since loading DCCP . This is native
* DCCP time difference format ( RFC 4340 , sec . 13 ) .
* Please note : This will wrap around about circa every 11.9 hours .
*/
u32 dccp_timestamp ( void )
{
s64 delta = ktime_us_delta ( ktime_get_real ( ) , dccp_timestamp_seed ) ;
do_div ( delta , 10 ) ;
return delta ;
}
EXPORT_SYMBOL_GPL ( dccp_timestamp ) ;
void __init dccp_timestamping_init ( void )
{
dccp_timestamp_seed = ktime_get_real ( ) ;
}