|
@@ -942,7 +942,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
|
|
|
|
+static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
|
|
|
|
+ u32 ts, struct tcp_md5sig_key *key, int rst)
|
|
{
|
|
{
|
|
struct tcphdr *th = tcp_hdr(skb), *t1;
|
|
struct tcphdr *th = tcp_hdr(skb), *t1;
|
|
struct sk_buff *buff;
|
|
struct sk_buff *buff;
|
|
@@ -951,31 +952,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
struct sock *ctl_sk = net->ipv6.tcp_sk;
|
|
struct sock *ctl_sk = net->ipv6.tcp_sk;
|
|
unsigned int tot_len = sizeof(struct tcphdr);
|
|
unsigned int tot_len = sizeof(struct tcphdr);
|
|
__be32 *topt;
|
|
__be32 *topt;
|
|
-#ifdef CONFIG_TCP_MD5SIG
|
|
|
|
- struct tcp_md5sig_key *key;
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
- if (th->rst)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (!ipv6_unicast_destination(skb))
|
|
|
|
- return;
|
|
|
|
|
|
|
|
|
|
+ if (ts)
|
|
|
|
+ tot_len += TCPOLEN_TSTAMP_ALIGNED;
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
- if (sk)
|
|
|
|
- key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
|
|
|
|
- else
|
|
|
|
- key = NULL;
|
|
|
|
-
|
|
|
|
if (key)
|
|
if (key)
|
|
tot_len += TCPOLEN_MD5SIG_ALIGNED;
|
|
tot_len += TCPOLEN_MD5SIG_ALIGNED;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- /*
|
|
|
|
- * We need to grab some memory, and put together an RST,
|
|
|
|
- * and then put it into the queue to be sent.
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
|
|
buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
|
|
GFP_ATOMIC);
|
|
GFP_ATOMIC);
|
|
if (buff == NULL)
|
|
if (buff == NULL)
|
|
@@ -990,18 +974,21 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
t1->dest = th->source;
|
|
t1->dest = th->source;
|
|
t1->source = th->dest;
|
|
t1->source = th->dest;
|
|
t1->doff = tot_len / 4;
|
|
t1->doff = tot_len / 4;
|
|
- t1->rst = 1;
|
|
|
|
-
|
|
|
|
- if(th->ack) {
|
|
|
|
- t1->seq = th->ack_seq;
|
|
|
|
- } else {
|
|
|
|
- t1->ack = 1;
|
|
|
|
- t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
|
|
|
|
- + skb->len - (th->doff<<2));
|
|
|
|
- }
|
|
|
|
|
|
+ t1->seq = htonl(seq);
|
|
|
|
+ t1->ack_seq = htonl(ack);
|
|
|
|
+ t1->ack = !rst || !th->ack;
|
|
|
|
+ t1->rst = rst;
|
|
|
|
+ t1->window = htons(win);
|
|
|
|
|
|
topt = (__be32 *)(t1 + 1);
|
|
topt = (__be32 *)(t1 + 1);
|
|
|
|
|
|
|
|
+ if (ts) {
|
|
|
|
+ *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
|
|
|
|
+ (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
|
|
|
|
+ *topt++ = htonl(tcp_time_stamp);
|
|
|
|
+ *topt++ = htonl(ts);
|
|
|
|
+ }
|
|
|
|
+
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
if (key) {
|
|
if (key) {
|
|
*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
|
|
*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
|
|
@@ -1036,7 +1023,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
|
|
if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
|
|
ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
|
|
ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
|
|
TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
|
|
TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
|
|
- TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
|
|
|
|
|
|
+ if (rst)
|
|
|
|
+ TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1044,87 +1032,40 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
kfree_skb(buff);
|
|
kfree_skb(buff);
|
|
}
|
|
}
|
|
|
|
|
|
-static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
|
|
|
|
- struct tcp_md5sig_key *key)
|
|
|
|
|
|
+static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
{
|
|
{
|
|
- struct tcphdr *th = tcp_hdr(skb), *t1;
|
|
|
|
- struct sk_buff *buff;
|
|
|
|
- struct flowi fl;
|
|
|
|
- struct net *net = dev_net(skb->dst->dev);
|
|
|
|
- struct sock *ctl_sk = net->ipv6.tcp_sk;
|
|
|
|
- unsigned int tot_len = sizeof(struct tcphdr);
|
|
|
|
- __be32 *topt;
|
|
|
|
-
|
|
|
|
- if (ts)
|
|
|
|
- tot_len += TCPOLEN_TSTAMP_ALIGNED;
|
|
|
|
|
|
+ struct tcphdr *th = tcp_hdr(skb);
|
|
|
|
+ u32 seq = 0, ack_seq = 0;
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
- if (key)
|
|
|
|
- tot_len += TCPOLEN_MD5SIG_ALIGNED;
|
|
|
|
|
|
+ struct tcp_md5sig_key *key;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
|
|
|
|
- GFP_ATOMIC);
|
|
|
|
- if (buff == NULL)
|
|
|
|
|
|
+ if (th->rst)
|
|
return;
|
|
return;
|
|
|
|
|
|
- skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
|
|
|
|
-
|
|
|
|
- t1 = (struct tcphdr *) skb_push(buff, tot_len);
|
|
|
|
-
|
|
|
|
- /* Swap the send and the receive. */
|
|
|
|
- memset(t1, 0, sizeof(*t1));
|
|
|
|
- t1->dest = th->source;
|
|
|
|
- t1->source = th->dest;
|
|
|
|
- t1->doff = tot_len / 4;
|
|
|
|
- t1->seq = htonl(seq);
|
|
|
|
- t1->ack_seq = htonl(ack);
|
|
|
|
- t1->ack = 1;
|
|
|
|
- t1->window = htons(win);
|
|
|
|
-
|
|
|
|
- topt = (__be32 *)(t1 + 1);
|
|
|
|
-
|
|
|
|
- if (ts) {
|
|
|
|
- *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
|
|
|
|
- (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
|
|
|
|
- *topt++ = htonl(tcp_time_stamp);
|
|
|
|
- *topt++ = htonl(ts);
|
|
|
|
- }
|
|
|
|
|
|
+ if (!ipv6_unicast_destination(skb))
|
|
|
|
+ return;
|
|
|
|
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
- if (key) {
|
|
|
|
- *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
|
|
|
|
- (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
|
|
|
|
- tcp_v6_md5_hash_hdr((__u8 *)topt, key,
|
|
|
|
- &ipv6_hdr(skb)->saddr,
|
|
|
|
- &ipv6_hdr(skb)->daddr, t1);
|
|
|
|
- }
|
|
|
|
|
|
+ if (sk)
|
|
|
|
+ key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
|
|
|
|
+ else
|
|
|
|
+ key = NULL;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- buff->csum = csum_partial((char *)t1, tot_len, 0);
|
|
|
|
-
|
|
|
|
- memset(&fl, 0, sizeof(fl));
|
|
|
|
- ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
|
|
|
|
- ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
|
|
|
|
-
|
|
|
|
- t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
|
|
|
|
- tot_len, IPPROTO_TCP,
|
|
|
|
- buff->csum);
|
|
|
|
-
|
|
|
|
- fl.proto = IPPROTO_TCP;
|
|
|
|
- fl.oif = inet6_iif(skb);
|
|
|
|
- fl.fl_ip_dport = t1->dest;
|
|
|
|
- fl.fl_ip_sport = t1->source;
|
|
|
|
- security_skb_classify_flow(skb, &fl);
|
|
|
|
|
|
+ if (th->ack)
|
|
|
|
+ seq = ntohl(th->ack_seq);
|
|
|
|
+ else
|
|
|
|
+ ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
|
|
|
|
+ (th->doff << 2);
|
|
|
|
|
|
- if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
|
|
|
|
- if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
|
|
|
|
- ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
|
|
|
|
- TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1);
|
|
|
|
+}
|
|
|
|
|
|
- kfree_skb(buff);
|
|
|
|
|
|
+static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
|
|
|
|
+ struct tcp_md5sig_key *key)
|
|
|
|
+{
|
|
|
|
+ tcp_v6_send_response(skb, seq, ack, win, ts, key, 0);
|
|
}
|
|
}
|
|
|
|
|
|
static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
|
|
static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
|