X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fdccp%2Fdccp.h;h=a0900bf98e6bbaf223f6cc3a02b500772ecc1781;hb=refs%2Fremotes%2Fvserver;hp=93f26dd6e6cbd79f636086316f41800aee6d2faf;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 93f26dd6e..a0900bf98 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -5,29 +5,46 @@ * * An implementation of the DCCP protocol * Copyright (c) 2005 Arnaldo Carvalho de Melo - * Copyright (c) 2005 Ian McDonald + * Copyright (c) 2005-6 Ian McDonald * * 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 #include #include #include #include #include "ackvec.h" +/* + * DCCP - specific warning and debugging macros. + */ +#define DCCP_WARN(fmt, a...) LIMIT_NETDEBUG(KERN_WARNING "%s: " fmt, \ + __FUNCTION__, ##a) +#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)); \ + } while (0) + +#ifdef MODULE +#define DCCP_PRINTK(enable, fmt, args...) do { if (enable) \ + printk(fmt, ##args); \ + } while(0) +#else +#define DCCP_PRINTK(enable, fmt, args...) printk(fmt, ##args) +#endif +#define DCCP_PR_DEBUG(enable, fmt, a...) DCCP_PRINTK(enable, KERN_DEBUG \ + "%s: " fmt, __FUNCTION__, ##a) + #ifdef CONFIG_IP_DCCP_DEBUG extern int dccp_debug; - -#define dccp_pr_debug(format, a...) \ - do { if (dccp_debug) \ - printk(KERN_DEBUG "%s: " format, __FUNCTION__ , ##a); \ - } while (0) -#define dccp_pr_debug_cat(format, a...) do { if (dccp_debug) \ - printk(format, ##a); } while (0) +#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) #else #define dccp_pr_debug(format, a...) #define dccp_pr_debug_cat(format, a...) @@ -36,22 +53,26 @@ extern int dccp_debug; extern struct inet_hashinfo dccp_hashinfo; extern atomic_t dccp_orphan_count; -extern int dccp_tw_count; -extern void dccp_tw_deschedule(struct inet_timewait_sock *tw); extern void dccp_time_wait(struct sock *sk, int state, int timeo); -/* FIXME: Right size this */ -#define DCCP_MAX_OPT_LEN 128 - -#define DCCP_MAX_PACKET_HDR 32 - -#define MAX_DCCP_HEADER (DCCP_MAX_PACKET_HDR + DCCP_MAX_OPT_LEN + MAX_HEADER) +/* + * 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) #define DCCP_TIMEWAIT_LEN (60 * HZ) /* how long to wait to destroy TIME-WAIT * state, about 60 seconds */ -/* draft-ietf-dccp-spec-11.txt initial RTO value */ +/* RFC 1122, 4.2.3.1 initial RTO value */ #define DCCP_TIMEOUT_INIT ((unsigned)(3 * HZ)) /* Maximal interval between probes for local resources. */ @@ -59,7 +80,17 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo); #define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */ -extern struct proto dccp_prot; +/* sysctl variables for DCCP */ +extern int sysctl_dccp_request_retries; +extern int sysctl_dccp_retries1; +extern int sysctl_dccp_retries2; +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; +extern int sysctl_dccp_tx_qlen; /* is seq1 < seq2 ? */ static inline int before48(const u64 seq1, const u64 seq2) @@ -84,6 +115,14 @@ static inline u64 max48(const u64 seq1, const u64 seq2) return after48(seq1, seq2) ? seq1 : seq2; } +/* is seq1 next seqno after seq2 */ +static inline int follows48(const u64 seq1, const u64 seq2) +{ + int diff = (seq1 & 0xFFFF) - (seq2 & 0xFFFF); + + return diff==1; +} + enum { DCCP_MIB_NUM = 0, DCCP_MIB_ACTIVEOPENS, /* ActiveOpens */ @@ -118,15 +157,40 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics); #define DCCP_ADD_STATS_USER(field, val) \ SNMP_ADD_STATS_USER(dccp_statistics, field, val) +/* + * Checksumming routines + */ +static inline int dccp_csum_coverage(const struct sk_buff *skb) +{ + 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) +{ + int cov = dccp_csum_coverage(skb); + + 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); + extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); -extern int dccp_send_response(struct sock *sk); extern void dccp_send_ack(struct sock *sk); extern void dccp_send_delayed_ack(struct sock *sk); +extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk); + extern void dccp_send_sync(struct sock *sk, const u64 seq, const enum dccp_pkt_type pkt_type); -extern int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo); +extern void dccp_write_xmit(struct sock *sk, int block); extern void dccp_write_space(struct sock *sk); extern void dccp_init_xmit_timers(struct sock *sk); @@ -140,66 +204,10 @@ 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); -static inline void dccp_set_state(struct sock *sk, const int state) -{ - const int oldstate = sk->sk_state; - - dccp_pr_debug("%s(%p) %-10.10s -> %s\n", - dccp_role(sk), sk, - dccp_state_name(oldstate), dccp_state_name(state)); - WARN_ON(state == oldstate); - - switch (state) { - case DCCP_OPEN: - if (oldstate != DCCP_OPEN) - DCCP_INC_STATS(DCCP_MIB_CURRESTAB); - break; - - case DCCP_CLOSED: - if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN) - DCCP_INC_STATS(DCCP_MIB_ESTABRESETS); - - sk->sk_prot->unhash(sk); - if (inet_csk(sk)->icsk_bind_hash != NULL && - !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) - inet_put_port(&dccp_hashinfo, sk); - /* fall through */ - default: - if (oldstate == DCCP_OPEN) - DCCP_DEC_STATS(DCCP_MIB_CURRESTAB); - } - - /* Change state AFTER socket is unhashed to avoid closed - * socket sitting in hash tables. - */ - sk->sk_state = state; -} - -static inline void dccp_done(struct sock *sk) -{ - dccp_set_state(sk, DCCP_CLOSED); - dccp_clear_xmit_timers(sk); - - sk->sk_shutdown = SHUTDOWN_MASK; - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_state_change(sk); - else - inet_csk_destroy_sock(sk); -} +extern void dccp_set_state(struct sock *sk, const int state); +extern void dccp_done(struct sock *sk); -static inline void dccp_openreq_init(struct request_sock *req, - struct dccp_sock *dp, - struct sk_buff *skb) -{ - /* - * FIXME: fill in the other req fields from the DCCP options - * received - */ - inet_rsk(req)->rmt_port = dccp_hdr(skb)->dccph_sport; - inet_rsk(req)->acked = 0; - req->rcv_wnd = 0; -} +extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb); extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb); @@ -209,10 +217,6 @@ extern struct sock *dccp_create_openreq_child(struct sock *sk, extern int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb); -extern void dccp_v4_err(struct sk_buff *skb, u32); - -extern int dccp_v4_rcv(struct sk_buff *skb); - extern struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, @@ -228,24 +232,30 @@ extern int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, extern int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, const struct dccp_hdr *dh, const unsigned len); -extern int dccp_v4_init_sock(struct sock *sk); -extern int dccp_v4_destroy_sock(struct sock *sk); +extern int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized); +extern int dccp_destroy_sock(struct sock *sk); 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 struct sk_buff *dccp_make_reset(struct sock *sk, - struct dst_entry *dst, - enum dccp_reset_codes code); extern int dccp_connect(struct sock *sk); extern int dccp_disconnect(struct sock *sk, int flags); +extern void dccp_hash(struct sock *sk); extern void dccp_unhash(struct sock *sk); extern int dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int dccp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen); +#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 extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t size); @@ -256,21 +266,15 @@ extern void dccp_shutdown(struct sock *sk, int how); 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 void dccp_v4_send_check(struct sock *sk, int len, - struct sk_buff *skb); extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -extern int dccp_v4_checksum(const struct sk_buff *skb, - const u32 saddr, const u32 daddr); - -extern int dccp_v4_send_reset(struct sock *sk, - enum dccp_reset_codes code); +extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); extern int dccp_invalid_packet(struct sk_buff *skb); static inline int dccp_bad_service_code(const struct sock *sk, - const __u32 service) + const __be32 service) { const struct dccp_sock *dp = dccp_sk(sk); @@ -334,41 +338,29 @@ static inline void dccp_hdr_set_seq(struct dccp_hdr *dh, const u64 gss) { struct dccp_hdr_ext *dhx = (struct dccp_hdr_ext *)((void *)dh + sizeof(*dh)); - -#if defined(__LITTLE_ENDIAN_BITFIELD) - dh->dccph_seq = htonl((gss >> 32)) >> 8; -#elif defined(__BIG_ENDIAN_BITFIELD) - dh->dccph_seq = htonl((gss >> 32)); -#else -#error "Adjust your defines" -#endif + dh->dccph_seq2 = 0; + dh->dccph_seq = htons((gss >> 32) & 0xfffff); dhx->dccph_seq_low = htonl(gss & 0xffffffff); } static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack, const u64 gsr) { -#if defined(__LITTLE_ENDIAN_BITFIELD) - dhack->dccph_ack_nr_high = htonl((gsr >> 32)) >> 8; -#elif defined(__BIG_ENDIAN_BITFIELD) - dhack->dccph_ack_nr_high = htonl((gsr >> 32)); -#else -#error "Adjust your defines" -#endif + dhack->dccph_reserved1 = 0; + dhack->dccph_ack_nr_high = htons(gsr >> 32); 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); + const struct dccp_minisock *dmsk = dccp_msk(sk); dp->dccps_gsr = seq; dccp_set_seqno(&dp->dccps_swl, - (dp->dccps_gsr + 1 - - (dp->dccps_options.dccpo_sequence_window / 4))); + dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4)); dccp_set_seqno(&dp->dccps_swh, - (dp->dccps_gsr + - (3 * dp->dccps_options.dccpo_sequence_window) / 4)); + dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4); } static inline void dccp_update_gss(struct sock *sk, u64 seq) @@ -378,7 +370,7 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq) dp->dccps_awh = dp->dccps_gss = seq; dccp_set_seqno(&dp->dccps_awl, (dp->dccps_gss - - dp->dccps_options.dccpo_sequence_window + 1)); + dccp_msk(sk)->dccpms_sequence_window + 1)); } static inline int dccp_ack_pending(const struct sock *sk) @@ -386,24 +378,22 @@ 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 - (dp->dccps_options.dccpo_send_ack_vector && + (dccp_msk(sk)->dccpms_send_ack_vector && dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) || #endif inet_csk_ack_scheduled(sk); } -extern void dccp_insert_options(struct sock *sk, struct sk_buff *skb); -extern void dccp_insert_option_elapsed_time(struct sock *sk, +extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); +extern int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb, u32 elapsed_time); -extern void dccp_insert_option_timestamp(struct sock *sk, +extern int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb); -extern void dccp_insert_option(struct sock *sk, struct sk_buff *skb, +extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb, unsigned char option, const void *value, unsigned char len); -extern struct socket *dccp_ctl_socket; - extern void dccp_timestamp(const struct sock *sk, struct timeval *tv); static inline suseconds_t timeval_usecs(const struct timeval *tv) @@ -442,6 +432,21 @@ static inline void timeval_sub_usecs(struct timeval *tv, tv->tv_sec--; tv->tv_usec += USEC_PER_SEC; } + DCCP_BUG_ON(tv->tv_sec < 0); +} + +#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 + #endif /* _DCCP_H */