Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.25-rc7 /net/dccp/options.c

Filename:/net/dccp/options.c
Lines Added:91
Lines Deleted:48
Also changed in: (Previous) 2.6.25-rc6  2.6.25-rc5  2.6.25-rc4  2.6.25-rc3  2.6.25-rc2  2.6.25-rc1 
(Following) 2.6.25-rc8  2.6.25-rc9  2.6.25  2.6.26-rc6-git2  2.6.26-rc6-git3  2.6.26-rc6-git4 

Location
[  2.6.25-rc7
  [  net
    [  dccp
       o  options.c

Patch

diff --git a/net/dccp/options.c b/net/dccp/options.c
index d286cff..d2a84a2 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -46,7 +46,13 @@ static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
    return value;
 }
 
-int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
+/**
+ * dccp_parse_options  -  Parse DCCP options present in @skb
+ * @sk: client|server|listening dccp socket (when @dreq != NULL)
+ * @dreq: request socket to use during connection setup, or NULL
+ */
+int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
+             struct sk_buff *skb)
 {
    struct dccp_sock *dp = dccp_sk(sk);
    const struct dccp_hdr *dh = dccp_hdr(skb);
@@ -92,6 +98,20 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
             goto out_invalid_option;
       }
 
+      /*
+       * CCID-Specific Options (from RFC 4340, sec. 10.3):
+       *
+       * Option numbers 128 through 191 are for options sent from the
+       * HC-Sender to the HC-Receiver; option numbers 192 through 255
+       * are for options sent from the HC-Receiver to   the HC-Sender.
+       *
+       * CCID-specific options are ignored during connection setup, as
+       * negotiation may still be in progress (see RFC 4340, 10.3).
+       *
+       */
+      if (dreq != NULL && opt >= 128)
+         goto ignore_option;
+
       switch (opt) {
       case DCCPO_PADDING:
          break;
@@ -112,6 +132,8 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
       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,
@@ -128,7 +150,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
       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))
@@ -136,7 +160,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
          break;
       case DCCPO_ACK_VECTOR_0:
       case DCCPO_ACK_VECTOR_1:
-         if (pkt_type == DCCP_PKT_DATA)
+         if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
             break;
 
          if (dccp_msk(sk)->dccpms_send_ack_vector &&
@@ -146,15 +170,27 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
       case DCCPO_TIMESTAMP:
          if (len != 4)
             goto out_invalid_option;
-
+         /*
+          * RFC 4340 13.1: "The precise time corresponding to
+          * Timestamp Value zero is not specified". We use
+          * zero to indicate absence of a meaningful timestamp.
+          */
          opt_val = get_unaligned((__be32 *)value);
-         opt_recv->dccpor_timestamp = ntohl(opt_val);
-
-         dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp;
-         dp->dccps_timestamp_time = ktime_get_real();
+         if (unlikely(opt_val == 0)) {
+            DCCP_WARN("Timestamp with zero value\n");
+            break;
+         }
 
+         if (dreq != NULL) {
+            dreq->dreq_timestamp_echo = ntohl(opt_val);
+            dreq->dreq_timestamp_time = dccp_timestamp();
+         } else {
+            opt_recv->dccpor_timestamp =
+               dp->dccps_timestamp_echo = ntohl(opt_val);
+            dp->dccps_timestamp_time = dccp_timestamp();
+         }
          dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n",
-                  dccp_role(sk), opt_recv->dccpor_timestamp,
+                  dccp_role(sk), ntohl(opt_val),
                   (unsigned long long)
                   DCCP_SKB_CB(skb)->dccpd_ack_seq);
          break;
@@ -194,18 +230,17 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
             opt_recv->dccpor_elapsed_time = elapsed_time;
          break;
       case DCCPO_ELAPSED_TIME:
-         if (len != 2 && len != 4)
-            goto out_invalid_option;
-
-         if (pkt_type == DCCP_PKT_DATA)
-            continue;
+         if (dccp_packet_without_ack(skb))   /* RFC 4340, 13.2 */
+            break;
 
          if (len == 2) {
             __be16 opt_val2 = get_unaligned((__be16 *)value);
             elapsed_time = ntohs(opt_val2);
-         } else {
+         } else if (len == 4) {
             opt_val = get_unaligned((__be32 *)value);
             elapsed_time = ntohl(opt_val);
+         } else {
+            goto out_invalid_option;
          }
 
          if (elapsed_time > opt_recv->dccpor_elapsed_time)
@@ -214,15 +249,6 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
          dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n",
                   dccp_role(sk), elapsed_time);
          break;
-         /*
-          * From RFC 4340, sec. 10.3:
-          *
-          *   Option numbers 128 through 191 are for
-          *   options sent from the HC-Sender to the
-          *   HC-Receiver; option numbers 192 through 255
-          *   are for options sent from the HC-Receiver to
-          *   the HC-Sender.
-          */
       case 128 ... 191: {
          const u16 idx = value - options;
 
@@ -246,7 +272,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
               "implemented, ignoring", sk, opt, len);
          break;
       }
-
+ignore_option:
       if (opt != DCCPO_MANDATORY)
          mandatory = 0;
    }
@@ -382,16 +408,24 @@ int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
 
 EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
 
-static int dccp_insert_option_timestamp_echo(struct sock *sk,
+static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
+                    struct dccp_request_sock *dreq,
                     struct sk_buff *skb)
 {
-   struct dccp_sock *dp = dccp_sk(sk);
    __be32 tstamp_echo;
-   int len, elapsed_time_len;
    unsigned char *to;
-   const suseconds_t delta = ktime_us_delta(ktime_get_real(),
-                   dp->dccps_timestamp_time);
-   u32 elapsed_time = delta / 10;
+   u32 elapsed_time, elapsed_time_len, len;
+
+   if (dreq != NULL) {
+      elapsed_time = dccp_timestamp() - dreq->dreq_timestamp_time;
+      tstamp_echo  = htonl(dreq->dreq_timestamp_echo);
+      dreq->dreq_timestamp_echo = 0;
+   } else {
+      elapsed_time = dccp_timestamp() - dp->dccps_timestamp_time;
+      tstamp_echo  = htonl(dp->dccps_timestamp_echo);
+      dp->dccps_timestamp_echo = 0;
+   }
+
    elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
    len = 6 + elapsed_time_len;
 
@@ -404,7 +438,6 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk,
    *to++ = DCCPO_TIMESTAMP_ECHO;
    *to++ = len;
 
-   tstamp_echo = htonl(dp->dccps_timestamp_echo);
    memcpy(to, &tstamp_echo, 4);
    to += 4;
 
@@ -416,8 +449,6 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk,
       memcpy(to, &var32, 4);
    }
 
-   dp->dccps_timestamp_echo = 0;
-   dp->dccps_timestamp_time = ktime_set(0, 0);
    return 0;
 }
 
@@ -510,6 +541,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);
@@ -526,10 +569,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
           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) {
@@ -553,18 +592,22 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
        dccp_insert_option_timestamp(sk, skb))
       return -1;
 
-   /* XXX: insert other options when appropriate */
+   if (dp->dccps_timestamp_echo != 0 &&
+       dccp_insert_option_timestamp_echo(dp, NULL, skb))
+      return -1;
+
+   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;
 }


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.