]> Pileus Git - ~andy/linux/blobdiff - net/dccp/options.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[~andy/linux] / net / dccp / options.c
index 0c996d8c79a31a0ae82de53ffc61d887e231061f..43bc24e761d0e707fca63a4404e061c270a071bc 100644 (file)
@@ -107,9 +107,11 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                 *
                 * CCID-specific options are ignored during connection setup, as
                 * negotiation may still be in progress (see RFC 4340, 10.3).
+                * The same applies to Ack Vectors, as these depend on the CCID.
                 *
                 */
-               if (dreq != NULL && opt >= 128)
+               if (dreq != NULL && (opt >= 128 ||
+                   opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1))
                        goto ignore_option;
 
                switch (opt) {
@@ -132,6 +134,8 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                case DCCPO_CHANGE_L:
                        /* fall through */
                case DCCPO_CHANGE_R:
+                       if (pkt_type == DCCP_PKT_DATA)
+                               break;
                        if (len < 2)
                                goto out_invalid_option;
                        rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
@@ -148,7 +152,9 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                case DCCPO_CONFIRM_L:
                        /* fall through */
                case DCCPO_CONFIRM_R:
-                       if (len < 2)
+                       if (pkt_type == DCCP_PKT_DATA)
+                               break;
+                       if (len < 2)    /* FIXME this disallows empty confirm */
                                goto out_invalid_option;
                        if (dccp_feat_confirm_recv(sk, opt, *value,
                                                   value + 1, len - 1))
@@ -537,6 +543,18 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
+/* The length of all options needs to be a multiple of 4 (5.8) */
+static void dccp_insert_option_padding(struct sk_buff *skb)
+{
+       int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4;
+
+       if (padding != 0) {
+               padding = 4 - padding;
+               memset(skb_push(skb, padding), 0, padding);
+               DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
+       }
+}
+
 int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
@@ -580,18 +598,18 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
            dccp_insert_option_timestamp_echo(dp, NULL, skb))
                return -1;
 
-       /* XXX: insert other options when appropriate */
+       dccp_insert_option_padding(skb);
+       return 0;
+}
 
-       if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) {
-               /* The length of all options has to be a multiple of 4 */
-               int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4;
+int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
+{
+       DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
-               if (padding != 0) {
-                       padding = 4 - padding;
-                       memset(skb_push(skb, padding), 0, padding);
-                       DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
-               }
-       }
+       if (dreq->dreq_timestamp_echo != 0 &&
+           dccp_insert_option_timestamp_echo(NULL, dreq, skb))
+               return -1;
 
+       dccp_insert_option_padding(skb);
        return 0;
 }