]> err.no Git - linux-2.6/blobdiff - net/dccp/options.c
[DCCP]: Simplified conditions due to use of enum:8 states
[linux-2.6] / net / dccp / options.c
index 0161a18e739a3629f8775f634adac92aece87894..ee709ae0a97f583f21f87af6b9a282d8f1deb03b 100644 (file)
@@ -4,14 +4,13 @@
  *  An implementation of the DCCP protocol
  *  Copyright (c) 2005 Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
  *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
- *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *  Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz>
  *
  *      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/config.h>
 #include <linux/dccp.h>
 #include <linux/module.h>
 #include <linux/types.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;
+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;
 
-void dccp_options_init(struct dccp_options *dccpo)
+EXPORT_SYMBOL_GPL(sysctl_dccp_feat_sequence_window);
+
+void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
-       dccpo->dccpo_sequence_window = dccp_feat_default_sequence_window;
-       dccpo->dccpo_rx_ccid         = dccp_feat_default_rx_ccid;
-       dccpo->dccpo_tx_ccid         = dccp_feat_default_tx_ccid;
-       dccpo->dccpo_ack_ratio       = dccp_feat_default_ack_ratio;
-       dccpo->dccpo_send_ack_vector = dccp_feat_default_send_ack_vector;
-       dccpo->dccpo_send_ndp_count  = dccp_feat_default_send_ndp_count;
+       dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
+       dmsk->dccpms_rx_ccid         = sysctl_dccp_feat_rx_ccid;
+       dmsk->dccpms_tx_ccid         = sysctl_dccp_feat_tx_ccid;
+       dmsk->dccpms_ack_ratio       = sysctl_dccp_feat_ack_ratio;
+       dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
+       dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
 
 static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
@@ -59,10 +60,6 @@ static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
 int dccp_parse_options(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 rx opt: " : "server rx opt: ";
-#endif
        const struct dccp_hdr *dh = dccp_hdr(skb);
        const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type;
        unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
@@ -78,6 +75,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
 
        memset(opt_recv, 0, sizeof(*opt_recv));
 
+       opt = len = 0;
        while (opt_ptr != opt_end) {
                opt   = *opt_ptr++;
                len   = 0;
@@ -117,7 +115,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                                goto out_invalid_option;
 
                        opt_recv->dccpor_ndp = dccp_decode_value_var(value, len);
-                       dccp_pr_debug("%sNDP count=%d\n", debug_prefix,
+                       dccp_pr_debug("%s rx opt: NDP count=%d\n", dccp_role(sk),
                                      opt_recv->dccpor_ndp);
                        break;
                case DCCPO_CHANGE_L:
@@ -150,7 +148,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                        if (pkt_type == DCCP_PKT_DATA)
                                break;
 
-                       if (dp->dccps_options.dccpo_send_ack_vector &&
+                       if (dccp_msk(sk)->dccpms_send_ack_vector &&
                            dccp_ackvec_parse(sk, skb, opt, value, len))
                                goto out_invalid_option;
                        break;
@@ -163,8 +161,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                        dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp;
                        dccp_timestamp(sk, &dp->dccps_timestamp_time);
 
-                       dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n",
-                                     debug_prefix, opt_recv->dccpor_timestamp,
+                       dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n",
+                                     dccp_role(sk), opt_recv->dccpor_timestamp,
                                      (unsigned long long)
                                      DCCP_SKB_CB(skb)->dccpd_ack_seq);
                        break;
@@ -174,8 +172,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
 
                        opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value);
 
-                       dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ",
-                                     debug_prefix,
+                       dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, "
+                                     "ackno=%llu, ",  dccp_role(sk),
                                      opt_recv->dccpor_timestamp_echo,
                                      len + 2,
                                      (unsigned long long)
@@ -209,11 +207,11 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                        if (elapsed_time > opt_recv->dccpor_elapsed_time)
                                opt_recv->dccpor_elapsed_time = elapsed_time;
 
-                       dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix,
-                                     elapsed_time);
+                       dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n",
+                                     dccp_role(sk), elapsed_time);
                        break;
                        /*
-                        * From draft-ietf-dccp-spec-11.txt:
+                        * From RFC 4340, sec. 10.3:
                         *
                         *      Option numbers 128 through 191 are for
                         *      options sent from the HC-Sender to the
@@ -240,9 +238,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                }
                        break;
                default:
-                       pr_info("DCCP(%p): option %d(len=%d) not "
-                               "implemented, ignoring\n",
-                               sk, opt, len);
+                       DCCP_CRIT("DCCP(%p): option %d(len=%d) not "
+                                 "implemented, ignoring", sk, opt, len);
                        break;
                }
 
@@ -259,7 +256,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
 out_invalid_option:
        DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
        DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
-       pr_info("DCCP(%p): invalid option %d, len=%d\n", sk, opt, len);
+       DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
        return -1;
 }
 
@@ -283,17 +280,14 @@ static inline int dccp_ndp_len(const int ndp)
        return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3;
 }
 
-void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
+int 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) {
-               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
-                              "%d option!\n", option);
-               return;
-       }
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN)
+               return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2;
 
@@ -302,11 +296,12 @@ void 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 void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
+static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
        int ndp = dp->dccps_ndp_count;
@@ -322,7 +317,7 @@ static void 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;
+                       return -1;
 
                DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
@@ -331,6 +326,8 @@ static void 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)
@@ -338,27 +335,18 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time)
        return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
 }
 
-void dccp_insert_option_elapsed_time(struct sock *sk,
-                                    struct sk_buff *skb,
-                                    u32 elapsed_time)
+int 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;
+               return 0;
 
-       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;
-       }
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+               return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
@@ -374,10 +362,7 @@ void dccp_insert_option_elapsed_time(struct sock *sk,
                memcpy(to, &var32, 4);
        }
 
-       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);
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
@@ -398,7 +383,7 @@ void dccp_timestamp(const struct sock *sk, struct timeval *tv)
 
 EXPORT_SYMBOL_GPL(dccp_timestamp);
 
-void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
+int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
 {
        struct timeval tv;
        __be32 now;
@@ -408,19 +393,15 @@ void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
        /* 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 */
 
-       dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
+       return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
 }
 
 EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
 
-static void dccp_insert_option_timestamp_echo(struct sock *sk,
-                                             struct sk_buff *skb)
+static int 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 elapsed_time;
@@ -432,11 +413,8 @@ static void 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) {
-               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
-                                        "timestamp echo!\n");
-               return;
-       }
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+               return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
@@ -456,14 +434,10 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk,
                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,
@@ -472,8 +446,7 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
        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);
+               DCCP_WARN("packet too small for feature %d option!\n", feat);
                return -1;
        }
 
@@ -486,20 +459,22 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 
        if (len)
                memcpy(to, val, len);
-       dccp_pr_debug("option %d feat %d len %d\n", type, feat, len);
 
+       dccp_pr_debug("%s(%s (%d), ...), length %d\n",
+                     dccp_feat_typename(type),
+                     dccp_feat_name(feat), feat, len);
        return 0;
 }
 
-static void dccp_insert_feat(struct sock *sk, struct sk_buff *skb)
+static int dccp_insert_options_feat(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, &dp->dccps_options.dccpo_conf,
-                                dccpop_node) {
+       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);
@@ -508,11 +483,10 @@ static void dccp_insert_feat(struct sock *sk, struct sk_buff *skb)
                        kfree(opt->dccpop_val);
                kfree(opt);
        }
-       INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
+       INIT_LIST_HEAD(&dmsk->dccpms_conf);
 
        /* see which features we need to send */
-       list_for_each_entry(opt, &dp->dccps_options.dccpo_pending,
-                           dccpop_node) {
+       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,
@@ -551,44 +525,49 @@ static void dccp_insert_feat(struct sock *sk, struct sk_buff *skb)
                inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                                          inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
        }
+
+       return 0;
 }
 
-void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
+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 (dp->dccps_options.dccpo_send_ndp_count)
-               dccp_insert_option_ndp(sk, skb);
+       if (dmsk->dccpms_send_ndp_count &&
+           dccp_insert_option_ndp(sk, skb))
+               return -1;
 
        if (!dccp_packet_without_ack(skb)) {
-               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 (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_hc_rx_insert_options) {
-               ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb);
+               if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb))
+                       return -1;
                dp->dccps_hc_rx_insert_options = 0;
        }
        if (dp->dccps_hc_tx_insert_options) {
-               ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb);
+               if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb))
+                       return -1;
                dp->dccps_hc_tx_insert_options = 0;
        }
 
        /* Feature negotiation */
-       switch(DCCP_SKB_CB(skb)->dccpd_type) {
-               /* Data packets can't do feat negotiation */
-       case DCCP_PKT_DATA:
-       case DCCP_PKT_DATAACK:
-               break;
-       default:
-               dccp_insert_feat(sk, skb);
-               break;
-       }
+       /* 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 */
 
@@ -602,4 +581,6 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
                        DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
                }
        }
+
+       return 0;
 }