diff options
Diffstat (limited to 'net/dccp/ackvec.c')
-rw-r--r-- | net/dccp/ackvec.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 41d34d1babc1..bdf1bb7a82c0 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
@@ -68,10 +68,15 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
68 | { | 68 | { |
69 | struct dccp_sock *dp = dccp_sk(sk); | 69 | struct dccp_sock *dp = dccp_sk(sk); |
70 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | 70 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; |
71 | int len = av->dccpav_vec_len + 2; | 71 | /* Figure out how many options do we need to represent the ackvec */ |
72 | const u16 nr_opts = (av->dccpav_vec_len + | ||
73 | DCCP_MAX_ACKVEC_OPT_LEN - 1) / | ||
74 | DCCP_MAX_ACKVEC_OPT_LEN; | ||
75 | u16 len = av->dccpav_vec_len + 2 * nr_opts, i; | ||
72 | struct timeval now; | 76 | struct timeval now; |
73 | u32 elapsed_time; | 77 | u32 elapsed_time; |
74 | unsigned char *to, *from; | 78 | const unsigned char *tail, *from; |
79 | unsigned char *to; | ||
75 | struct dccp_ackvec_record *avr; | 80 | struct dccp_ackvec_record *avr; |
76 | 81 | ||
77 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | 82 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
@@ -90,24 +95,37 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
90 | 95 | ||
91 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 96 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
92 | 97 | ||
93 | to = skb_push(skb, len); | 98 | to = skb_push(skb, len); |
94 | *to++ = DCCPO_ACK_VECTOR_0; | ||
95 | *to++ = len; | ||
96 | |||
97 | len = av->dccpav_vec_len; | 99 | len = av->dccpav_vec_len; |
98 | from = av->dccpav_buf + av->dccpav_buf_head; | 100 | from = av->dccpav_buf + av->dccpav_buf_head; |
101 | tail = av->dccpav_buf + DCCP_MAX_ACKVEC_LEN; | ||
102 | |||
103 | for (i = 0; i < nr_opts; ++i) { | ||
104 | int copylen = len; | ||
105 | |||
106 | if (len > DCCP_MAX_ACKVEC_OPT_LEN) | ||
107 | copylen = DCCP_MAX_ACKVEC_OPT_LEN; | ||
99 | 108 | ||
100 | /* Check if buf_head wraps */ | 109 | *to++ = DCCPO_ACK_VECTOR_0; |
101 | if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) { | 110 | *to++ = copylen + 2; |
102 | const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head; | 111 | |
112 | /* Check if buf_head wraps */ | ||
113 | if (from + copylen > tail) { | ||
114 | const u16 tailsize = tail - from; | ||
115 | |||
116 | memcpy(to, from, tailsize); | ||
117 | to += tailsize; | ||
118 | len -= tailsize; | ||
119 | copylen -= tailsize; | ||
120 | from = av->dccpav_buf; | ||
121 | } | ||
103 | 122 | ||
104 | memcpy(to, from, tailsize); | 123 | memcpy(to, from, copylen); |
105 | to += tailsize; | 124 | from += copylen; |
106 | len -= tailsize; | 125 | to += copylen; |
107 | from = av->dccpav_buf; | 126 | len -= copylen; |
108 | } | 127 | } |
109 | 128 | ||
110 | memcpy(to, from, len); | ||
111 | /* | 129 | /* |
112 | * From RFC 4340, A.2: | 130 | * From RFC 4340, A.2: |
113 | * | 131 | * |