2005-08-10 07:10:42 +04:00
/*
* NET Generic infrastructure for INET connection oriented protocols .
*
* Definitions for inet_connection_sock
*
* Authors : Many people , see the TCP sources
*
* From code originally in TCP
*
* 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 .
*/
# ifndef _INET_CONNECTION_SOCK_H
# define _INET_CONNECTION_SOCK_H
2005-12-14 10:15:52 +03:00
# include <linux/compiler.h>
2005-08-10 07:11:08 +04:00
# include <linux/string.h>
2005-08-10 07:10:42 +04:00
# include <linux/timer.h>
2006-10-20 01:23:57 +04:00
# include <linux/poll.h>
2005-12-27 07:43:12 +03:00
# include <net/inet_sock.h>
2005-08-10 07:10:42 +04:00
# include <net/request_sock.h>
2005-08-10 07:11:08 +04:00
# define INET_CSK_DEBUG 1
/* Cancel timers, when they are not required. */
# undef INET_CSK_CLEAR_TIMERS
2005-08-10 07:10:42 +04:00
struct inet_bind_bucket ;
struct inet_hashinfo ;
2005-08-10 11:03:31 +04:00
struct tcp_congestion_ops ;
2005-08-10 07:10:42 +04:00
2005-12-14 10:15:52 +03:00
/*
* Pointers to address related TCP functions
* ( i . e . things that depend on the address family )
*/
struct inet_connection_sock_af_ops {
2007-01-26 12:04:55 +03:00
int ( * queue_xmit ) ( struct sk_buff * skb , int ipfragok ) ;
2005-12-14 10:15:52 +03:00
void ( * send_check ) ( struct sock * sk , int len ,
struct sk_buff * skb ) ;
int ( * rebuild_header ) ( struct sock * sk ) ;
int ( * conn_request ) ( struct sock * sk , struct sk_buff * skb ) ;
struct sock * ( * syn_recv_sock ) ( struct sock * sk , struct sk_buff * skb ,
struct request_sock * req ,
struct dst_entry * dst ) ;
int ( * remember_stamp ) ( struct sock * sk ) ;
[INET_CONNECTION_SOCK]: Pack struct inet_connection_sock_af_ops
We have a hole in:
[acme@newtoy net-2.6.20]$ pahole net/ipv6/tcp_ipv6.o inet_connection_sock_af_ops
/* /pub/scm/linux/kernel/git/acme/net-2.6.20/include/net/inet_connection_sock.h:38 */
struct inet_connection_sock_af_ops {
int (*queue_xmit)(); /* 0 4 */
void (*send_check)(); /* 4 4 */
int (*rebuild_header)(); /* 8 4 */
int (*conn_request)(); /* 12 4 */
struct sock * (*syn_recv_sock)(); /* 16 4 */
int (*remember_stamp)(); /* 20 4 */
__u16 net_header_len; /* 24 2 */
/* XXX 2 bytes hole, try to pack */
int (*setsockopt)(); /* 28 4 */
int (*getsockopt)(); /* 32 4 */
int (*compat_setsockopt)(); /* 36 4 */
int (*compat_getsockopt)(); /* 40 4 */
void (*addr2sockaddr)(); /* 44 4 */
int sockaddr_len; /* 48 4 */
}; /* size: 52, sum members: 50, holes: 1, sum holes: 2 */
But we don't need sockaddr_len to be an int:
[acme@newtoy net-2.6.20]$ find net -name "*.[ch]" | xargs grep '\.sockaddr_len.\+=' | sort -u
net/dccp/ipv4.c: .sockaddr_len = sizeof(struct sockaddr_in),
net/dccp/ipv6.c: .sockaddr_len = sizeof(struct sockaddr_in6),
net/ipv4/tcp_ipv4.c: .sockaddr_len = sizeof(struct sockaddr_in),
net/ipv6/tcp_ipv6.c: .sockaddr_len = sizeof(struct sockaddr_in6),
net/sctp/ipv6.c: .sockaddr_len = sizeof(struct sockaddr_in6),
net/sctp/protocol.c: .sockaddr_len = sizeof(struct sockaddr_in),
[acme@newtoy net-2.6.20]$ pahole --sizes net/ipv6/tcp_ipv6.o | grep sockaddr_in
struct sockaddr_in: 16 0
struct sockaddr_in6: 28 0
[acme@newtoy net-2.6.20]$
So I turned sockaddr_len a 'u16', and now:
[acme@newtoy net-2.6.20]$ pahole net/ipv6/tcp_ipv6.o inet_connection_sock_af_ops
/* /pub/scm/linux/kernel/git/acme/net-2.6.20/include/net/inet_connection_sock.h:38 */
struct inet_connection_sock_af_ops {
int (*queue_xmit)(); /* 0 4 */
void (*send_check)(); /* 4 4 */
int (*rebuild_header)(); /* 8 4 */
int (*conn_request)(); /* 12 4 */
struct sock * (*syn_recv_sock)(); /* 16 4 */
int (*remember_stamp)(); /* 20 4 */
u16 net_header_len; /* 24 2 */
u16 sockaddr_len; /* 26 2 */
int (*setsockopt)(); /* 28 4 */
int (*getsockopt)(); /* 32 4 */
int (*compat_setsockopt)(); /* 36 4 */
int (*compat_getsockopt)(); /* 40 4 */
void (*addr2sockaddr)(); /* 44 4 */
}; /* size: 48 */
So we've saved 4 bytes:
[acme@newtoy net-2.6.20]$ codiff -sV /tmp/tcp_ipv6.o.before net/ipv6/tcp_ipv6.o
/pub/scm/linux/kernel/git/acme/net-2.6.20/net/ipv6/tcp_ipv6.c:
struct inet_connection_sock_af_ops | -4
net_header_len;
from: __u16 /* 24(0) 2(0) */
to: u16 /* 24(0) 2(0) */
sockaddr_len;
from: int /* 48(0) 4(0) */
to: u16 /* 26(0) 2(0) */
1 struct changed
[acme@newtoy net-2.6.20]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-27 22:56:43 +03:00
u16 net_header_len ;
u16 sockaddr_len ;
2005-12-14 10:15:52 +03:00
int ( * setsockopt ) ( struct sock * sk , int level , int optname ,
char __user * optval , int optlen ) ;
int ( * getsockopt ) ( struct sock * sk , int level , int optname ,
char __user * optval , int __user * optlen ) ;
2006-03-21 09:45:21 +03:00
int ( * compat_setsockopt ) ( struct sock * sk ,
int level , int optname ,
char __user * optval , int optlen ) ;
int ( * compat_getsockopt ) ( struct sock * sk ,
int level , int optname ,
char __user * optval , int __user * optlen ) ;
2005-12-14 10:15:52 +03:00
void ( * addr2sockaddr ) ( struct sock * sk , struct sockaddr * ) ;
} ;
2005-08-10 07:10:42 +04:00
/** inet_connection_sock - INET connection oriented sock
*
* @ icsk_accept_queue : FIFO of established children
* @ icsk_bind_hash : Bind node
* @ icsk_timeout : Timeout
* @ icsk_retransmit_timer : Resend ( no ack )
* @ icsk_rto : Retransmit timeout
2005-12-14 10:26:10 +03:00
* @ icsk_pmtu_cookie Last pmtu seen by socket
2005-08-10 11:03:31 +04:00
* @ icsk_ca_ops Pluggable congestion control hook
2005-12-14 10:15:52 +03:00
* @ icsk_af_ops Operations which are AF_INET { 4 , 6 } specific
2005-08-10 11:03:31 +04:00
* @ icsk_ca_state : Congestion control state
2005-08-10 07:10:42 +04:00
* @ icsk_retransmits : Number of unrecovered [ RTO ] timeouts
* @ icsk_pending : Scheduled timer event
* @ icsk_backoff : Backoff
* @ icsk_syn_retries : Number of allowed SYN ( or equivalent ) retries
2005-08-10 11:03:31 +04:00
* @ icsk_probes_out : unanswered 0 window probes
2005-12-14 10:26:10 +03:00
* @ icsk_ext_hdr_len : Network protocol overhead ( IP / IPv6 options )
2005-08-10 07:10:42 +04:00
* @ icsk_ack : Delayed ACK control data
2006-03-21 04:53:41 +03:00
* @ icsk_mtup ; MTU probing control data
2005-08-10 07:10:42 +04:00
*/
struct inet_connection_sock {
/* inet_sock has to be the first member! */
struct inet_sock icsk_inet ;
struct request_sock_queue icsk_accept_queue ;
struct inet_bind_bucket * icsk_bind_hash ;
unsigned long icsk_timeout ;
struct timer_list icsk_retransmit_timer ;
struct timer_list icsk_delack_timer ;
__u32 icsk_rto ;
2005-12-14 10:26:10 +03:00
__u32 icsk_pmtu_cookie ;
2006-01-10 02:56:09 +03:00
const struct tcp_congestion_ops * icsk_ca_ops ;
const struct inet_connection_sock_af_ops * icsk_af_ops ;
2005-12-14 10:26:10 +03:00
unsigned int ( * icsk_sync_mss ) ( struct sock * sk , u32 pmtu ) ;
2005-08-10 11:03:31 +04:00
__u8 icsk_ca_state ;
2005-08-10 07:10:42 +04:00
__u8 icsk_retransmits ;
__u8 icsk_pending ;
__u8 icsk_backoff ;
__u8 icsk_syn_retries ;
2005-08-10 11:03:31 +04:00
__u8 icsk_probes_out ;
2005-12-14 10:26:10 +03:00
__u16 icsk_ext_hdr_len ;
2005-08-10 07:10:42 +04:00
struct {
__u8 pending ; /* ACK is pending */
__u8 quick ; /* Scheduled number of quick acks */
__u8 pingpong ; /* The session is interactive */
__u8 blocked ; /* Delayed ACK was blocked by socket lock */
__u32 ato ; /* Predicted tick of soft clock */
unsigned long timeout ; /* Currently scheduled timeout */
__u32 lrcvtime ; /* timestamp of last received data packet */
__u16 last_seg_size ; /* Size of last incoming segment */
__u16 rcv_mss ; /* MSS used for delayed ACK decisions */
} icsk_ack ;
2006-03-21 04:53:41 +03:00
struct {
int enabled ;
/* Range of MTUs to search */
int search_high ;
int search_low ;
/* Information on the current probe. */
int probe_size ;
} icsk_mtup ;
2005-08-10 11:03:31 +04:00
u32 icsk_ca_priv [ 16 ] ;
# define ICSK_CA_PRIV_SIZE (16 * sizeof(u32))
2005-08-10 07:10:42 +04:00
} ;
2005-08-10 07:11:08 +04:00
# define ICSK_TIME_RETRANS 1 /* Retransmit timer */
# define ICSK_TIME_DACK 2 /* Delayed ack timer */
# define ICSK_TIME_PROBE0 3 /* Zero window probe timer */
# define ICSK_TIME_KEEPOPEN 4 /* Keepalive timer */
2005-08-10 07:10:42 +04:00
static inline struct inet_connection_sock * inet_csk ( const struct sock * sk )
{
return ( struct inet_connection_sock * ) sk ;
}
2005-08-10 11:03:31 +04:00
static inline void * inet_csk_ca ( const struct sock * sk )
{
return ( void * ) inet_csk ( sk ) - > icsk_ca_priv ;
}
2005-08-10 07:11:24 +04:00
extern struct sock * inet_csk_clone ( struct sock * sk ,
const struct request_sock * req ,
2005-10-07 10:46:04 +04:00
const gfp_t priority ) ;
2005-08-10 07:11:24 +04:00
2005-08-10 07:11:08 +04:00
enum inet_csk_ack_state_t {
ICSK_ACK_SCHED = 1 ,
ICSK_ACK_TIMER = 2 ,
2006-09-19 23:52:50 +04:00
ICSK_ACK_PUSHED = 4 ,
ICSK_ACK_PUSHED2 = 8
2005-08-10 07:11:08 +04:00
} ;
2005-08-10 07:10:42 +04:00
extern void inet_csk_init_xmit_timers ( struct sock * sk ,
void ( * retransmit_handler ) ( unsigned long ) ,
void ( * delack_handler ) ( unsigned long ) ,
void ( * keepalive_handler ) ( unsigned long ) ) ;
extern void inet_csk_clear_xmit_timers ( struct sock * sk ) ;
2005-08-10 07:11:08 +04:00
static inline void inet_csk_schedule_ack ( struct sock * sk )
{
inet_csk ( sk ) - > icsk_ack . pending | = ICSK_ACK_SCHED ;
}
static inline int inet_csk_ack_scheduled ( const struct sock * sk )
{
return inet_csk ( sk ) - > icsk_ack . pending & ICSK_ACK_SCHED ;
}
static inline void inet_csk_delack_init ( struct sock * sk )
{
memset ( & inet_csk ( sk ) - > icsk_ack , 0 , sizeof ( inet_csk ( sk ) - > icsk_ack ) ) ;
}
extern void inet_csk_delete_keepalive_timer ( struct sock * sk ) ;
extern void inet_csk_reset_keepalive_timer ( struct sock * sk , unsigned long timeout ) ;
# ifdef INET_CSK_DEBUG
extern const char inet_csk_timer_bug_msg [ ] ;
# endif
static inline void inet_csk_clear_xmit_timer ( struct sock * sk , const int what )
{
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
if ( what = = ICSK_TIME_RETRANS | | what = = ICSK_TIME_PROBE0 ) {
icsk - > icsk_pending = 0 ;
# ifdef INET_CSK_CLEAR_TIMERS
sk_stop_timer ( sk , & icsk - > icsk_retransmit_timer ) ;
# endif
} else if ( what = = ICSK_TIME_DACK ) {
icsk - > icsk_ack . blocked = icsk - > icsk_ack . pending = 0 ;
# ifdef INET_CSK_CLEAR_TIMERS
sk_stop_timer ( sk , & icsk - > icsk_delack_timer ) ;
# endif
}
# ifdef INET_CSK_DEBUG
else {
2005-08-30 09:51:28 +04:00
pr_debug ( " %s " , inet_csk_timer_bug_msg ) ;
2005-08-10 07:11:08 +04:00
}
# endif
}
/*
* Reset the retransmission timer
*/
static inline void inet_csk_reset_xmit_timer ( struct sock * sk , const int what ,
unsigned long when ,
const unsigned long max_when )
{
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
if ( when > max_when ) {
# ifdef INET_CSK_DEBUG
pr_debug ( " reset_xmit_timer: sk=%p %d when=0x%lx, caller=%p \n " ,
sk , what , when , current_text_addr ( ) ) ;
# endif
when = max_when ;
}
if ( what = = ICSK_TIME_RETRANS | | what = = ICSK_TIME_PROBE0 ) {
icsk - > icsk_pending = what ;
icsk - > icsk_timeout = jiffies + when ;
sk_reset_timer ( sk , & icsk - > icsk_retransmit_timer , icsk - > icsk_timeout ) ;
} else if ( what = = ICSK_TIME_DACK ) {
icsk - > icsk_ack . pending | = ICSK_ACK_TIMER ;
icsk - > icsk_ack . timeout = jiffies + when ;
sk_reset_timer ( sk , & icsk - > icsk_delack_timer , icsk - > icsk_ack . timeout ) ;
}
# ifdef INET_CSK_DEBUG
else {
2005-08-30 09:51:28 +04:00
pr_debug ( " %s " , inet_csk_timer_bug_msg ) ;
2005-08-10 07:11:08 +04:00
}
# endif
}
extern struct sock * inet_csk_accept ( struct sock * sk , int flags , int * err ) ;
2005-08-10 07:10:42 +04:00
extern struct request_sock * inet_csk_search_req ( const struct sock * sk ,
struct request_sock * * * prevp ,
2006-09-28 05:36:59 +04:00
const __be16 rport ,
2006-09-28 05:27:47 +04:00
const __be32 raddr ,
const __be32 laddr ) ;
2005-12-14 10:14:47 +03:00
extern int inet_csk_bind_conflict ( const struct sock * sk ,
const struct inet_bind_bucket * tb ) ;
2005-08-10 07:10:42 +04:00
extern int inet_csk_get_port ( struct inet_hashinfo * hashinfo ,
2005-12-14 10:14:47 +03:00
struct sock * sk , unsigned short snum ,
int ( * bind_conflict ) ( const struct sock * sk ,
const struct inet_bind_bucket * tb ) ) ;
2005-08-10 07:10:42 +04:00
extern struct dst_entry * inet_csk_route_req ( struct sock * sk ,
const struct request_sock * req ) ;
2005-08-10 07:11:08 +04:00
static inline void inet_csk_reqsk_queue_add ( struct sock * sk ,
struct request_sock * req ,
struct sock * child )
{
reqsk_queue_add ( & inet_csk ( sk ) - > icsk_accept_queue , req , sk , child ) ;
}
extern void inet_csk_reqsk_queue_hash_add ( struct sock * sk ,
struct request_sock * req ,
2005-12-14 10:15:12 +03:00
unsigned long timeout ) ;
2005-08-10 07:11:08 +04:00
static inline void inet_csk_reqsk_queue_removed ( struct sock * sk ,
struct request_sock * req )
{
if ( reqsk_queue_removed ( & inet_csk ( sk ) - > icsk_accept_queue , req ) = = 0 )
inet_csk_delete_keepalive_timer ( sk ) ;
}
static inline void inet_csk_reqsk_queue_added ( struct sock * sk ,
const unsigned long timeout )
{
if ( reqsk_queue_added ( & inet_csk ( sk ) - > icsk_accept_queue ) = = 0 )
inet_csk_reset_keepalive_timer ( sk , timeout ) ;
}
static inline int inet_csk_reqsk_queue_len ( const struct sock * sk )
{
return reqsk_queue_len ( & inet_csk ( sk ) - > icsk_accept_queue ) ;
}
static inline int inet_csk_reqsk_queue_young ( const struct sock * sk )
{
return reqsk_queue_len_young ( & inet_csk ( sk ) - > icsk_accept_queue ) ;
}
static inline int inet_csk_reqsk_queue_is_full ( const struct sock * sk )
{
return reqsk_queue_is_full ( & inet_csk ( sk ) - > icsk_accept_queue ) ;
}
static inline void inet_csk_reqsk_queue_unlink ( struct sock * sk ,
struct request_sock * req ,
struct request_sock * * prev )
{
reqsk_queue_unlink ( & inet_csk ( sk ) - > icsk_accept_queue , req , prev ) ;
}
static inline void inet_csk_reqsk_queue_drop ( struct sock * sk ,
struct request_sock * req ,
struct request_sock * * prev )
{
inet_csk_reqsk_queue_unlink ( sk , req , prev ) ;
inet_csk_reqsk_queue_removed ( sk , req ) ;
reqsk_free ( req ) ;
}
2005-08-10 07:15:09 +04:00
extern void inet_csk_reqsk_queue_prune ( struct sock * parent ,
const unsigned long interval ,
const unsigned long timeout ,
const unsigned long max_rto ) ;
extern void inet_csk_destroy_sock ( struct sock * sk ) ;
2005-08-24 08:52:58 +04:00
/*
* LISTEN is a special case for poll . .
*/
static inline unsigned int inet_csk_listen_poll ( const struct sock * sk )
{
return ! reqsk_queue_empty ( & inet_csk ( sk ) - > icsk_accept_queue ) ?
( POLLIN | POLLRDNORM ) : 0 ;
}
2005-08-10 07:15:09 +04:00
extern int inet_csk_listen_start ( struct sock * sk , const int nr_table_entries ) ;
2005-08-10 07:11:56 +04:00
extern void inet_csk_listen_stop ( struct sock * sk ) ;
2005-12-14 10:16:04 +03:00
extern void inet_csk_addr2sockaddr ( struct sock * sk , struct sockaddr * uaddr ) ;
2006-03-21 09:01:03 +03:00
extern int inet_csk_ctl_sock_create ( struct socket * * sock ,
unsigned short family ,
unsigned short type ,
unsigned char protocol ) ;
2006-03-21 09:46:16 +03:00
extern int inet_csk_compat_getsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int __user * optlen ) ;
extern int inet_csk_compat_setsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int optlen ) ;
2005-08-10 07:10:42 +04:00
# endif /* _INET_CONNECTION_SOCK_H */