X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fdccp%2Foptions.c;h=0a76426c9aeab322f6eae5dd8e8e2309e1454d98;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=e9feb2a0c7706ef1a464d3d7428dac77cc36013d;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/net/dccp/options.c b/net/dccp/options.c index e9feb2a0c..0a76426c9 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -21,23 +21,19 @@ #include "ackvec.h" #include "ccid.h" #include "dccp.h" -#include "feat.h" -int dccp_feat_default_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW; -int dccp_feat_default_rx_ccid = DCCPF_INITIAL_CCID; -int dccp_feat_default_tx_ccid = DCCPF_INITIAL_CCID; -int dccp_feat_default_ack_ratio = DCCPF_INITIAL_ACK_RATIO; -int dccp_feat_default_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR; -int dccp_feat_default_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT; +/* stores the default values for new connection. may be changed with sysctl */ +static const struct dccp_options dccpo_default_values = { + .dccpo_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW, + .dccpo_rx_ccid = DCCPF_INITIAL_CCID, + .dccpo_tx_ccid = DCCPF_INITIAL_CCID, + .dccpo_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR, + .dccpo_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT, +}; -void dccp_minisock_init(struct dccp_minisock *dmsk) +void dccp_options_init(struct dccp_options *dccpo) { - dmsk->dccpms_sequence_window = dccp_feat_default_sequence_window; - dmsk->dccpms_rx_ccid = dccp_feat_default_rx_ccid; - dmsk->dccpms_tx_ccid = dccp_feat_default_tx_ccid; - dmsk->dccpms_ack_ratio = dccp_feat_default_ack_ratio; - dmsk->dccpms_send_ack_vector = dccp_feat_default_send_ack_vector; - dmsk->dccpms_send_ndp_count = dccp_feat_default_send_ndp_count; + memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo)); } static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) @@ -73,12 +69,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) unsigned char opt, len; unsigned char *value; u32 elapsed_time; - int rc; - int mandatory = 0; memset(opt_recv, 0, sizeof(*opt_recv)); - opt = len = 0; while (opt_ptr != opt_end) { opt = *opt_ptr++; len = 0; @@ -107,12 +100,6 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) switch (opt) { case DCCPO_PADDING: break; - case DCCPO_MANDATORY: - if (mandatory) - goto out_invalid_option; - if (pkt_type != DCCP_PKT_DATA) - mandatory = 1; - break; case DCCPO_NDP_COUNT: if (len > 3) goto out_invalid_option; @@ -121,37 +108,12 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) dccp_pr_debug("%sNDP count=%d\n", debug_prefix, opt_recv->dccpor_ndp); break; - 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; case DCCPO_ACK_VECTOR_0: case DCCPO_ACK_VECTOR_1: if (pkt_type == DCCP_PKT_DATA) - break; + continue; - if (dccp_msk(sk)->dccpms_send_ack_vector && + if (dp->dccps_options.dccpo_send_ack_vector && dccp_ackvec_parse(sk, skb, opt, value, len)) goto out_invalid_option; break; @@ -159,7 +121,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) if (len != 4) goto out_invalid_option; - opt_recv->dccpor_timestamp = ntohl(*(__be32 *)value); + opt_recv->dccpor_timestamp = ntohl(*(u32 *)value); dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; dccp_timestamp(sk, &dp->dccps_timestamp_time); @@ -173,7 +135,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) if (len != 4 && len != 6 && len != 8) goto out_invalid_option; - opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value); + opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value); dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", debug_prefix, @@ -187,9 +149,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) break; if (len == 6) - elapsed_time = ntohs(*(__be16 *)(value + 4)); + elapsed_time = ntohs(*(u16 *)(value + 4)); else - elapsed_time = ntohl(*(__be32 *)(value + 4)); + elapsed_time = ntohl(*(u32 *)(value + 4)); /* Give precedence to the biggest ELAPSED_TIME */ if (elapsed_time > opt_recv->dccpor_elapsed_time) @@ -203,9 +165,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) continue; if (len == 2) - elapsed_time = ntohs(*(__be16 *)value); + elapsed_time = ntohs(*(u16 *)value); else - elapsed_time = ntohl(*(__be32 *)value); + elapsed_time = ntohl(*(u32 *)value); if (elapsed_time > opt_recv->dccpor_elapsed_time) opt_recv->dccpor_elapsed_time = elapsed_time; @@ -246,15 +208,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) sk, opt, len); break; } - - if (opt != DCCPO_MANDATORY) - mandatory = 0; } - /* mandatory was the last byte in option list -> reset connection */ - if (mandatory) - goto out_invalid_option; - return 0; out_invalid_option: @@ -264,8 +219,6 @@ out_invalid_option: return -1; } -EXPORT_SYMBOL_GPL(dccp_parse_options); - static void dccp_encode_value_var(const u32 value, unsigned char *to, const unsigned int len) { @@ -284,14 +237,17 @@ static inline int dccp_ndp_len(const int ndp) return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; } -int dccp_insert_option(struct sock *sk, struct sk_buff *skb, +void dccp_insert_option(struct sock *sk, struct sk_buff *skb, const unsigned char option, const void *value, const unsigned char len) { unsigned char *to; - if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) - return -1; + if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) { + LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " + "%d option!\n", option); + return; + } DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; @@ -300,12 +256,11 @@ int dccp_insert_option(struct sock *sk, struct sk_buff *skb, *to++ = len + 2; memcpy(to, value, len); - return 0; } EXPORT_SYMBOL_GPL(dccp_insert_option); -static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) +static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); int ndp = dp->dccps_ndp_count; @@ -321,7 +276,7 @@ static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) const int len = ndp_len + 2; if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) - return -1; + return; DCCP_SKB_CB(skb)->dccpd_opt_len += len; @@ -330,8 +285,6 @@ static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) *ptr++ = len; dccp_encode_value_var(ndp, ptr, ndp_len); } - - return 0; } static inline int dccp_elapsed_time_len(const u32 elapsed_time) @@ -339,18 +292,27 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time) return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; } -int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb, - u32 elapsed_time) +void dccp_insert_option_elapsed_time(struct sock *sk, + struct sk_buff *skb, + u32 elapsed_time) { +#ifdef CONFIG_IP_DCCP_DEBUG + struct dccp_sock *dp = dccp_sk(sk); + const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? + "CLIENT TX opt: " : "server TX opt: "; +#endif const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); const int len = 2 + elapsed_time_len; unsigned char *to; if (elapsed_time_len == 0) - return 0; + return; - if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) - return -1; + if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { + LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " + "insert elapsed time!\n"); + return; + } DCCP_SKB_CB(skb)->dccpd_opt_len += len; @@ -359,14 +321,17 @@ int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb, *to++ = len; if (elapsed_time_len == 2) { - const __be16 var16 = htons((u16)elapsed_time); + const u16 var16 = htons((u16)elapsed_time); memcpy(to, &var16, 2); } else { - const __be32 var32 = htonl(elapsed_time); + const u32 var32 = htonl(elapsed_time); memcpy(to, &var32, 4); } - return 0; + dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n", + debug_prefix, elapsed_time, + len, + (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); } EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); @@ -387,27 +352,32 @@ void dccp_timestamp(const struct sock *sk, struct timeval *tv) EXPORT_SYMBOL_GPL(dccp_timestamp); -int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) +void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) { struct timeval tv; - __be32 now; - + u32 now; + dccp_timestamp(sk, &tv); - now = htonl(timeval_usecs(&tv) / 10); + now = timeval_usecs(&tv) / 10; /* 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 */ - return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); + now = htonl(now); + dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); } EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); -static int dccp_insert_option_timestamp_echo(struct sock *sk, - struct sk_buff *skb) +static void dccp_insert_option_timestamp_echo(struct sock *sk, + struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); +#ifdef CONFIG_IP_DCCP_DEBUG + const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? + "CLIENT TX opt: " : "server TX opt: "; +#endif struct timeval now; - __be32 tstamp_echo; + u32 tstamp_echo; u32 elapsed_time; int len, elapsed_time_len; unsigned char *to; @@ -417,8 +387,11 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk, elapsed_time_len = dccp_elapsed_time_len(elapsed_time); len = 6 + elapsed_time_len; - if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) - return -1; + if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { + LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " + "timestamp echo!\n"); + return; + } DCCP_SKB_CB(skb)->dccpd_opt_len += len; @@ -429,149 +402,51 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk, tstamp_echo = htonl(dp->dccps_timestamp_echo); memcpy(to, &tstamp_echo, 4); to += 4; - + if (elapsed_time_len == 2) { - const __be16 var16 = htons((u16)elapsed_time); + const u16 var16 = htons((u16)elapsed_time); memcpy(to, &var16, 2); } else if (elapsed_time_len == 4) { - const __be32 var32 = htonl(elapsed_time); + const u32 var32 = htonl(elapsed_time); memcpy(to, &var32, 4); } + dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n", + debug_prefix, dp->dccps_timestamp_echo, + len, + (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); + dp->dccps_timestamp_echo = 0; dp->dccps_timestamp_time.tv_sec = 0; dp->dccps_timestamp_time.tv_usec = 0; - return 0; } -static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, - u8 *val, u8 len) -{ - u8 *to; - - if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) { - LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small" - " to insert feature %d option!\n", feat); - 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_pr_debug("option %d feat %d len %d\n", type, feat, len); - - return 0; -} - -static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) +void dccp_insert_options(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); - struct dccp_minisock *dmsk = dccp_msk(sk); - struct dccp_opt_pend *opt, *next; - int change = 0; - - /* confirm any options [NN opts] */ - list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { - 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); - } - INIT_LIST_HEAD(&dmsk->dccpms_conf); - - /* see which features we need to send */ - list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { - /* 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); - } - - return 0; -} - -int dccp_insert_options(struct sock *sk, struct sk_buff *skb) -{ - struct dccp_sock *dp = dccp_sk(sk); - struct dccp_minisock *dmsk = dccp_msk(sk); DCCP_SKB_CB(skb)->dccpd_opt_len = 0; - if (dmsk->dccpms_send_ndp_count && - dccp_insert_option_ndp(sk, skb)) - return -1; + if (dp->dccps_options.dccpo_send_ndp_count) + dccp_insert_option_ndp(sk, skb); if (!dccp_packet_without_ack(skb)) { - if (dmsk->dccpms_send_ack_vector && - 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; + if (dp->dccps_options.dccpo_send_ack_vector && + dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) + dccp_insert_option_ackvec(sk, skb); + if (dp->dccps_timestamp_echo != 0) + dccp_insert_option_timestamp_echo(sk, skb); } if (dp->dccps_hc_rx_insert_options) { - if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb)) - return -1; + ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); dp->dccps_hc_rx_insert_options = 0; } if (dp->dccps_hc_tx_insert_options) { - if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb)) - return -1; + ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); dp->dccps_hc_tx_insert_options = 0; } - /* Feature negotiation */ - /* 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; - /* XXX: insert other options when appropriate */ if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { @@ -584,6 +459,4 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb) DCCP_SKB_CB(skb)->dccpd_opt_len += padding; } } - - return 0; }