Commit 2ab61b01 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://eden-feed.erg.abdn.ac.uk/net-2.6

parents 6f9f489a 860239c5
...@@ -226,7 +226,7 @@ static inline void dccp_csum_outgoing(struct sk_buff *skb) ...@@ -226,7 +226,7 @@ static inline void dccp_csum_outgoing(struct sk_buff *skb)
extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb);
extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); extern int dccp_retransmit_skb(struct sock *sk);
extern void dccp_send_ack(struct sock *sk); extern void dccp_send_ack(struct sock *sk);
extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk); extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk);
......
...@@ -196,8 +196,8 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, ...@@ -196,8 +196,8 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
static void dccp_v4_err(struct sk_buff *skb, u32 info) static void dccp_v4_err(struct sk_buff *skb, u32 info)
{ {
const struct iphdr *iph = (struct iphdr *)skb->data; const struct iphdr *iph = (struct iphdr *)skb->data;
const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + const u8 offset = iph->ihl << 2;
(iph->ihl << 2)); const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
struct dccp_sock *dp; struct dccp_sock *dp;
struct inet_sock *inet; struct inet_sock *inet;
const int type = icmp_hdr(skb)->type; const int type = icmp_hdr(skb)->type;
...@@ -207,7 +207,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) ...@@ -207,7 +207,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
int err; int err;
struct net *net = dev_net(skb->dev); struct net *net = dev_net(skb->dev);
if (skb->len < (iph->ihl << 2) + 8) { if (skb->len < offset + sizeof(*dh) ||
skb->len < offset + __dccp_basic_hdr_len(dh)) {
ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
return; return;
} }
...@@ -238,7 +239,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) ...@@ -238,7 +239,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
dp = dccp_sk(sk); dp = dccp_sk(sk);
seq = dccp_hdr_seq(dh); seq = dccp_hdr_seq(dh);
if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
!between48(seq, dp->dccps_swl, dp->dccps_swh)) { !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
goto out; goto out;
} }
......
...@@ -89,12 +89,19 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -89,12 +89,19 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
{ {
struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
struct dccp_sock *dp;
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
struct sock *sk; struct sock *sk;
int err; int err;
__u64 seq; __u64 seq;
struct net *net = dev_net(skb->dev); struct net *net = dev_net(skb->dev);
if (skb->len < offset + sizeof(*dh) ||
skb->len < offset + __dccp_basic_hdr_len(dh)) {
ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
return;
}
sk = inet6_lookup(net, &dccp_hashinfo, sk = inet6_lookup(net, &dccp_hashinfo,
&hdr->daddr, dh->dccph_dport, &hdr->daddr, dh->dccph_dport,
&hdr->saddr, dh->dccph_sport, inet6_iif(skb)); &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,6 +123,14 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (sk->sk_state == DCCP_CLOSED) if (sk->sk_state == DCCP_CLOSED)
goto out; goto out;
dp = dccp_sk(sk);
seq = dccp_hdr_seq(dh);
if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
!between48(seq, dp->dccps_awl, dp->dccps_awh)) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
goto out;
}
np = inet6_sk(sk); np = inet6_sk(sk);
if (type == ICMPV6_PKT_TOOBIG) { if (type == ICMPV6_PKT_TOOBIG) {
...@@ -168,7 +183,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -168,7 +183,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
icmpv6_err_convert(type, code, &err); icmpv6_err_convert(type, code, &err);
seq = dccp_hdr_seq(dh);
/* Might be for an request_sock */ /* Might be for an request_sock */
switch (sk->sk_state) { switch (sk->sk_state) {
struct request_sock *req, **prev; struct request_sock *req, **prev;
......
...@@ -53,8 +53,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -53,8 +53,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
dccp_packet_hdr_len(dcb->dccpd_type); dccp_packet_hdr_len(dcb->dccpd_type);
int err, set_ack = 1; int err, set_ack = 1;
u64 ackno = dp->dccps_gsr; u64 ackno = dp->dccps_gsr;
/*
dccp_inc_seqno(&dp->dccps_gss); * Increment GSS here already in case the option code needs it.
* Update GSS for real only if option processing below succeeds.
*/
dcb->dccpd_seq = ADD48(dp->dccps_gss, 1);
switch (dcb->dccpd_type) { switch (dcb->dccpd_type) {
case DCCP_PKT_DATA: case DCCP_PKT_DATA:
...@@ -66,6 +69,9 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -66,6 +69,9 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
case DCCP_PKT_REQUEST: case DCCP_PKT_REQUEST:
set_ack = 0; set_ack = 0;
/* Use ISS on the first (non-retransmitted) Request. */
if (icsk->icsk_retransmits == 0)
dcb->dccpd_seq = dp->dccps_iss;
/* fall through */ /* fall through */
case DCCP_PKT_SYNC: case DCCP_PKT_SYNC:
...@@ -84,8 +90,6 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -84,8 +90,6 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
break; break;
} }
dcb->dccpd_seq = dp->dccps_gss;
if (dccp_insert_options(sk, skb)) { if (dccp_insert_options(sk, skb)) {
kfree_skb(skb); kfree_skb(skb);
return -EPROTO; return -EPROTO;
...@@ -103,7 +107,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -103,7 +107,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
/* XXX For now we're using only 48 bits sequence numbers */ /* XXX For now we're using only 48 bits sequence numbers */
dh->dccph_x = 1; dh->dccph_x = 1;
dp->dccps_awh = dp->dccps_gss; dccp_update_gss(sk, dcb->dccpd_seq);
dccp_hdr_set_seq(dh, dp->dccps_gss); dccp_hdr_set_seq(dh, dp->dccps_gss);
if (set_ack) if (set_ack)
dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), ackno); 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,6 +116,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
case DCCP_PKT_REQUEST: case DCCP_PKT_REQUEST:
dccp_hdr_request(skb)->dccph_req_service = dccp_hdr_request(skb)->dccph_req_service =
dp->dccps_service; dp->dccps_service;
/*
* Limit Ack window to ISS <= P.ackno <= GSS, so that
* only Responses to Requests we sent are considered.
*/
dp->dccps_awl = dp->dccps_iss;
break; break;
case DCCP_PKT_RESET: case DCCP_PKT_RESET:
dccp_hdr_reset(skb)->dccph_reset_code = dccp_hdr_reset(skb)->dccph_reset_code =
...@@ -284,14 +293,26 @@ void dccp_write_xmit(struct sock *sk, int block) ...@@ -284,14 +293,26 @@ void dccp_write_xmit(struct sock *sk, int block)
} }
} }
int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb) /**
* dccp_retransmit_skb - Retransmit Request, Close, or CloseReq packets
* There are only four retransmittable packet types in DCCP:
* - Request in client-REQUEST state (sec. 8.1.1),
* - CloseReq in server-CLOSEREQ state (sec. 8.3),
* - Close in node-CLOSING state (sec. 8.3),
* - Acks in client-PARTOPEN state (sec. 8.1.5, handled by dccp_delack_timer()).
* This function expects sk->sk_send_head to contain the original skb.
*/
int dccp_retransmit_skb(struct sock *sk)
{ {
WARN_ON(sk->sk_send_head == NULL);
if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk) != 0) if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk) != 0)
return -EHOSTUNREACH; /* Routing failure or similar. */ return -EHOSTUNREACH; /* Routing failure or similar. */
return dccp_transmit_skb(sk, (skb_cloned(skb) ? /* this count is used to distinguish original and retransmitted skb */
pskb_copy(skb, GFP_ATOMIC): inet_csk(sk)->icsk_retransmits++;
skb_clone(skb, GFP_ATOMIC)));
return dccp_transmit_skb(sk, skb_clone(sk->sk_send_head, GFP_ATOMIC));
} }
struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, 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,19 +458,7 @@ static inline void dccp_connect_init(struct sock *sk)
dccp_sync_mss(sk, dst_mtu(dst)); dccp_sync_mss(sk, dst_mtu(dst));
/* /* Initialise GAR as per 8.5; AWL/AWH are set in dccp_transmit_skb() */
* SWL and AWL are initially adjusted so that they are not less than
* the initial Sequence Numbers received and sent, respectively:
* SWL := max(GSR + 1 - floor(W/4), ISR),
* AWL := max(GSS - W' + 1, ISS).
* These adjustments MUST be applied only at the beginning of the
* connection.
*/
dccp_update_gss(sk, dp->dccps_iss);
dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
/* S.GAR - greatest valid acknowledgement number received on a non-Sync;
* initialized to S.ISS (sec. 8.5) */
dp->dccps_gar = dp->dccps_iss; dp->dccps_gar = dp->dccps_iss;
icsk->icsk_retransmits = 0; icsk->icsk_retransmits = 0;
......
...@@ -98,22 +98,12 @@ static void dccp_retransmit_timer(struct sock *sk) ...@@ -98,22 +98,12 @@ static void dccp_retransmit_timer(struct sock *sk)
goto backoff; goto backoff;
} }
/*
* sk->sk_send_head has to have one skb with
* DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP
* packet types. The only packets eligible for retransmission are:
* -- Requests in client-REQUEST state (sec. 8.1.1)
* -- Acks in client-PARTOPEN state (sec. 8.1.5)
* -- CloseReq in server-CLOSEREQ state (sec. 8.3)
* -- Close in node-CLOSING state (sec. 8.3) */
WARN_ON(sk->sk_send_head == NULL);
/* /*
* More than than 4MSL (8 minutes) has passed, a RESET(aborted) was * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
* sent, no need to retransmit, this sock is dead. * sent, no need to retransmit, this sock is dead.
*/ */
if (dccp_write_timeout(sk)) if (dccp_write_timeout(sk))
goto out; return;
/* /*
* We want to know the number of packets retransmitted, not the * We want to know the number of packets retransmitted, not the
...@@ -122,30 +112,28 @@ static void dccp_retransmit_timer(struct sock *sk) ...@@ -122,30 +112,28 @@ static void dccp_retransmit_timer(struct sock *sk)
if (icsk->icsk_retransmits == 0) if (icsk->icsk_retransmits == 0)
DCCP_INC_STATS_BH(DCCP_MIB_TIMEOUTS); DCCP_INC_STATS_BH(DCCP_MIB_TIMEOUTS);
if (dccp_retransmit_skb(sk, sk->sk_send_head) < 0) { if (dccp_retransmit_skb(sk) != 0) {
/* /*
* Retransmission failed because of local congestion, * Retransmission failed because of local congestion,
* do not backoff. * do not backoff.
*/ */
if (icsk->icsk_retransmits == 0) if (--icsk->icsk_retransmits == 0)
icsk->icsk_retransmits = 1; icsk->icsk_retransmits = 1;
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
min(icsk->icsk_rto, min(icsk->icsk_rto,
TCP_RESOURCE_PROBE_INTERVAL), TCP_RESOURCE_PROBE_INTERVAL),
DCCP_RTO_MAX); DCCP_RTO_MAX);
goto out; return;
} }
backoff: backoff:
icsk->icsk_backoff++; icsk->icsk_backoff++;
icsk->icsk_retransmits++;
icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto,
DCCP_RTO_MAX); DCCP_RTO_MAX);
if (icsk->icsk_retransmits > sysctl_dccp_retries1) if (icsk->icsk_retransmits > sysctl_dccp_retries1)
__sk_dst_reset(sk); __sk_dst_reset(sk);
out:;
} }
static void dccp_write_timer(unsigned long data) static void dccp_write_timer(unsigned long data)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment