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
2006-11-13 18:25:41 +03:00
int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW ;
int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID ;
int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID ;
int sysctl_dccp_feat_ack_ratio = DCCPF_INITIAL_ACK_RATIO ;
int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR ;
int sysctl_dccp_feat_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT ;
2005-08-10 07:14:34 +04:00
static u32 dccp_decode_value_var ( const unsigned char * bf , const u8 len )
{
u32 value = 0 ;
if ( len > 3 )
value + = * bf + + < < 24 ;
if ( len > 2 )
value + = * bf + + < < 16 ;
if ( len > 1 )
value + = * bf + + < < 8 ;
if ( len > 0 )
value + = * bf ;
return value ;
}
int dccp_parse_options ( struct sock * sk , struct sk_buff * skb )
{
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 ;
2006-11-24 18:02:42 +03:00
u64 ackno = DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ;
2005-08-10 07:14:34 +04:00
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 ;
unsigned char * 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 )
goto out_invalid_option ;
len = * opt_ptr + + ;
if ( len < 3 )
goto out_invalid_option ;
/*
* Remove the type and len fields , leaving
* just the value size
*/
len - = 2 ;
value = opt_ptr ;
opt_ptr + = len ;
if ( opt_ptr > opt_end )
goto out_invalid_option ;
}
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 :
if ( len > 3 )
goto out_invalid_option ;
opt_recv - > dccpor_ndp = dccp_decode_value_var ( value , len ) ;
2006-11-14 17:57:34 +03:00
dccp_pr_debug ( " %s rx opt: NDP count=%d \n " , dccp_role ( sk ) ,
2005-08-14 03:34:54 +04:00
opt_recv - > dccpor_ndp ) ;
2005-08-10 07:14:34 +04:00
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_CHANGE_L :
/* fall through */
case DCCPO_CHANGE_R :
if ( len < 2 )
goto out_invalid_option ;
rc = dccp_feat_change_recv ( sk , opt , * value , value + 1 ,
len - 1 ) ;
/*
* When there is a change error , change_recv is
* responsible for dealing with it . i . e . reply with an
* empty confirm .
* If the change was mandatory , then we need to die .
*/
if ( rc & & mandatory )
goto out_invalid_option ;
break ;
case DCCPO_CONFIRM_L :
/* fall through */
case DCCPO_CONFIRM_R :
if ( len < 2 )
goto out_invalid_option ;
if ( dccp_feat_confirm_recv ( sk , opt , * value ,
value + 1 , len - 1 ) )
goto out_invalid_option ;
break ;
2005-08-10 07:14:34 +04:00
case DCCPO_ACK_VECTOR_0 :
2005-09-18 11:17:51 +04:00
case DCCPO_ACK_VECTOR_1 :
2007-11-21 15:13:53 +03:00
if ( dccp_packet_without_ack ( skb ) ) /* RFC 4340, 11.4 */
2006-03-21 09:30:51 +03:00
break ;
2005-08-10 07:14:34 +04:00
2006-03-21 09:50:58 +03:00
if ( dccp_msk ( sk ) - > dccpms_send_ack_vector & &
2006-11-24 18:02:42 +03:00
dccp_ackvec_parse ( sk , skb , & ackno , opt , value , len ) )
2005-09-18 11:17:51 +04:00
goto out_invalid_option ;
2005-08-10 07:14:34 +04:00
break ;
case DCCPO_TIMESTAMP :
if ( len ! = 4 )
goto out_invalid_option ;
2007-10-24 16:46:58 +04:00
opt_val = get_unaligned ( ( __be32 * ) value ) ;
opt_recv - > dccpor_timestamp = ntohl ( opt_val ) ;
2005-08-10 07:14:34 +04:00
dp - > dccps_timestamp_echo = opt_recv - > dccpor_timestamp ;
2007-08-20 04:18:33 +04:00
dp - > dccps_timestamp_time = ktime_get_real ( ) ;
2005-08-10 07:14:34 +04:00
2006-11-14 17:57:34 +03:00
dccp_pr_debug ( " %s rx opt: TIMESTAMP=%u, ackno=%llu \n " ,
dccp_role ( sk ) , opt_recv - > dccpor_timestamp ,
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 ) ;
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 ;
/*
2006-10-25 03:17:51 +04:00
* From RFC 4340 , sec . 10.3 :
2005-08-10 07:14:34 +04:00
*
2005-08-14 03:34:54 +04:00
* Option numbers 128 through 191 are for
* options sent from the HC - Sender to the
* HC - Receiver ; option numbers 192 through 255
* are for options sent from the HC - Receiver to
* the HC - Sender .
2005-08-10 07:14:34 +04:00
*/
case 128 . . . 191 : {
const u16 idx = value - options ;
2005-08-14 03:34:54 +04:00
if ( ccid_hc_rx_parse_options ( dp - > dccps_hc_rx_ccid , sk ,
opt , len , idx ,
value ) ! = 0 )
2005-08-10 07:14:34 +04:00
goto out_invalid_option ;
}
break ;
case 192 . . . 255 : {
const u16 idx = value - options ;
2005-08-14 03:34:54 +04:00
if ( ccid_hc_tx_parse_options ( dp - > dccps_hc_tx_ccid , sk ,
opt , len , idx ,
value ) ! = 0 )
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
}
[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 ;
2005-08-10 07:14:34 +04:00
return 0 ;
out_invalid_option :
DCCP_INC_STATS_BH ( DCCP_MIB_INVALIDOPT ) ;
DCCP_SKB_CB ( skb ) - > dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR ;
2006-11-20 23:39:23 +03:00
DCCP_WARN ( " DCCP(%p): invalid option %d, len=%d " , sk , opt , len ) ;
2005-08-10 07:14:34 +04:00
return - 1 ;
}
2006-03-21 08:25:11 +03:00
EXPORT_SYMBOL_GPL ( dccp_parse_options ) ;
2005-08-10 07:14:34 +04:00
static void dccp_encode_value_var ( const u32 value , unsigned char * to ,
const unsigned int len )
{
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 ) ;
}
static inline int dccp_ndp_len ( const int ndp )
{
return likely ( ndp < = 0xFF ) ? 1 : ndp < = 0xFFFF ? 2 : 3 ;
}
2006-03-21 09:32:06 +03:00
int dccp_insert_option ( struct sock * sk , struct sk_buff * skb ,
2005-08-10 07:14:34 +04:00
const unsigned char option ,
const void * value , const unsigned char len )
{
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 ) ;
int ndp = dp - > dccps_ndp_count ;
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
}
2006-03-21 09:32:06 +03:00
int dccp_insert_option_elapsed_time ( struct sock * sk , 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
2006-03-21 09:32:06 +03:00
int dccp_insert_option_timestamp ( struct sock * sk , 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 */
2006-03-21 09:32:06 +03:00
return dccp_insert_option ( sk , skb , DCCPO_TIMESTAMP , & now , sizeof ( now ) ) ;
2005-08-10 07:14:34 +04:00
}
2005-08-24 08:51:36 +04:00
EXPORT_SYMBOL_GPL ( dccp_insert_option_timestamp ) ;
2006-03-21 09:32:06 +03:00
static int dccp_insert_option_timestamp_echo ( struct sock * sk ,
struct sk_buff * skb )
2005-08-10 07:14:34 +04:00
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2006-03-21 06:23:32 +03:00
__be32 tstamp_echo ;
2005-09-09 09:38:35 +04:00
int len , elapsed_time_len ;
2005-08-10 07:14:34 +04:00
unsigned char * to ;
2007-08-20 04:18:33 +04:00
const suseconds_t delta = ktime_us_delta ( ktime_get_real ( ) ,
dp - > dccps_timestamp_time ) ;
u32 elapsed_time = delta / 10 ;
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 ;
tstamp_echo = htonl ( dp - > dccps_timestamp_echo ) ;
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
dp - > dccps_timestamp_echo = 0 ;
2007-08-20 04:18:33 +04:00
dp - > dccps_timestamp_time = ktime_set ( 0 , 0 ) ;
2006-03-21 09:32:06 +03:00
return 0 ;
2005-08-10 07:14:34 +04:00
}
[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
static int dccp_insert_feat_opt ( struct sk_buff * skb , u8 type , u8 feat ,
2007-02-09 17:24:38 +03:00
u8 * val , u8 len )
[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
{
u8 * to ;
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN ) {
2006-11-20 23:39:23 +03:00
DCCP_WARN ( " packet too small for feature %d option! \n " , feat ) ;
[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
return - 1 ;
}
DCCP_SKB_CB ( skb ) - > dccpd_opt_len + = len + 3 ;
to = skb_push ( skb , len + 3 ) ;
* to + + = type ;
* to + + = len + 3 ;
* to + + = feat ;
if ( len )
memcpy ( to , val , len ) ;
[DCCP]: Make feature negotiation more readable
This patch replaces cryptic feature negotiation messages of type
Oct 31 15:42:20 kernel: dccp_feat_change: feat change type=32 feat=1
Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=34 feat=1
Oct 31 15:42:21 kernel: dccp_feat_change: feat change type=32 feat=5
into ones of type:
Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(CCID (1), 3)
Nov 2 13:54:45 kernel: dccp_feat_change: ChangeR(CCID (1), 3)
Nov 2 13:54:45 kernel: dccp_feat_change: ChangeL(Ack Ratio (5), 2)
Also,
* completed the feature number list wrt RFC 4340 sec. 6.4
* annotating which ones have been implemented so far
* implemented rudimentary sanity checking in feat.c (FIXMEs)
* some minor fixes
Commiter note: uninlined dccp_feat_name and dccp_feat_typename, for
consistency with dccp_{state,packet}_name, that, BTW,
should be compiled only if CONFIG_IP_DCCP_DEBUG is
selected, leaving this to another cset tho. Also
shortened dccp_feat_negotiation_debug to dccp_feat_debug.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-14 17:48:10 +03:00
dccp_pr_debug ( " %s(%s (%d), ...), length %d \n " ,
dccp_feat_typename ( type ) ,
dccp_feat_name ( feat ) , feat , len ) ;
[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
return 0 ;
}
2006-03-21 09:32:06 +03:00
static int dccp_insert_options_feat ( struct sock * sk , struct sk_buff * skb )
[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
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2006-03-21 09:50:58 +03:00
struct dccp_minisock * dmsk = dccp_msk ( 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-21 04:43:56 +03:00
struct dccp_opt_pend * opt , * next ;
int change = 0 ;
/* confirm any options [NN opts] */
2006-03-21 09:50:58 +03:00
list_for_each_entry_safe ( opt , next , & dmsk - > dccpms_conf , dccpop_node ) {
[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
dccp_insert_feat_opt ( skb , opt - > dccpop_type ,
opt - > dccpop_feat , opt - > dccpop_val ,
opt - > dccpop_len ) ;
/* fear empty confirms */
if ( opt - > dccpop_val )
kfree ( opt - > dccpop_val ) ;
kfree ( opt ) ;
}
2006-03-21 09:50:58 +03:00
INIT_LIST_HEAD ( & dmsk - > dccpms_conf ) ;
[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
/* see which features we need to send */
2006-03-21 09:50:58 +03:00
list_for_each_entry ( opt , & dmsk - > dccpms_pending , dccpop_node ) {
[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
/* see if we need to send any confirm */
if ( opt - > dccpop_sc ) {
dccp_insert_feat_opt ( skb , opt - > dccpop_type + 1 ,
opt - > dccpop_feat ,
opt - > dccpop_sc - > dccpoc_val ,
opt - > dccpop_sc - > dccpoc_len ) ;
BUG_ON ( ! opt - > dccpop_sc - > dccpoc_val ) ;
kfree ( opt - > dccpop_sc - > dccpoc_val ) ;
kfree ( opt - > dccpop_sc ) ;
opt - > dccpop_sc = NULL ;
}
/* any option not confirmed, re-send it */
if ( ! opt - > dccpop_conf ) {
dccp_insert_feat_opt ( skb , opt - > dccpop_type ,
opt - > dccpop_feat , opt - > dccpop_val ,
opt - > dccpop_len ) ;
change + + ;
}
}
/* Retransmit timer.
* If this is the master listening sock , we don ' t set a timer on it . It
* should be fine because if the dude doesn ' t receive our RESPONSE
* [ which will contain the CHANGE ] he will send another REQUEST which
* will " retrnasmit " the change .
*/
if ( change & & dp - > dccps_role ! = DCCP_ROLE_LISTEN ) {
dccp_pr_debug ( " reset feat negotiation timer %p \n " , sk ) ;
/* XXX don't reset the timer on re-transmissions. I.e. reset it
* only when sending new stuff i guess . Currently the timer
* never backs off because on re - transmission it just resets it !
*/
inet_csk_reset_xmit_timer ( sk , ICSK_TIME_RETRANS ,
inet_csk ( sk ) - > icsk_rto , DCCP_RTO_MAX ) ;
}
2006-03-21 09:32:06 +03:00
return 0 ;
[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
}
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 ) ;
2006-03-21 09:50:58 +03:00
struct dccp_minisock * dmsk = dccp_msk ( sk ) ;
2005-08-10 07:14:34 +04:00
DCCP_SKB_CB ( skb ) - > dccpd_opt_len = 0 ;
2006-03-21 09:50:58 +03:00
if ( dmsk - > dccpms_send_ndp_count & &
2006-03-21 09:32:06 +03:00
dccp_insert_option_ndp ( sk , skb ) )
return - 1 ;
2005-08-10 07:14:34 +04:00
if ( ! dccp_packet_without_ack ( skb ) ) {
2006-03-21 09:50:58 +03:00
if ( dmsk - > dccpms_send_ack_vector & &
2006-03-21 09:32:06 +03:00
dccp_ackvec_pending ( dp - > dccps_hc_rx_ackvec ) & &
dccp_insert_option_ackvec ( sk , skb ) )
return - 1 ;
if ( dp - > dccps_timestamp_echo ! = 0 & &
dccp_insert_option_timestamp_echo ( 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]: 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
/* Feature negotiation */
2006-03-21 09:32:06 +03:00
/* Data packets can't do feat negotiation */
if ( DCCP_SKB_CB ( skb ) - > dccpd_type ! = DCCP_PKT_DATA & &
DCCP_SKB_CB ( skb ) - > dccpd_type ! = DCCP_PKT_DATAACK & &
dccp_insert_options_feat ( sk , skb ) )
return - 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
2007-03-20 21:27:17 +03:00
/*
* Obtain RTT sample from Request / Response exchange .
* This is currently used in CCID 3 initialisation .
*/
if ( DCCP_SKB_CB ( skb ) - > dccpd_type = = DCCP_PKT_REQUEST & &
dccp_insert_option_timestamp ( sk , skb ) )
return - 1 ;
2005-08-10 07:14:34 +04:00
/* XXX: insert other options when appropriate */
if ( DCCP_SKB_CB ( skb ) - > dccpd_opt_len ! = 0 ) {
/* The length of all options has to be a multiple of 4 */
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
return 0 ;
2005-08-10 07:14:34 +04:00
}