]> err.no Git - linux-2.6/blobdiff - net/dccp/options.c
Merge with git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / net / dccp / options.c
index 79d228e4d6b21ca2fa1633dd81a1e00f928e673f..e9feb2a0c7706ef1a464d3d7428dac77cc36013d 100644 (file)
@@ -30,14 +30,14 @@ 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;
 
-void dccp_options_init(struct dccp_options *dccpo)
+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 = 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;
 }
 
 static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
@@ -78,6 +78,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;
@@ -109,7 +110,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                case DCCPO_MANDATORY:
                        if (mandatory)
                                goto out_invalid_option;
-                       mandatory = 1;
+                       if (pkt_type != DCCP_PKT_DATA)
+                               mandatory = 1;
                        break;
                case DCCPO_NDP_COUNT:
                        if (len > 3)
@@ -147,9 +149,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                case DCCPO_ACK_VECTOR_0:
                case DCCPO_ACK_VECTOR_1:
                        if (pkt_type == DCCP_PKT_DATA)
-                               continue;
+                               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;
@@ -249,6 +251,10 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                        mandatory = 0;
        }
 
+       /* mandatory was the last byte in option list -> reset connection */
+       if (mandatory)
+               goto out_invalid_option;
+
        return 0;
 
 out_invalid_option:
@@ -278,17 +284,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;
 
@@ -297,11 +300,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;
@@ -317,7 +321,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;
 
@@ -326,6 +330,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)
@@ -333,27 +339,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;
 
@@ -369,10 +366,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);
@@ -393,7 +387,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;
@@ -403,19 +397,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;
@@ -427,11 +417,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;
 
@@ -451,14 +438,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,
@@ -486,15 +469,15 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
        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);
@@ -503,11 +486,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,
@@ -546,44 +528,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 */
 
@@ -597,4 +584,6 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
                        DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
                }
        }
+
+       return 0;
 }