diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/dccp.h | 2 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 9 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 16 | ||||
-rw-r--r-- | net/dccp/output.c | 53 | ||||
-rw-r--r-- | net/dccp/timer.c | 20 |
5 files changed, 56 insertions, 44 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 743d85fcd651..1c2e3ec2eb57 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -226,7 +226,7 @@ static inline void dccp_csum_outgoing(struct sk_buff *skb) | |||
226 | 226 | ||
227 | extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); | 227 | extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); |
228 | 228 | ||
229 | extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); | 229 | extern int dccp_retransmit_skb(struct sock *sk); |
230 | 230 | ||
231 | extern void dccp_send_ack(struct sock *sk); | 231 | extern void dccp_send_ack(struct sock *sk); |
232 | extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk); | 232 | extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk); |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index a835b88237cb..882c5c4de69e 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -196,8 +196,8 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, | |||
196 | static void dccp_v4_err(struct sk_buff *skb, u32 info) | 196 | static void dccp_v4_err(struct sk_buff *skb, u32 info) |
197 | { | 197 | { |
198 | const struct iphdr *iph = (struct iphdr *)skb->data; | 198 | const struct iphdr *iph = (struct iphdr *)skb->data; |
199 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + | 199 | const u8 offset = iph->ihl << 2; |
200 | (iph->ihl << 2)); | 200 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); |
201 | struct dccp_sock *dp; | 201 | struct dccp_sock *dp; |
202 | struct inet_sock *inet; | 202 | struct inet_sock *inet; |
203 | const int type = icmp_hdr(skb)->type; | 203 | const int type = icmp_hdr(skb)->type; |
@@ -207,7 +207,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) | |||
207 | int err; | 207 | int err; |
208 | struct net *net = dev_net(skb->dev); | 208 | struct net *net = dev_net(skb->dev); |
209 | 209 | ||
210 | if (skb->len < (iph->ihl << 2) + 8) { | 210 | if (skb->len < offset + sizeof(*dh) || |
211 | skb->len < offset + __dccp_basic_hdr_len(dh)) { | ||
211 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); | 212 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); |
212 | return; | 213 | return; |
213 | } | 214 | } |
@@ -238,7 +239,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) | |||
238 | dp = dccp_sk(sk); | 239 | dp = dccp_sk(sk); |
239 | seq = dccp_hdr_seq(dh); | 240 | seq = dccp_hdr_seq(dh); |
240 | if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && | 241 | if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && |
241 | !between48(seq, dp->dccps_swl, dp->dccps_swh)) { | 242 | !between48(seq, dp->dccps_awl, dp->dccps_awh)) { |
242 | NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); | 243 | NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); |
243 | goto out; | 244 | goto out; |
244 | } | 245 | } |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index da509127e00c..5e1ee0da2c40 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -89,12 +89,19 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
89 | { | 89 | { |
90 | struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; | 90 | struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; |
91 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); | 91 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); |
92 | struct dccp_sock *dp; | ||
92 | struct ipv6_pinfo *np; | 93 | struct ipv6_pinfo *np; |
93 | struct sock *sk; | 94 | struct sock *sk; |
94 | int err; | 95 | int err; |
95 | __u64 seq; | 96 | __u64 seq; |
96 | struct net *net = dev_net(skb->dev); | 97 | struct net *net = dev_net(skb->dev); |
97 | 98 | ||
99 | if (skb->len < offset + sizeof(*dh) || | ||
100 | skb->len < offset + __dccp_basic_hdr_len(dh)) { | ||
101 | ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); | ||
102 | return; | ||
103 | } | ||
104 | |||
98 | sk = inet6_lookup(net, &dccp_hashinfo, | 105 | sk = inet6_lookup(net, &dccp_hashinfo, |
99 | &hdr->daddr, dh->dccph_dport, | 106 | &hdr->daddr, dh->dccph_dport, |
100 | &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); | 107 | &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); |
@@ -116,6 +123,14 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
116 | if (sk->sk_state == DCCP_CLOSED) | 123 | if (sk->sk_state == DCCP_CLOSED) |
117 | goto out; | 124 | goto out; |
118 | 125 | ||
126 | dp = dccp_sk(sk); | ||
127 | seq = dccp_hdr_seq(dh); | ||
128 | if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && | ||
129 | !between48(seq, dp->dccps_awl, dp->dccps_awh)) { | ||
130 | NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); | ||
131 | goto out; | ||
132 | } | ||
133 | |||
119 | np = inet6_sk(sk); | 134 | np = inet6_sk(sk); |
120 | 135 | ||
121 | if (type == ICMPV6_PKT_TOOBIG) { | 136 | if (type == ICMPV6_PKT_TOOBIG) { |
@@ -168,7 +183,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
168 | 183 | ||
169 | icmpv6_err_convert(type, code, &err); | 184 | icmpv6_err_convert(type, code, &err); |
170 | 185 | ||
171 | seq = dccp_hdr_seq(dh); | ||
172 | /* Might be for an request_sock */ | 186 | /* Might be for an request_sock */ |
173 | switch (sk->sk_state) { | 187 | switch (sk->sk_state) { |
174 | struct request_sock *req, **prev; | 188 | struct request_sock *req, **prev; |
diff --git a/net/dccp/output.c b/net/dccp/output.c index fe20068c5d8e..d06945c7d3df 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -53,8 +53,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
53 | dccp_packet_hdr_len(dcb->dccpd_type); | 53 | dccp_packet_hdr_len(dcb->dccpd_type); |
54 | int err, set_ack = 1; | 54 | int err, set_ack = 1; |
55 | u64 ackno = dp->dccps_gsr; | 55 | u64 ackno = dp->dccps_gsr; |
56 | 56 | /* | |
57 | dccp_inc_seqno(&dp->dccps_gss); | 57 | * Increment GSS here already in case the option code needs it. |
58 | * Update GSS for real only if option processing below succeeds. | ||
59 | */ | ||
60 | dcb->dccpd_seq = ADD48(dp->dccps_gss, 1); | ||
58 | 61 | ||
59 | switch (dcb->dccpd_type) { | 62 | switch (dcb->dccpd_type) { |
60 | case DCCP_PKT_DATA: | 63 | case DCCP_PKT_DATA: |
@@ -66,6 +69,9 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
66 | 69 | ||
67 | case DCCP_PKT_REQUEST: | 70 | case DCCP_PKT_REQUEST: |
68 | set_ack = 0; | 71 | set_ack = 0; |
72 | /* Use ISS on the first (non-retransmitted) Request. */ | ||
73 | if (icsk->icsk_retransmits == 0) | ||
74 | dcb->dccpd_seq = dp->dccps_iss; | ||
69 | /* fall through */ | 75 | /* fall through */ |
70 | 76 | ||
71 | case DCCP_PKT_SYNC: | 77 | case DCCP_PKT_SYNC: |
@@ -84,8 +90,6 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
84 | break; | 90 | break; |
85 | } | 91 | } |
86 | 92 | ||
87 | dcb->dccpd_seq = dp->dccps_gss; | ||
88 | |||
89 | if (dccp_insert_options(sk, skb)) { | 93 | if (dccp_insert_options(sk, skb)) { |
90 | kfree_skb(skb); | 94 | kfree_skb(skb); |
91 | return -EPROTO; | 95 | return -EPROTO; |
@@ -103,7 +107,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
103 | /* XXX For now we're using only 48 bits sequence numbers */ | 107 | /* XXX For now we're using only 48 bits sequence numbers */ |
104 | dh->dccph_x = 1; | 108 | dh->dccph_x = 1; |
105 | 109 | ||
106 | dp->dccps_awh = dp->dccps_gss; | 110 | dccp_update_gss(sk, dcb->dccpd_seq); |
107 | dccp_hdr_set_seq(dh, dp->dccps_gss); | 111 | dccp_hdr_set_seq(dh, dp->dccps_gss); |
108 | if (set_ack) | 112 | if (set_ack) |
109 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), ackno); | 113 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), ackno); |
@@ -112,6 +116,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
112 | case DCCP_PKT_REQUEST: | 116 | case DCCP_PKT_REQUEST: |
113 | dccp_hdr_request(skb)->dccph_req_service = | 117 | dccp_hdr_request(skb)->dccph_req_service = |
114 | dp->dccps_service; | 118 | dp->dccps_service; |
119 | /* | ||
120 | * Limit Ack window to ISS <= P.ackno <= GSS, so that | ||
121 | * only Responses to Requests we sent are considered. | ||
122 | */ | ||
123 | dp->dccps_awl = dp->dccps_iss; | ||
115 | break; | 124 | break; |
116 | case DCCP_PKT_RESET: | 125 | case DCCP_PKT_RESET: |
117 | dccp_hdr_reset(skb)->dccph_reset_code = | 126 | dccp_hdr_reset(skb)->dccph_reset_code = |
@@ -284,14 +293,26 @@ void dccp_write_xmit(struct sock *sk, int block) | |||
284 | } | 293 | } |
285 | } | 294 | } |
286 | 295 | ||
287 | int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | 296 | /** |
297 | * dccp_retransmit_skb - Retransmit Request, Close, or CloseReq packets | ||
298 | * There are only four retransmittable packet types in DCCP: | ||
299 | * - Request in client-REQUEST state (sec. 8.1.1), | ||
300 | * - CloseReq in server-CLOSEREQ state (sec. 8.3), | ||
301 | * - Close in node-CLOSING state (sec. 8.3), | ||
302 | * - Acks in client-PARTOPEN state (sec. 8.1.5, handled by dccp_delack_timer()). | ||
303 | * This function expects sk->sk_send_head to contain the original skb. | ||
304 | */ | ||
305 | int dccp_retransmit_skb(struct sock *sk) | ||
288 | { | 306 | { |
307 | WARN_ON(sk->sk_send_head == NULL); | ||
308 | |||
289 | if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk) != 0) | 309 | if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk) != 0) |
290 | return -EHOSTUNREACH; /* Routing failure or similar. */ | 310 | return -EHOSTUNREACH; /* Routing failure or similar. */ |
291 | 311 | ||
292 | return dccp_transmit_skb(sk, (skb_cloned(skb) ? | 312 | /* this count is used to distinguish original and retransmitted skb */ |
293 | pskb_copy(skb, GFP_ATOMIC): | 313 | inet_csk(sk)->icsk_retransmits++; |
294 | skb_clone(skb, GFP_ATOMIC))); | 314 | |
315 | return dccp_transmit_skb(sk, skb_clone(sk->sk_send_head, GFP_ATOMIC)); | ||
295 | } | 316 | } |
296 | 317 | ||
297 | struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | 318 | struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, |
@@ -437,19 +458,7 @@ static inline void dccp_connect_init(struct sock *sk) | |||
437 | 458 | ||
438 | dccp_sync_mss(sk, dst_mtu(dst)); | 459 | dccp_sync_mss(sk, dst_mtu(dst)); |
439 | 460 | ||
440 | /* | 461 | /* Initialise GAR as per 8.5; AWL/AWH are set in dccp_transmit_skb() */ |
441 | * SWL and AWL are initially adjusted so that they are not less than | ||
442 | * the initial Sequence Numbers received and sent, respectively: | ||
443 | * SWL := max(GSR + 1 - floor(W/4), ISR), | ||
444 | * AWL := max(GSS - W' + 1, ISS). | ||
445 | * These adjustments MUST be applied only at the beginning of the | ||
446 | * connection. | ||
447 | */ | ||
448 | dccp_update_gss(sk, dp->dccps_iss); | ||
449 | dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); | ||
450 | |||
451 | /* S.GAR - greatest valid acknowledgement number received on a non-Sync; | ||
452 | * initialized to S.ISS (sec. 8.5) */ | ||
453 | dp->dccps_gar = dp->dccps_iss; | 462 | dp->dccps_gar = dp->dccps_iss; |
454 | 463 | ||
455 | icsk->icsk_retransmits = 0; | 464 | icsk->icsk_retransmits = 0; |
diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 6a5b961b6f5c..54b3c7e9e016 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c | |||
@@ -99,21 +99,11 @@ static void dccp_retransmit_timer(struct sock *sk) | |||
99 | } | 99 | } |
100 | 100 | ||
101 | /* | 101 | /* |
102 | * sk->sk_send_head has to have one skb with | ||
103 | * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP | ||
104 | * packet types. The only packets eligible for retransmission are: | ||
105 | * -- Requests in client-REQUEST state (sec. 8.1.1) | ||
106 | * -- Acks in client-PARTOPEN state (sec. 8.1.5) | ||
107 | * -- CloseReq in server-CLOSEREQ state (sec. 8.3) | ||
108 | * -- Close in node-CLOSING state (sec. 8.3) */ | ||
109 | WARN_ON(sk->sk_send_head == NULL); | ||
110 | |||
111 | /* | ||
112 | * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was | 102 | * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was |
113 | * sent, no need to retransmit, this sock is dead. | 103 | * sent, no need to retransmit, this sock is dead. |
114 | */ | 104 | */ |
115 | if (dccp_write_timeout(sk)) | 105 | if (dccp_write_timeout(sk)) |
116 | goto out; | 106 | return; |
117 | 107 | ||
118 | /* | 108 | /* |
119 | * We want to know the number of packets retransmitted, not the | 109 | * We want to know the number of packets retransmitted, not the |
@@ -122,30 +112,28 @@ static void dccp_retransmit_timer(struct sock *sk) | |||
122 | if (icsk->icsk_retransmits == 0) | 112 | if (icsk->icsk_retransmits == 0) |
123 | DCCP_INC_STATS_BH(DCCP_MIB_TIMEOUTS); | 113 | DCCP_INC_STATS_BH(DCCP_MIB_TIMEOUTS); |
124 | 114 | ||
125 | if (dccp_retransmit_skb(sk, sk->sk_send_head) < 0) { | 115 | if (dccp_retransmit_skb(sk) != 0) { |
126 | /* | 116 | /* |
127 | * Retransmission failed because of local congestion, | 117 | * Retransmission failed because of local congestion, |
128 | * do not backoff. | 118 | * do not backoff. |
129 | */ | 119 | */ |
130 | if (icsk->icsk_retransmits == 0) | 120 | if (--icsk->icsk_retransmits == 0) |
131 | icsk->icsk_retransmits = 1; | 121 | icsk->icsk_retransmits = 1; |
132 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | 122 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, |
133 | min(icsk->icsk_rto, | 123 | min(icsk->icsk_rto, |
134 | TCP_RESOURCE_PROBE_INTERVAL), | 124 | TCP_RESOURCE_PROBE_INTERVAL), |
135 | DCCP_RTO_MAX); | 125 | DCCP_RTO_MAX); |
136 | goto out; | 126 | return; |
137 | } | 127 | } |
138 | 128 | ||
139 | backoff: | 129 | backoff: |
140 | icsk->icsk_backoff++; | 130 | icsk->icsk_backoff++; |
141 | icsk->icsk_retransmits++; | ||
142 | 131 | ||
143 | icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); | 132 | icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); |
144 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, | 133 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, |
145 | DCCP_RTO_MAX); | 134 | DCCP_RTO_MAX); |
146 | if (icsk->icsk_retransmits > sysctl_dccp_retries1) | 135 | if (icsk->icsk_retransmits > sysctl_dccp_retries1) |
147 | __sk_dst_reset(sk); | 136 | __sk_dst_reset(sk); |
148 | out:; | ||
149 | } | 137 | } |
150 | 138 | ||
151 | static void dccp_write_timer(unsigned long data) | 139 | static void dccp_write_timer(unsigned long data) |