2005-08-10 07:14:34 +04:00
/*
* net / dccp / options . c
*
* An implementation of the DCCP protocol
2005-08-20 07:23:43 +04:00
* Copyright ( c ) 2005 Aristeu Sergio Rozanski Filho < aris @ cathedrallabs . org >
* Copyright ( c ) 2005 Arnaldo Carvalho de Melo < acme @ ghostprotocols . net >
2006-08-27 06:01:30 +04:00
* Copyright ( c ) 2005 Ian McDonald < ian . mcdonald @ jandi . co . nz >
2005-08-10 07:14:34 +04:00
*
* 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/module.h>
# include <linux/types.h>
2007-10-24 16:46:58 +04:00
# include <asm/unaligned.h>
2005-08-10 07:14:34 +04:00
# include <linux/kernel.h>
# include <linux/skbuff.h>
2005-09-18 11:17:51 +04:00
# include "ackvec.h"
2005-08-10 07:14:34 +04:00
# include "ccid.h"
# include "dccp.h"
[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-21 04:43:56 +03:00
# include "feat.h"
2005-08-10 07:14:34 +04:00
2008-11-24 03:07:53 +03:00
u64 dccp_decode_value_var ( const u8 * bf , const u8 len )
2005-08-10 07:14:34 +04:00
{
2008-11-24 03:07:53 +03:00
u64 value = 0 ;
2005-08-10 07:14:34 +04:00
2008-11-24 03:07:53 +03:00
if ( len > = DCCP_OPTVAL_MAXLEN )
value + = ( ( u64 ) * bf + + ) < < 40 ;
if ( len > 4 )
value + = ( ( u64 ) * bf + + ) < < 32 ;
2005-08-10 07:14:34 +04:00
if ( len > 3 )
2008-11-24 03:07:53 +03:00
value + = ( ( u64 ) * bf + + ) < < 24 ;
2005-08-10 07:14:34 +04:00
if ( len > 2 )
2008-11-24 03:07:53 +03:00
value + = ( ( u64 ) * bf + + ) < < 16 ;
2005-08-10 07:14:34 +04:00
if ( len > 1 )
2008-11-24 03:07:53 +03:00
value + = ( ( u64 ) * bf + + ) < < 8 ;
2005-08-10 07:14:34 +04:00
if ( len > 0 )
value + = * bf ;
return value ;
}
2007-12-13 17:29:24 +03:00
/**
* dccp_parse_options - Parse DCCP options present in @ skb
* @ sk : client | server | listening dccp socket ( when @ dreq ! = NULL )
* @ dreq : request socket to use during connection setup , or NULL
*/
int dccp_parse_options ( struct sock * sk , struct dccp_request_sock * dreq ,
struct sk_buff * skb )
2005-08-10 07:14:34 +04:00
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
const struct dccp_hdr * dh = dccp_hdr ( skb ) ;
const u8 pkt_type = DCCP_SKB_CB ( skb ) - > dccpd_type ;
unsigned char * options = ( unsigned char * ) dh + dccp_hdr_len ( skb ) ;
unsigned char * opt_ptr = options ;
2005-08-14 03:34:54 +04:00
const unsigned char * opt_end = ( unsigned char * ) dh +
( dh - > dccph_doff * 4 ) ;
2005-08-10 07:14:34 +04:00
struct dccp_options_received * opt_recv = & dp - > dccps_options_received ;
unsigned char opt , len ;
2008-11-26 03:57:30 +03:00
unsigned char * uninitialized_var ( value ) ;
2005-09-09 09:32:01 +04:00
u32 elapsed_time ;
2007-10-24 16:46:58 +04:00
__be32 opt_val ;
[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-21 04:43:56 +03:00
int rc ;
int mandatory = 0 ;
2005-08-10 07:14:34 +04:00
memset ( opt_recv , 0 , sizeof ( * opt_recv ) ) ;
2006-03-21 09:36:01 +03:00
opt = len = 0 ;
2005-08-10 07:14:34 +04:00
while ( opt_ptr ! = opt_end ) {
opt = * opt_ptr + + ;
len = 0 ;
value = NULL ;
/* Check if this isn't a single byte option */
if ( opt > DCCPO_MAX_RESERVED ) {
if ( opt_ptr = = opt_end )
2008-08-23 15:28:27 +04:00
goto out_nonsensical_length ;
2005-08-10 07:14:34 +04:00
len = * opt_ptr + + ;
2008-08-23 15:28:27 +04:00
if ( len < 2 )
goto out_nonsensical_length ;
2005-08-10 07:14:34 +04:00
/*
* Remove the type and len fields , leaving
* just the value size
*/
len - = 2 ;
value = opt_ptr ;
opt_ptr + = len ;
if ( opt_ptr > opt_end )
2008-08-23 15:28:27 +04:00
goto out_nonsensical_length ;
2005-08-10 07:14:34 +04:00
}
2007-12-13 17:29:24 +03:00
/*
* CCID - specific options are ignored during connection setup , as
* negotiation may still be in progress ( see RFC 4340 , 10.3 ) .
2008-06-11 14:19:09 +04:00
* The same applies to Ack Vectors , as these depend on the CCID .
2007-12-13 17:29:24 +03:00
*/
2010-09-19 22:08:00 +04:00
if ( dreq ! = NULL & & ( opt > = DCCPO_MIN_RX_CCID_SPECIFIC | |
2008-06-11 14:19:09 +04:00
opt = = DCCPO_ACK_VECTOR_0 | | opt = = DCCPO_ACK_VECTOR_1 ) )
2007-12-13 17:29:24 +03:00
goto ignore_option ;
2005-08-10 07:14:34 +04:00
switch ( opt ) {
case DCCPO_PADDING :
break ;
[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-21 04:43:56 +03:00
case DCCPO_MANDATORY :
if ( mandatory )
goto out_invalid_option ;
2006-03-21 09:06:02 +03:00
if ( pkt_type ! = DCCP_PKT_DATA )
mandatory = 1 ;
[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-21 04:43:56 +03:00
break ;
2005-08-10 07:14:34 +04:00
case DCCPO_NDP_COUNT :
2008-07-13 14:51:40 +04:00
if ( len > 6 )
2005-08-10 07:14:34 +04:00
goto out_invalid_option ;
opt_recv - > dccpor_ndp = dccp_decode_value_var ( value , len ) ;
2008-07-13 14:51:40 +04:00
dccp_pr_debug ( " %s opt: NDP count=%llu \n " , dccp_role ( sk ) ,
( unsigned long long ) opt_recv - > dccpor_ndp ) ;
2005-08-10 07:14:34 +04:00
break ;
2008-12-02 10:33:18 +03:00
case DCCPO_CHANGE_L . . . DCCPO_CONFIRM_R :
if ( pkt_type = = DCCP_PKT_DATA ) /* RFC 4340, 6 */
2007-12-13 17:48:19 +03:00
break ;
2011-05-06 07:27:18 +04:00
if ( len = = 0 )
goto out_invalid_option ;
2008-12-02 10:32:35 +03:00
rc = dccp_feat_parse_options ( sk , dreq , mandatory , opt ,
* value , value + 1 , len - 1 ) ;
if ( rc )
goto out_featneg_failed ;
2008-09-09 15:27:22 +04:00
break ;
2005-08-10 07:14:34 +04:00
case DCCPO_TIMESTAMP :
if ( len ! = 4 )
goto out_invalid_option ;
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-12-13 17:37:19 +03:00
/*
* RFC 4340 13.1 : " The precise time corresponding to
* Timestamp Value zero is not specified " . We use
* zero to indicate absence of a meaningful timestamp .
*/
2007-10-24 16:46:58 +04:00
opt_val = get_unaligned ( ( __be32 * ) value ) ;
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-12-13 17:37:19 +03:00
if ( unlikely ( opt_val = = 0 ) ) {
DCCP_WARN ( " Timestamp with zero value \n " ) ;
break ;
}
2005-08-10 07:14:34 +04:00
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-12-13 17:37:19 +03:00
if ( dreq ! = NULL ) {
dreq - > dreq_timestamp_echo = ntohl ( opt_val ) ;
dreq - > dreq_timestamp_time = dccp_timestamp ( ) ;
} else {
opt_recv - > dccpor_timestamp =
dp - > dccps_timestamp_echo = ntohl ( opt_val ) ;
dp - > dccps_timestamp_time = dccp_timestamp ( ) ;
}
2006-11-14 17:57:34 +03:00
dccp_pr_debug ( " %s rx opt: TIMESTAMP=%u, ackno=%llu \n " ,
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-12-13 17:37:19 +03:00
dccp_role ( sk ) , ntohl ( opt_val ) ,
2005-08-10 07:27:14 +04:00
( unsigned long long )
2005-08-10 07:14:34 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ) ;
2010-10-11 22:41:13 +04:00
/* schedule an Ack in case this sender is quiescent */
inet_csk_schedule_ack ( sk ) ;
2005-08-10 07:14:34 +04:00
break ;
case DCCPO_TIMESTAMP_ECHO :
2005-08-20 07:23:43 +04:00
if ( len ! = 4 & & len ! = 6 & & len ! = 8 )
2005-08-10 07:14:34 +04:00
goto out_invalid_option ;
2007-10-24 16:46:58 +04:00
opt_val = get_unaligned ( ( __be32 * ) value ) ;
opt_recv - > dccpor_timestamp_echo = ntohl ( opt_val ) ;
2005-08-10 07:14:34 +04:00
2006-11-14 17:57:34 +03:00
dccp_pr_debug ( " %s rx opt: TIMESTAMP_ECHO=%u, len=%d, "
2007-04-21 00:56:47 +04:00
" ackno=%llu " , dccp_role ( sk ) ,
2005-08-14 03:34:54 +04:00
opt_recv - > dccpor_timestamp_echo ,
2005-08-10 07:27:14 +04:00
len + 2 ,
( unsigned long long )
2005-08-20 07:23:43 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ) ;
2007-10-24 16:46:58 +04:00
value + = 4 ;
2005-08-20 07:23:43 +04:00
2007-10-24 16:46:58 +04:00
if ( len = = 4 ) { /* no elapsed time included */
2007-04-21 00:56:47 +04:00
dccp_pr_debug_cat ( " \n " ) ;
2005-09-09 09:32:01 +04:00
break ;
2007-04-21 00:56:47 +04:00
}
2005-09-09 09:32:01 +04:00
2007-10-24 16:46:58 +04:00
if ( len = = 6 ) { /* 2-byte elapsed time */
__be16 opt_val2 = get_unaligned ( ( __be16 * ) value ) ;
elapsed_time = ntohs ( opt_val2 ) ;
} else { /* 4-byte elapsed time */
opt_val = get_unaligned ( ( __be32 * ) value ) ;
elapsed_time = ntohl ( opt_val ) ;
}
2005-09-09 09:32:01 +04:00
2007-10-05 01:44:01 +04:00
dccp_pr_debug_cat ( " , ELAPSED_TIME=%u \n " , elapsed_time ) ;
2007-04-21 00:56:47 +04:00
2005-09-09 09:32:01 +04:00
/* Give precedence to the biggest ELAPSED_TIME */
if ( elapsed_time > opt_recv - > dccpor_elapsed_time )
opt_recv - > dccpor_elapsed_time = elapsed_time ;
2005-08-10 07:14:34 +04:00
break ;
case DCCPO_ELAPSED_TIME :
2007-11-21 15:13:53 +03:00
if ( dccp_packet_without_ack ( skb ) ) /* RFC 4340, 13.2 */
break ;
2005-08-20 07:23:43 +04:00
2007-10-24 16:46:58 +04:00
if ( len = = 2 ) {
__be16 opt_val2 = get_unaligned ( ( __be16 * ) value ) ;
elapsed_time = ntohs ( opt_val2 ) ;
2007-11-21 15:13:53 +03:00
} else if ( len = = 4 ) {
2007-10-24 16:46:58 +04:00
opt_val = get_unaligned ( ( __be32 * ) value ) ;
elapsed_time = ntohl ( opt_val ) ;
2007-11-21 15:13:53 +03:00
} else {
goto out_invalid_option ;
2007-10-24 16:46:58 +04:00
}
2005-09-09 09:32:01 +04:00
if ( elapsed_time > opt_recv - > dccpor_elapsed_time )
opt_recv - > dccpor_elapsed_time = elapsed_time ;
2005-08-20 07:23:43 +04:00
2006-11-14 17:57:34 +03:00
dccp_pr_debug ( " %s rx opt: ELAPSED_TIME=%d \n " ,
dccp_role ( sk ) , elapsed_time ) ;
2005-08-10 07:14:34 +04:00
break ;
2010-09-19 22:08:00 +04:00
case DCCPO_MIN_RX_CCID_SPECIFIC . . . DCCPO_MAX_RX_CCID_SPECIFIC :
2005-08-14 03:34:54 +04:00
if ( ccid_hc_rx_parse_options ( dp - > dccps_hc_rx_ccid , sk ,
2010-09-19 22:06:50 +04:00
pkt_type , opt , value , len ) )
2005-08-10 07:14:34 +04:00
goto out_invalid_option ;
break ;
2010-11-14 19:26:13 +03:00
case DCCPO_ACK_VECTOR_0 :
case DCCPO_ACK_VECTOR_1 :
if ( dccp_packet_without_ack ( skb ) ) /* RFC 4340, 11.4 */
break ;
/*
* Ack vectors are processed by the TX CCID if it is
* interested . The RX CCID need not parse Ack Vectors ,
* since it is only interested in clearing old state .
* Fall through .
*/
2010-09-19 22:08:00 +04:00
case DCCPO_MIN_TX_CCID_SPECIFIC . . . DCCPO_MAX_TX_CCID_SPECIFIC :
2005-08-14 03:34:54 +04:00
if ( ccid_hc_tx_parse_options ( dp - > dccps_hc_tx_ccid , sk ,
2010-09-19 22:06:50 +04:00
pkt_type , opt , value , len ) )
2005-08-10 07:14:34 +04:00
goto out_invalid_option ;
break ;
default :
2006-11-20 23:39:23 +03:00
DCCP_CRIT ( " DCCP(%p): option %d(len=%d) not "
" implemented, ignoring " , sk , opt , len ) ;
2005-08-10 07:14:34 +04:00
break ;
2007-02-09 17:24:38 +03:00
}
2007-12-13 17:29:24 +03:00
ignore_option :
[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-21 04:43:56 +03:00
if ( opt ! = DCCPO_MANDATORY )
mandatory = 0 ;
2005-08-10 07:14:34 +04:00
}
2006-03-21 09:06:02 +03:00
/* mandatory was the last byte in option list -> reset connection */
if ( mandatory )
goto out_invalid_option ;
2008-08-23 15:28:27 +04:00
out_nonsensical_length :
/* RFC 4340, 5.8: ignore option and all remaining option space */
2005-08-10 07:14:34 +04:00
return 0 ;
out_invalid_option :
DCCP_INC_STATS_BH ( DCCP_MIB_INVALIDOPT ) ;
2008-12-02 10:32:35 +03:00
rc = DCCP_RESET_CODE_OPTION_ERROR ;
out_featneg_failed :
DCCP_WARN ( " DCCP(%p): Option %d (len=%d) error=%u \n " , sk , opt , len , rc ) ;
DCCP_SKB_CB ( skb ) - > dccpd_reset_code = rc ;
2008-08-23 15:28:27 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_reset_data [ 0 ] = opt ;
DCCP_SKB_CB ( skb ) - > dccpd_reset_data [ 1 ] = len > 0 ? value [ 0 ] : 0 ;
DCCP_SKB_CB ( skb ) - > dccpd_reset_data [ 2 ] = len > 1 ? value [ 1 ] : 0 ;
2005-08-10 07:14:34 +04:00
return - 1 ;
}
2006-03-21 08:25:11 +03:00
EXPORT_SYMBOL_GPL ( dccp_parse_options ) ;
2008-11-24 03:07:53 +03:00
void dccp_encode_value_var ( const u64 value , u8 * to , const u8 len )
2005-08-10 07:14:34 +04:00
{
2008-11-24 03:07:53 +03:00
if ( len > = DCCP_OPTVAL_MAXLEN )
* to + + = ( value & 0xFF0000000000ull ) > > 40 ;
if ( len > 4 )
* to + + = ( value & 0xFF00000000ull ) > > 32 ;
2005-08-10 07:14:34 +04:00
if ( len > 3 )
* to + + = ( value & 0xFF000000 ) > > 24 ;
if ( len > 2 )
* to + + = ( value & 0xFF0000 ) > > 16 ;
if ( len > 1 )
* to + + = ( value & 0xFF00 ) > > 8 ;
if ( len > 0 )
* to + + = ( value & 0xFF ) ;
}
2008-07-13 14:51:40 +04:00
static inline u8 dccp_ndp_len ( const u64 ndp )
2005-08-10 07:14:34 +04:00
{
2008-07-13 14:51:40 +04:00
if ( likely ( ndp < = 0xFF ) )
return 1 ;
2010-05-25 01:33:03 +04:00
return likely ( ndp < = USHRT_MAX ) ? 2 : ( ndp < = UINT_MAX ? 4 : 6 ) ;
2005-08-10 07:14:34 +04:00
}
2010-06-22 05:14:34 +04:00
int dccp_insert_option ( struct sk_buff * skb , const unsigned char option ,
const void * value , const unsigned char len )
2005-08-10 07:14:34 +04:00
{
unsigned char * to ;
2006-03-21 09:32:06 +03:00
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN )
return - 1 ;
2005-08-10 07:14:34 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + = len + 2 ;
to = skb_push ( skb , len + 2 ) ;
* to + + = option ;
* to + + = len + 2 ;
memcpy ( to , value , len ) ;
2006-03-21 09:32:06 +03:00
return 0 ;
2005-08-10 07:14:34 +04:00
}
EXPORT_SYMBOL_GPL ( dccp_insert_option ) ;
2006-03-21 09:32:06 +03:00
static int dccp_insert_option_ndp ( struct sock * sk , struct sk_buff * skb )
2005-08-10 07:14:34 +04:00
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2008-07-13 14:51:40 +04:00
u64 ndp = dp - > dccps_ndp_count ;
2005-08-10 07:14:34 +04:00
if ( dccp_non_data_packet ( skb ) )
+ + dp - > dccps_ndp_count ;
else
dp - > dccps_ndp_count = 0 ;
if ( ndp > 0 ) {
unsigned char * ptr ;
const int ndp_len = dccp_ndp_len ( ndp ) ;
const int len = ndp_len + 2 ;
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len + len > DCCP_MAX_OPT_LEN )
2006-03-21 09:32:06 +03:00
return - 1 ;
2005-08-10 07:14:34 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + = len ;
ptr = skb_push ( skb , len ) ;
* ptr + + = DCCPO_NDP_COUNT ;
* ptr + + = len ;
dccp_encode_value_var ( ndp , ptr , ndp_len ) ;
}
2006-03-21 09:32:06 +03:00
return 0 ;
2005-08-10 07:14:34 +04:00
}
static inline int dccp_elapsed_time_len ( const u32 elapsed_time )
{
2005-08-19 03:45:29 +04:00
return elapsed_time = = 0 ? 0 : elapsed_time < = 0xFFFF ? 2 : 4 ;
2005-08-10 07:14:34 +04:00
}
2010-11-10 23:20:07 +03:00
/* FIXME: This function is currently not used anywhere */
2010-06-22 05:14:34 +04:00
int dccp_insert_option_elapsed_time ( struct sk_buff * skb , u32 elapsed_time )
2005-08-10 07:14:34 +04:00
{
const int elapsed_time_len = dccp_elapsed_time_len ( elapsed_time ) ;
const int len = 2 + elapsed_time_len ;
unsigned char * to ;
2005-08-20 07:23:43 +04:00
if ( elapsed_time_len = = 0 )
2006-03-21 09:32:06 +03:00
return 0 ;
2005-08-10 07:14:34 +04:00
2006-03-21 09:32:06 +03:00
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len + len > DCCP_MAX_OPT_LEN )
return - 1 ;
2005-08-10 07:14:34 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + = len ;
to = skb_push ( skb , len ) ;
* to + + = DCCPO_ELAPSED_TIME ;
* to + + = len ;
2005-08-20 07:23:43 +04:00
if ( elapsed_time_len = = 2 ) {
2006-03-21 06:23:32 +03:00
const __be16 var16 = htons ( ( u16 ) elapsed_time ) ;
2005-08-20 07:23:43 +04:00
memcpy ( to , & var16 , 2 ) ;
} else {
2006-03-21 06:23:32 +03:00
const __be32 var32 = htonl ( elapsed_time ) ;
2005-08-20 07:23:43 +04:00
memcpy ( to , & var32 , 4 ) ;
}
2005-08-10 07:14:34 +04:00
2006-03-21 09:32:06 +03:00
return 0 ;
2005-08-10 07:14:34 +04:00
}
2005-08-24 08:51:36 +04:00
EXPORT_SYMBOL_GPL ( dccp_insert_option_elapsed_time ) ;
2005-08-10 07:14:34 +04:00
2010-10-05 08:24:09 +04:00
static int dccp_insert_option_timestamp ( struct sk_buff * skb )
2005-08-10 07:14:34 +04:00
{
2007-09-26 09:40:13 +04:00
__be32 now = htonl ( dccp_timestamp ( ) ) ;
2005-08-20 07:23:43 +04:00
/* yes this will overflow but that is the point as we want a
* 10 usec 32 bit timer which mean it wraps every 11.9 hours */
2010-06-22 05:14:34 +04:00
return dccp_insert_option ( skb , DCCPO_TIMESTAMP , & now , sizeof ( now ) ) ;
2005-08-10 07:14:34 +04:00
}
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-12-13 17:37:19 +03:00
static int dccp_insert_option_timestamp_echo ( struct dccp_sock * dp ,
struct dccp_request_sock * dreq ,
2006-03-21 09:32:06 +03:00
struct sk_buff * skb )
2005-08-10 07:14:34 +04:00
{
2006-03-21 06:23:32 +03:00
__be32 tstamp_echo ;
2005-08-10 07:14:34 +04:00
unsigned char * to ;
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-12-13 17:37:19 +03:00
u32 elapsed_time , elapsed_time_len , len ;
if ( dreq ! = NULL ) {
elapsed_time = dccp_timestamp ( ) - dreq - > dreq_timestamp_time ;
tstamp_echo = htonl ( dreq - > dreq_timestamp_echo ) ;
dreq - > dreq_timestamp_echo = 0 ;
} else {
elapsed_time = dccp_timestamp ( ) - dp - > dccps_timestamp_time ;
tstamp_echo = htonl ( dp - > dccps_timestamp_echo ) ;
dp - > dccps_timestamp_echo = 0 ;
}
2005-09-09 09:38:35 +04:00
elapsed_time_len = dccp_elapsed_time_len ( elapsed_time ) ;
len = 6 + elapsed_time_len ;
2006-03-21 09:32:06 +03:00
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len + len > DCCP_MAX_OPT_LEN )
return - 1 ;
2005-08-10 07:14:34 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + = len ;
to = skb_push ( skb , len ) ;
* to + + = DCCPO_TIMESTAMP_ECHO ;
* to + + = len ;
memcpy ( to , & tstamp_echo , 4 ) ;
to + = 4 ;
[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-21 04:43:56 +03:00
2005-08-20 07:23:43 +04:00
if ( elapsed_time_len = = 2 ) {
2006-03-21 06:23:32 +03:00
const __be16 var16 = htons ( ( u16 ) elapsed_time ) ;
2005-08-20 07:23:43 +04:00
memcpy ( to , & var16 , 2 ) ;
} else if ( elapsed_time_len = = 4 ) {
2006-03-21 06:23:32 +03:00
const __be32 var32 = htonl ( elapsed_time ) ;
2005-08-20 07:23:43 +04:00
memcpy ( to , & var32 , 4 ) ;
}
2005-08-10 07:14:34 +04:00
2006-03-21 09:32:06 +03:00
return 0 ;
2005-08-10 07:14:34 +04:00
}
2010-11-10 23:21:02 +03:00
static int dccp_insert_option_ackvec ( struct sock * sk , struct sk_buff * skb )
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
struct dccp_ackvec * av = dp - > dccps_hc_rx_ackvec ;
2010-11-14 19:25:46 +03:00
struct dccp_skb_cb * dcb = DCCP_SKB_CB ( skb ) ;
2010-11-10 23:21:35 +03:00
const u16 buflen = dccp_ackvec_buflen ( av ) ;
2010-11-10 23:21:02 +03:00
/* Figure out how many options do we need to represent the ackvec */
2010-11-10 23:21:35 +03:00
const u8 nr_opts = DIV_ROUND_UP ( buflen , DCCP_SINGLE_OPT_MAXLEN ) ;
u16 len = buflen + 2 * nr_opts ;
2010-11-10 23:21:02 +03:00
u8 i , nonce = 0 ;
const unsigned char * tail , * from ;
unsigned char * to ;
2010-11-14 19:25:46 +03:00
if ( dcb - > dccpd_opt_len + len > DCCP_MAX_OPT_LEN ) {
DCCP_WARN ( " Lacking space for %u bytes on %s packet \n " , len ,
dccp_packet_name ( dcb - > dccpd_type ) ) ;
2010-11-10 23:21:02 +03:00
return - 1 ;
2010-11-14 19:25:46 +03:00
}
/*
* Since Ack Vectors are variable - length , we can not always predict
* their size . To catch exception cases where the space is running out
* on the skb , a separate Sync is scheduled to carry the Ack Vector .
*/
if ( len > DCCPAV_MIN_OPTLEN & &
len + dcb - > dccpd_opt_len + skb - > len > dp - > dccps_mss_cache ) {
DCCP_WARN ( " No space left for Ack Vector (%u) on skb (%u+%u), "
" MPS=%u ==> reduce payload size? \n " , len , skb - > len ,
dcb - > dccpd_opt_len , dp - > dccps_mss_cache ) ;
dp - > dccps_sync_scheduled = 1 ;
return 0 ;
}
dcb - > dccpd_opt_len + = len ;
2010-11-10 23:21:02 +03:00
to = skb_push ( skb , len ) ;
2010-11-10 23:21:35 +03:00
len = buflen ;
2010-11-10 23:21:02 +03:00
from = av - > av_buf + av - > av_buf_head ;
tail = av - > av_buf + DCCPAV_MAX_ACKVEC_LEN ;
for ( i = 0 ; i < nr_opts ; + + i ) {
int copylen = len ;
if ( len > DCCP_SINGLE_OPT_MAXLEN )
copylen = DCCP_SINGLE_OPT_MAXLEN ;
/*
* RFC 4340 , 12.2 : Encode the Nonce Echo for this Ack Vector via
* its type ; ack_nonce is the sum of all individual buf_nonce ' s .
*/
nonce ^ = av - > av_buf_nonce [ i ] ;
* to + + = DCCPO_ACK_VECTOR_0 + av - > av_buf_nonce [ i ] ;
* to + + = copylen + 2 ;
/* Check if buf_head wraps */
if ( from + copylen > tail ) {
const u16 tailsize = tail - from ;
memcpy ( to , from , tailsize ) ;
to + = tailsize ;
len - = tailsize ;
copylen - = tailsize ;
from = av - > av_buf ;
}
memcpy ( to , from , copylen ) ;
from + = copylen ;
to + = copylen ;
len - = copylen ;
}
/*
* Each sent Ack Vector is recorded in the list , as per A .2 of RFC 4340.
*/
2010-11-14 19:25:46 +03:00
if ( dccp_ackvec_update_records ( av , dcb - > dccpd_seq , nonce ) )
2010-11-10 23:21:02 +03:00
return - ENOBUFS ;
return 0 ;
}
2008-11-24 03:09:11 +03:00
/**
* dccp_insert_option_mandatory - Mandatory option ( 5.8 .2 )
* Note that since we are using skb_push , this function needs to be called
* _after_ inserting the option it is supposed to influence ( stack order ) .
*/
int dccp_insert_option_mandatory ( struct sk_buff * skb )
{
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len > = DCCP_MAX_OPT_LEN )
return - 1 ;
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + + ;
* skb_push ( skb , 1 ) = DCCPO_MANDATORY ;
return 0 ;
}
2008-11-24 03:10:23 +03:00
/**
* dccp_insert_fn_opt - Insert single Feature - Negotiation option into @ skb
* @ type : % DCCPO_CHANGE_L , % DCCPO_CHANGE_R , % DCCPO_CONFIRM_L , % DCCPO_CONFIRM_R
* @ feat : one out of % dccp_feature_numbers
* @ val : NN value or SP array ( preferred element first ) to copy
* @ len : true length of @ val in bytes ( excluding first element repetition )
* @ repeat_first : whether to copy the first element of @ val twice
* The last argument is used to construct Confirm options , where the preferred
* value and the preference list appear separately ( RFC 4340 , 6.3 .1 ) . Preference
* lists are kept such that the preferred entry is always first , so we only need
* to copy twice , and avoid the overhead of cloning into a bigger array .
*/
int dccp_insert_fn_opt ( struct sk_buff * skb , u8 type , u8 feat ,
u8 * val , u8 len , bool repeat_first )
2008-09-04 09:30:19 +04:00
{
2008-11-24 03:10:23 +03:00
u8 tot_len , * to ;
2008-09-04 09:30:19 +04:00
2008-11-24 03:10:23 +03:00
/* take the `Feature' field and possible repetition into account */
if ( len > ( DCCP_SINGLE_OPT_MAXLEN - 2 ) ) {
DCCP_WARN ( " length %u for feature %u too large \n " , len , feat ) ;
2008-09-04 09:30:19 +04:00
return - 1 ;
2008-09-04 09:30:19 +04:00
}
2008-09-04 09:30:19 +04:00
2008-11-24 03:10:23 +03:00
if ( unlikely ( val = = NULL | | len = = 0 ) )
2011-12-19 17:56:45 +04:00
len = repeat_first = false ;
2008-11-24 03:10:23 +03:00
tot_len = 3 + repeat_first + len ;
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN ) {
DCCP_WARN ( " packet too small for feature %d option! \n " , feat ) ;
return - 1 ;
}
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + = tot_len ;
2008-09-04 09:30:19 +04:00
2008-11-24 03:10:23 +03:00
to = skb_push ( skb , tot_len ) ;
2008-09-09 15:27:22 +04:00
* to + + = type ;
2008-11-24 03:10:23 +03:00
* to + + = tot_len ;
2008-09-09 15:27:22 +04:00
* to + + = feat ;
2008-09-04 09:30:19 +04:00
2008-11-24 03:10:23 +03:00
if ( repeat_first )
* to + + = * val ;
2008-09-09 15:27:22 +04:00
if ( len )
memcpy ( to , val , len ) ;
2008-09-04 09:30:19 +04:00
return 0 ;
}
2007-12-13 17:38:11 +03:00
/* The length of all options needs to be a multiple of 4 (5.8) */
static void dccp_insert_option_padding ( struct sk_buff * skb )
{
int padding = DCCP_SKB_CB ( skb ) - > dccpd_opt_len % 4 ;
if ( padding ! = 0 ) {
padding = 4 - padding ;
memset ( skb_push ( skb , padding ) , 0 , padding ) ;
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + = padding ;
}
}
2006-03-21 09:32:06 +03:00
int dccp_insert_options ( struct sock * sk , struct sk_buff * skb )
2005-08-10 07:14:34 +04:00
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
DCCP_SKB_CB ( skb ) - > dccpd_opt_len = 0 ;
2008-12-08 12:18:37 +03:00
if ( dp - > dccps_send_ndp_count & & dccp_insert_option_ndp ( sk , skb ) )
2006-03-21 09:32:06 +03:00
return - 1 ;
2005-08-10 07:14:34 +04:00
2008-12-02 10:29:30 +03:00
if ( DCCP_SKB_CB ( skb ) - > dccpd_type ! = DCCP_PKT_DATA ) {
/* Feature Negotiation */
if ( dccp_feat_insert_opts ( dp , NULL , skb ) )
2006-03-21 09:32:06 +03:00
return - 1 ;
2008-12-02 10:29:30 +03:00
if ( DCCP_SKB_CB ( skb ) - > dccpd_type = = DCCP_PKT_REQUEST ) {
/*
* Obtain RTT sample from Request / Response exchange .
2010-06-22 05:14:35 +04:00
* This is currently used for TFRC initialisation .
2008-12-02 10:29:30 +03:00
*/
2010-06-22 05:14:34 +04:00
if ( dccp_insert_option_timestamp ( skb ) )
2008-12-02 10:29:30 +03:00
return - 1 ;
2010-11-10 23:21:35 +03:00
} else if ( dccp_ackvec_pending ( sk ) & &
2008-12-02 10:29:30 +03:00
dccp_insert_option_ackvec ( sk , skb ) ) {
return - 1 ;
}
2005-08-10 07:14:34 +04:00
}
2005-09-09 09:30:07 +04:00
if ( dp - > dccps_hc_rx_insert_options ) {
2006-03-21 09:32:06 +03:00
if ( ccid_hc_rx_insert_options ( dp - > dccps_hc_rx_ccid , sk , skb ) )
return - 1 ;
2005-09-09 09:30:07 +04:00
dp - > dccps_hc_rx_insert_options = 0 ;
}
2005-08-10 07:14:34 +04:00
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-12-13 17:37:19 +03:00
if ( dp - > dccps_timestamp_echo ! = 0 & &
dccp_insert_option_timestamp_echo ( dp , NULL , skb ) )
return - 1 ;
2007-12-13 17:38:11 +03:00
dccp_insert_option_padding ( skb ) ;
return 0 ;
}
2005-08-10 07:14:34 +04:00
2007-12-13 17:38:11 +03:00
int dccp_insert_options_rsk ( struct dccp_request_sock * dreq , struct sk_buff * skb )
{
DCCP_SKB_CB ( skb ) - > dccpd_opt_len = 0 ;
2005-08-10 07:14:34 +04:00
2008-12-02 10:29:30 +03:00
if ( dccp_feat_insert_opts ( NULL , dreq , skb ) )
return - 1 ;
2010-06-22 05:14:35 +04:00
/* Obtain RTT sample from Response/Ack exchange (used by TFRC). */
if ( dccp_insert_option_timestamp ( skb ) )
return - 1 ;
2007-12-13 17:38:11 +03:00
if ( dreq - > dreq_timestamp_echo ! = 0 & &
dccp_insert_option_timestamp_echo ( NULL , dreq , skb ) )
return - 1 ;
2006-03-21 09:32:06 +03:00
2007-12-13 17:38:11 +03:00
dccp_insert_option_padding ( skb ) ;
2006-03-21 09:32:06 +03:00
return 0 ;
2005-08-10 07:14:34 +04:00
}