@@ -771,6 +771,30 @@ static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow,
#define IP6_DEFAULT_AUTO_FLOW_LABELS IP6_AUTO_FLOW_LABEL_OPTOUT
+static inline bool ip6_need_make_flowlabel(struct net *net, __be32 flowlabel,
+ bool autolabel)
+{
+ if (flowlabel ||
+ net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
+ (!autolabel &&
+ net->ipv6.sysctl.auto_flowlabels != IP6_AUTO_FLOW_LABEL_FORCED))
+ return false;
+
+ return true;
+}
+
+static inline __be32 __ip6_make_flowlabel(struct net *net, u32 hash)
+{
+ __be32 flowlabel;
+
+ flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
+
+ if (net->ipv6.sysctl.flowlabel_state_ranges)
+ flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG;
+
+ return flowlabel;
+}
+
static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
__be32 flowlabel, bool autolabel,
struct flowi6 *fl6)
@@ -782,20 +806,20 @@ static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
*/
flowlabel &= IPV6_FLOWLABEL_MASK;
- if (flowlabel ||
- net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
- (!autolabel &&
- net->ipv6.sysctl.auto_flowlabels != IP6_AUTO_FLOW_LABEL_FORCED))
+ if (!ip6_need_make_flowlabel(net, flowlabel, autolabel))
return flowlabel;
hash = skb_get_hash_flowi6(skb, fl6);
- flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
-
- if (net->ipv6.sysctl.flowlabel_state_ranges)
- flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG;
+ return __ip6_make_flowlabel(net, hash);
+}
- return flowlabel;
+static inline __be32 ip6_make_flowlabel_from_hash(struct net *net,
+ bool autolabel, u32 hash)
+{
+ if (!ip6_need_make_flowlabel(net, 0, autolabel))
+ return 0;
+ return __ip6_make_flowlabel(net, hash);
}
static inline int ip6_default_np_autolabel(struct net *net)
@@ -276,11 +276,17 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
#if IS_ENABLED(CONFIG_IPV6)
if (tw->tw_family == PF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
+ __be32 flowlabel;
tw->tw_v6_daddr = sk->sk_v6_daddr;
tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
tw->tw_tclass = np->tclass;
- tw->tw_flowlabel = be32_to_cpu(np->flow_label & IPV6_FLOWLABEL_MASK);
+ flowlabel = np->flow_label & IPV6_FLOWLABEL_MASK;
+ if (flowlabel == 0)
+ flowlabel = ip6_make_flowlabel_from_hash(
+ sock_net(sk), np->autoflowlabel,
+ sk->sk_txhash);
+ tw->tw_flowlabel = be32_to_cpu(flowlabel);
tw->tw_ipv6only = sk->sk_ipv6only;
}
#endif
@@ -891,6 +891,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
struct sock *sk1 = NULL;
#endif
int oif;
+ u8 tclass = 0;
+ __be32 flowlabel = 0;
if (th->rst)
return;
@@ -939,7 +941,21 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
(th->doff << 2);
oif = sk ? sk->sk_bound_dev_if : 0;
- tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0);
+ if (sk) {
+ if (sk_fullsock(sk)) {
+ struct ipv6_pinfo *np = inet6_sk(sk);
+
+ tclass = np->tclass;
+ flowlabel = np->flow_label & IPV6_FLOWLABEL_MASK;
+ } else {
+ struct inet_timewait_sock *tw = inet_twsk(sk);
+
+ tclass = tw->tw_tclass;
+ flowlabel = cpu_to_be32(tw->tw_flowlabel);
+ }
+ }
+ tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1,
+ tclass, flowlabel);
#ifdef CONFIG_TCP_MD5SIG
out: