2005-08-10 07:14:34 +04:00
# ifndef _DCCP_H
# define _DCCP_H
/*
* net / dccp / dccp . h
*
* An implementation of the DCCP protocol
2005-08-20 07:23:43 +04:00
* Copyright ( c ) 2005 Arnaldo Carvalho de Melo < acme @ conectiva . com . br >
2006-08-27 06:01:30 +04:00
* Copyright ( c ) 2005 - 6 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 version 2 as
* published by the Free Software Foundation .
*/
# include <linux/dccp.h>
2007-08-20 04:16:35 +04:00
# include <linux/ktime.h>
2005-08-10 07:14:34 +04:00
# include <net/snmp.h>
# include <net/sock.h>
# include <net/tcp.h>
2005-09-18 11:17:51 +04:00
# include "ackvec.h"
2005-08-10 07:14:34 +04:00
2006-11-20 23:39:23 +03:00
/*
* DCCP - specific warning and debugging macros .
*/
# define DCCP_WARN(fmt, a...) LIMIT_NETDEBUG(KERN_WARNING "%s: " fmt, \
2007-02-09 17:24:38 +03:00
__FUNCTION__ , # # a )
2006-11-20 23:39:23 +03:00
# define DCCP_CRIT(fmt, a...) printk(KERN_CRIT fmt " at %s:%d / %s()\n", ##a, \
__FILE__ , __LINE__ , __FUNCTION__ )
# define DCCP_BUG(a...) do { DCCP_CRIT("BUG: " a); dump_stack(); } while(0)
# define DCCP_BUG_ON(cond) do { if (unlikely((cond) != 0)) \
DCCP_BUG ( " \" %s \" holds (exception!) " , \
__stringify ( cond ) ) ; \
2006-11-16 02:27:47 +03:00
} while ( 0 )
2006-11-20 23:26:03 +03:00
# define DCCP_PRINTK(enable, fmt, args...) do { if (enable) \
printk ( fmt , # # args ) ; \
2007-02-09 17:24:38 +03:00
} while ( 0 )
2006-11-20 23:26:03 +03:00
# define DCCP_PR_DEBUG(enable, fmt, a...) DCCP_PRINTK(enable, KERN_DEBUG \
" %s: " fmt , __FUNCTION__ , # # a )
2005-08-14 03:35:39 +04:00
# ifdef CONFIG_IP_DCCP_DEBUG
2005-08-10 07:14:34 +04:00
extern int dccp_debug ;
2006-11-20 23:26:03 +03:00
# define dccp_pr_debug(format, a...) DCCP_PR_DEBUG(dccp_debug, format, ##a)
# define dccp_pr_debug_cat(format, a...) DCCP_PRINTK(dccp_debug, format, ##a)
2005-08-10 07:14:34 +04:00
# else
# define dccp_pr_debug(format, a...)
# define dccp_pr_debug_cat(format, a...)
# endif
extern struct inet_hashinfo dccp_hashinfo ;
extern atomic_t dccp_orphan_count ;
extern void dccp_time_wait ( struct sock * sk , int state , int timeo ) ;
2006-11-10 07:13:56 +03:00
/*
* Set safe upper bounds for header and option length . Since Data Offset is 8
* bits ( RFC 4340 , sec . 5.1 ) , the total header length can never be more than
* 4 * 255 = 1020 bytes . The largest possible header length is 28 bytes ( X = 1 ) :
* - DCCP - Response with ACK Subheader and 4 bytes of Service code OR
* - DCCP - Reset with ACK Subheader and 4 bytes of Reset Code fields
* Hence a safe upper bound for the maximum option length is 1020 - 28 = 992
*/
# define MAX_DCCP_SPECIFIC_HEADER (255 * sizeof(int))
# define DCCP_MAX_PACKET_HDR 28
# define DCCP_MAX_OPT_LEN (MAX_DCCP_SPECIFIC_HEADER - DCCP_MAX_PACKET_HDR)
# define MAX_DCCP_HEADER (MAX_DCCP_SPECIFIC_HEADER + MAX_HEADER)
2005-08-10 07:14:34 +04:00
# define DCCP_TIMEWAIT_LEN (60 * HZ) / * how long to wait to destroy TIME-WAIT
* state , about 60 seconds */
2006-10-25 03:17:51 +04:00
/* RFC 1122, 4.2.3.1 initial RTO value */
2005-08-10 07:14:34 +04:00
# define DCCP_TIMEOUT_INIT ((unsigned)(3 * HZ))
2007-03-20 21:23:18 +03:00
# define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */
/* bounds for sampled RTT values from packet exchanges (in usec) */
# define DCCP_SANE_RTT_MIN 100
# define DCCP_SANE_RTT_MAX (4 * USEC_PER_SEC)
2005-08-10 07:14:34 +04:00
/* Maximal interval between probes for local resources. */
# define DCCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ / 2U))
2006-11-13 18:23:52 +03:00
/* sysctl variables for DCCP */
extern int sysctl_dccp_request_retries ;
extern int sysctl_dccp_retries1 ;
extern int sysctl_dccp_retries2 ;
2006-11-13 18:25:41 +03:00
extern int sysctl_dccp_feat_sequence_window ;
extern int sysctl_dccp_feat_rx_ccid ;
extern int sysctl_dccp_feat_tx_ccid ;
extern int sysctl_dccp_feat_ack_ratio ;
extern int sysctl_dccp_feat_send_ack_vector ;
extern int sysctl_dccp_feat_send_ndp_count ;
2006-11-20 23:30:17 +03:00
extern int sysctl_dccp_tx_qlen ;
2006-11-13 18:23:52 +03:00
2007-03-20 18:26:51 +03:00
/*
* 48 - bit sequence number arithmetic ( signed and unsigned )
*/
# define INT48_MIN 0x800000000000LL /* 2^47 */
# define UINT48_MAX 0xFFFFFFFFFFFFLL /* 2^48 - 1 */
# define COMPLEMENT48(x) (0x1000000000000LL - (x)) /* 2^48 - x */
# define TO_SIGNED48(x) (((x) < INT48_MIN)? (x) : -COMPLEMENT48( (x)))
# define TO_UNSIGNED48(x) (((x) >= 0)? (x) : COMPLEMENT48(-(x)))
# define ADD48(a, b) (((a) + (b)) & UINT48_MAX)
# define SUB48(a, b) ADD48((a), COMPLEMENT48(b))
static inline void dccp_set_seqno ( u64 * seqno , u64 value )
{
* seqno = value & UINT48_MAX ;
}
static inline void dccp_inc_seqno ( u64 * seqno )
{
* seqno = ADD48 ( * seqno , 1 ) ;
}
2007-03-20 18:45:59 +03:00
/* signed mod-2^48 distance: pos. if seqno1 < seqno2, neg. if seqno1 > seqno2 */
static inline s64 dccp_delta_seqno ( const u64 seqno1 , const u64 seqno2 )
2007-03-20 18:26:51 +03:00
{
2007-03-20 18:45:59 +03:00
u64 delta = SUB48 ( seqno2 , seqno1 ) ;
return TO_SIGNED48 ( delta ) ;
2007-03-20 18:26:51 +03:00
}
2005-08-10 07:14:34 +04:00
/* is seq1 < seq2 ? */
2005-08-15 04:05:53 +04:00
static inline int before48 ( const u64 seq1 , const u64 seq2 )
2005-08-10 07:14:34 +04:00
{
2007-03-20 19:00:26 +03:00
return ( s64 ) ( ( seq2 < < 16 ) - ( seq1 < < 16 ) ) > 0 ;
2005-08-10 07:14:34 +04:00
}
/* is seq1 > seq2 ? */
2007-03-20 19:00:26 +03:00
# define after48(seq1, seq2) before48(seq2, seq1)
2005-08-10 07:14:34 +04:00
/* is seq2 <= seq1 <= seq3 ? */
2005-08-15 04:05:53 +04:00
static inline int between48 ( const u64 seq1 , const u64 seq2 , const u64 seq3 )
2005-08-10 07:14:34 +04:00
{
return ( seq3 < < 16 ) - ( seq2 < < 16 ) > = ( seq1 < < 16 ) - ( seq2 < < 16 ) ;
}
static inline u64 max48 ( const u64 seq1 , const u64 seq2 )
{
return after48 ( seq1 , seq2 ) ? seq1 : seq2 ;
}
2006-08-27 06:06:42 +04:00
/* is seq1 next seqno after seq2 */
static inline int follows48 ( const u64 seq1 , const u64 seq2 )
{
2007-03-20 19:03:47 +03:00
return dccp_delta_seqno ( seq2 , seq1 ) = = 1 ;
2006-08-27 06:06:42 +04:00
}
2005-08-10 07:14:34 +04:00
enum {
DCCP_MIB_NUM = 0 ,
DCCP_MIB_ACTIVEOPENS , /* ActiveOpens */
DCCP_MIB_ESTABRESETS , /* EstabResets */
DCCP_MIB_CURRESTAB , /* CurrEstab */
2007-02-09 17:24:38 +03:00
DCCP_MIB_OUTSEGS , /* OutSegs */
2005-08-10 07:14:34 +04:00
DCCP_MIB_OUTRSTS ,
DCCP_MIB_ABORTONTIMEOUT ,
DCCP_MIB_TIMEOUTS ,
DCCP_MIB_ABORTFAILED ,
DCCP_MIB_PASSIVEOPENS ,
DCCP_MIB_ATTEMPTFAILS ,
DCCP_MIB_OUTDATAGRAMS ,
DCCP_MIB_INERRS ,
DCCP_MIB_OPTMANDATORYERROR ,
DCCP_MIB_INVALIDOPT ,
__DCCP_MIB_MAX
} ;
# define DCCP_MIB_MAX __DCCP_MIB_MAX
struct dccp_mib {
unsigned long mibs [ DCCP_MIB_MAX ] ;
} __SNMP_MIB_ALIGN__ ;
DECLARE_SNMP_STAT ( struct dccp_mib , dccp_statistics ) ;
2005-08-14 03:34:54 +04:00
# define DCCP_INC_STATS(field) SNMP_INC_STATS(dccp_statistics, field)
# define DCCP_INC_STATS_BH(field) SNMP_INC_STATS_BH(dccp_statistics, field)
# define DCCP_INC_STATS_USER(field) SNMP_INC_STATS_USER(dccp_statistics, field)
# define DCCP_DEC_STATS(field) SNMP_DEC_STATS(dccp_statistics, field)
# define DCCP_ADD_STATS_BH(field, val) \
SNMP_ADD_STATS_BH ( dccp_statistics , field , val )
# define DCCP_ADD_STATS_USER(field, val) \
SNMP_ADD_STATS_USER ( dccp_statistics , field , val )
2005-08-10 07:14:34 +04:00
2006-11-10 22:43:06 +03:00
/*
* Checksumming routines
*/
2007-05-28 23:32:26 +04:00
static inline unsigned int dccp_csum_coverage ( const struct sk_buff * skb )
2006-11-10 22:43:06 +03:00
{
const struct dccp_hdr * dh = dccp_hdr ( skb ) ;
if ( dh - > dccph_cscov = = 0 )
return skb - > len ;
return ( dh - > dccph_doff + dh - > dccph_cscov - 1 ) * sizeof ( u32 ) ;
}
static inline void dccp_csum_outgoing ( struct sk_buff * skb )
{
2007-05-28 23:32:26 +04:00
unsigned int cov = dccp_csum_coverage ( skb ) ;
2006-11-10 22:43:06 +03:00
if ( cov > = skb - > len )
dccp_hdr ( skb ) - > dccph_cscov = 0 ;
skb - > csum = skb_checksum ( skb , 0 , ( cov > skb - > len ) ? skb - > len : cov , 0 ) ;
}
extern void dccp_v4_send_check ( struct sock * sk , int len , struct sk_buff * skb ) ;
2005-08-10 07:14:34 +04:00
extern int dccp_retransmit_skb ( struct sock * sk , struct sk_buff * skb ) ;
extern void dccp_send_ack ( struct sock * sk ) ;
extern void dccp_send_delayed_ack ( struct sock * sk ) ;
2006-11-10 17:32:01 +03:00
extern void dccp_reqsk_send_ack ( struct sk_buff * sk , struct request_sock * rsk ) ;
2005-08-17 10:10:59 +04:00
extern void dccp_send_sync ( struct sock * sk , const u64 seq ,
const enum dccp_pkt_type pkt_type ) ;
2005-08-10 07:14:34 +04:00
2006-08-27 06:16:45 +04:00
extern void dccp_write_xmit ( struct sock * sk , int block ) ;
2005-08-29 09:15:54 +04:00
extern void dccp_write_space ( struct sock * sk ) ;
2005-08-10 07:30:56 +04:00
2005-08-10 07:14:34 +04:00
extern void dccp_init_xmit_timers ( struct sock * sk ) ;
static inline void dccp_clear_xmit_timers ( struct sock * sk )
{
inet_csk_clear_xmit_timers ( sk ) ;
}
extern unsigned int dccp_sync_mss ( struct sock * sk , u32 pmtu ) ;
extern const char * dccp_packet_name ( const int type ) ;
extern const char * dccp_state_name ( const int state ) ;
2006-03-21 08:58:56 +03:00
extern void dccp_set_state ( struct sock * sk , const int state ) ;
extern void dccp_done ( struct sock * sk ) ;
2005-08-10 07:14:34 +04:00
2006-11-10 21:08:37 +03:00
extern void dccp_reqsk_init ( struct request_sock * req , struct sk_buff * skb ) ;
2005-08-10 07:14:34 +04:00
extern int dccp_v4_conn_request ( struct sock * sk , struct sk_buff * skb ) ;
extern struct sock * dccp_create_openreq_child ( struct sock * sk ,
const struct request_sock * req ,
const struct sk_buff * skb ) ;
extern int dccp_v4_do_rcv ( struct sock * sk , struct sk_buff * skb ) ;
extern struct sock * dccp_v4_request_recv_sock ( struct sock * sk ,
struct sk_buff * skb ,
struct request_sock * req ,
struct dst_entry * dst ) ;
extern struct sock * dccp_check_req ( struct sock * sk , struct sk_buff * skb ,
struct request_sock * req ,
struct request_sock * * prev ) ;
extern int dccp_child_process ( struct sock * parent , struct sock * child ,
struct sk_buff * skb ) ;
extern int dccp_rcv_state_process ( struct sock * sk , struct sk_buff * skb ,
struct dccp_hdr * dh , unsigned len ) ;
extern int dccp_rcv_established ( struct sock * sk , struct sk_buff * skb ,
const struct dccp_hdr * dh , const unsigned len ) ;
2006-03-21 09:00:37 +03:00
extern int dccp_init_sock ( struct sock * sk , const __u8 ctl_sock_initialized ) ;
2006-03-21 08:23:15 +03:00
extern int dccp_destroy_sock ( struct sock * sk ) ;
2005-12-14 10:24:16 +03:00
2005-08-10 07:14:34 +04:00
extern void dccp_close ( struct sock * sk , long timeout ) ;
extern struct sk_buff * dccp_make_response ( struct sock * sk ,
struct dst_entry * dst ,
struct request_sock * req ) ;
extern int dccp_connect ( struct sock * sk ) ;
extern int dccp_disconnect ( struct sock * sk , int flags ) ;
2006-03-21 08:23:39 +03:00
extern void dccp_hash ( struct sock * sk ) ;
2005-12-14 10:24:16 +03:00
extern void dccp_unhash ( struct sock * sk ) ;
2005-08-10 07:14:34 +04:00
extern int dccp_getsockopt ( struct sock * sk , int level , int optname ,
2005-08-14 05:42:25 +04:00
char __user * optval , int __user * optlen ) ;
extern int dccp_setsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int optlen ) ;
2006-03-21 09:45:21 +03:00
# ifdef CONFIG_COMPAT
extern int compat_dccp_getsockopt ( struct sock * sk ,
int level , int optname ,
char __user * optval , int __user * optlen ) ;
extern int compat_dccp_setsockopt ( struct sock * sk ,
int level , int optname ,
char __user * optval , int optlen ) ;
# endif
2005-08-10 07:14:34 +04:00
extern int dccp_ioctl ( struct sock * sk , int cmd , unsigned long arg ) ;
2005-08-14 03:34:54 +04:00
extern int dccp_sendmsg ( struct kiocb * iocb , struct sock * sk ,
struct msghdr * msg , size_t size ) ;
2005-08-10 07:14:34 +04:00
extern int dccp_recvmsg ( struct kiocb * iocb , struct sock * sk ,
struct msghdr * msg , size_t len , int nonblock ,
int flags , int * addr_len ) ;
extern void dccp_shutdown ( struct sock * sk , int how ) ;
2005-12-14 10:24:16 +03:00
extern int inet_dccp_listen ( struct socket * sock , int backlog ) ;
extern unsigned int dccp_poll ( struct file * file , struct socket * sock ,
poll_table * wait ) ;
extern int dccp_v4_connect ( struct sock * sk , struct sockaddr * uaddr ,
int addr_len ) ;
2005-08-10 07:14:34 +04:00
2006-03-21 06:25:24 +03:00
extern int dccp_send_reset ( struct sock * sk , enum dccp_reset_codes code ) ;
2005-08-24 08:50:06 +04:00
extern void dccp_send_close ( struct sock * sk , const int active ) ;
2005-12-14 10:24:16 +03:00
extern int dccp_invalid_packet ( struct sk_buff * skb ) ;
2007-08-20 04:16:35 +04:00
extern u32 dccp_sample_rtt ( struct sock * sk , ktime_t t_recv ,
ktime_t * t_history ) ;
2005-12-14 10:24:16 +03:00
static inline int dccp_bad_service_code ( const struct sock * sk ,
2006-03-21 06:23:32 +03:00
const __be32 service )
2005-12-14 10:24:16 +03:00
{
const struct dccp_sock * dp = dccp_sk ( sk ) ;
if ( dp - > dccps_service = = service )
return 0 ;
return ! dccp_list_has_service ( dp - > dccps_service_list , service ) ;
}
2005-08-10 07:14:34 +04:00
struct dccp_skb_cb {
2005-09-17 03:58:40 +04:00
__u8 dccpd_type : 4 ;
__u8 dccpd_ccval : 4 ;
__u8 dccpd_reset_code ;
__u16 dccpd_opt_len ;
2005-08-10 07:14:34 +04:00
__u64 dccpd_seq ;
__u64 dccpd_ack_seq ;
} ;
# define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0]))
static inline int dccp_non_data_packet ( const struct sk_buff * skb )
{
const __u8 type = DCCP_SKB_CB ( skb ) - > dccpd_type ;
return type = = DCCP_PKT_ACK | |
type = = DCCP_PKT_CLOSE | |
type = = DCCP_PKT_CLOSEREQ | |
type = = DCCP_PKT_RESET | |
type = = DCCP_PKT_SYNC | |
type = = DCCP_PKT_SYNCACK ;
}
static inline int dccp_packet_without_ack ( const struct sk_buff * skb )
{
const __u8 type = DCCP_SKB_CB ( skb ) - > dccpd_type ;
return type = = DCCP_PKT_DATA | | type = = DCCP_PKT_REQUEST ;
}
2007-03-20 18:26:51 +03:00
# define DCCP_PKT_WITHOUT_ACK_SEQ (UINT48_MAX << 2)
2005-08-10 07:14:34 +04:00
static inline void dccp_hdr_set_seq ( struct dccp_hdr * dh , const u64 gss )
{
2005-08-14 03:34:54 +04:00
struct dccp_hdr_ext * dhx = ( struct dccp_hdr_ext * ) ( ( void * ) dh +
sizeof ( * dh ) ) ;
2006-03-21 06:23:32 +03:00
dh - > dccph_seq2 = 0 ;
dh - > dccph_seq = htons ( ( gss > > 32 ) & 0xfffff ) ;
2005-08-10 07:14:34 +04:00
dhx - > dccph_seq_low = htonl ( gss & 0xffffffff ) ;
}
2005-08-14 03:34:54 +04:00
static inline void dccp_hdr_set_ack ( struct dccp_hdr_ack_bits * dhack ,
const u64 gsr )
2005-08-10 07:14:34 +04:00
{
2006-03-21 06:23:32 +03:00
dhack - > dccph_reserved1 = 0 ;
dhack - > dccph_ack_nr_high = htons ( gsr > > 32 ) ;
2005-08-10 07:14:34 +04:00
dhack - > dccph_ack_nr_low = htonl ( gsr & 0xffffffff ) ;
}
static inline void dccp_update_gsr ( struct sock * sk , u64 seq )
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2006-03-21 09:50:58 +03:00
const struct dccp_minisock * dmsk = dccp_msk ( sk ) ;
2005-08-10 07:14:34 +04:00
2005-08-21 12:36:45 +04:00
dp - > dccps_gsr = seq ;
dccp_set_seqno ( & dp - > dccps_swl ,
2006-03-21 09:50:58 +03:00
dp - > dccps_gsr + 1 - ( dmsk - > dccpms_sequence_window / 4 ) ) ;
2005-08-10 07:14:34 +04:00
dccp_set_seqno ( & dp - > dccps_swh ,
2006-03-21 09:50:58 +03:00
dp - > dccps_gsr + ( 3 * dmsk - > dccpms_sequence_window ) / 4 ) ;
2005-08-10 07:14:34 +04:00
}
static inline void dccp_update_gss ( struct sock * sk , u64 seq )
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2005-08-21 12:36:45 +04:00
dp - > dccps_awh = dp - > dccps_gss = seq ;
dccp_set_seqno ( & dp - > dccps_awl ,
2005-08-14 03:34:54 +04:00
( dp - > dccps_gss -
2006-03-21 09:50:58 +03:00
dccp_msk ( sk ) - > dccpms_sequence_window + 1 ) ) ;
2005-08-10 07:14:34 +04:00
}
2007-02-09 17:24:38 +03:00
2005-09-18 11:17:51 +04:00
static inline int dccp_ack_pending ( const struct sock * sk )
{
const struct dccp_sock * dp = dccp_sk ( sk ) ;
return dp - > dccps_timestamp_echo ! = 0 | |
# ifdef CONFIG_IP_DCCP_ACKVEC
2006-03-21 09:50:58 +03:00
( dccp_msk ( sk ) - > dccpms_send_ack_vector & &
2005-09-18 11:17:51 +04:00
dccp_ackvec_pending ( dp - > dccps_hc_rx_ackvec ) ) | |
# endif
inet_csk_ack_scheduled ( sk ) ;
}
2005-08-10 07:14:34 +04:00
2006-03-21 09:32:06 +03:00
extern int dccp_insert_options ( struct sock * sk , struct sk_buff * skb ) ;
extern int dccp_insert_option_elapsed_time ( struct sock * sk ,
2005-08-10 07:14:34 +04:00
struct sk_buff * skb ,
u32 elapsed_time ) ;
2007-09-26 09:40:13 +04:00
extern u32 dccp_timestamp ( void ) ;
extern void dccp_timestamping_init ( void ) ;
2006-03-21 09:32:06 +03:00
extern int dccp_insert_option_timestamp ( struct sock * sk ,
2005-08-24 08:51:36 +04:00
struct sk_buff * skb ) ;
2006-03-21 09:32:06 +03:00
extern int dccp_insert_option ( struct sock * sk , struct sk_buff * skb ,
2005-08-10 07:14:34 +04:00
unsigned char option ,
const void * value , unsigned char len ) ;
2006-03-21 06:25:02 +03:00
# ifdef CONFIG_SYSCTL
extern int dccp_sysctl_init ( void ) ;
extern void dccp_sysctl_exit ( void ) ;
# else
static inline int dccp_sysctl_init ( void )
{
return 0 ;
}
static inline void dccp_sysctl_exit ( void )
{
}
# endif
2005-08-10 07:14:34 +04:00
# endif /* _DCCP_H */