static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw) { struct inet6_timewait_sock *tw6; struct tcp_metrics_block *tm; struct inetpeer_addr addr; unsigned int hash; struct net *net; addr.family = tw->tw_family; switch (addr.family) { case AF_INET: addr.addr.a4 = tw->tw_daddr; hash = (__force unsigned int) addr.addr.a4; break; case AF_INET6: tw6 = inet6_twsk((struct sock *)tw); *(struct in6_addr *)addr.addr.a6 = tw6->tw_v6_daddr; hash = ipv6_addr_hash(&tw6->tw_v6_daddr); break; default: return NULL; } net = twsk_net(tw); hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; tm = rcu_dereference(tm->tcpm_next)) { if (addr_same(&tm->tcpm_addr, &addr)) break; } return tm; }
static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw) { struct tcp_metrics_block *tm; struct inetpeer_addr saddr, daddr; unsigned int hash; struct net *net; if (tw->tw_family == AF_INET) { saddr.family = AF_INET; saddr.addr.a4 = tw->tw_rcv_saddr; daddr.family = AF_INET; daddr.addr.a4 = tw->tw_daddr; hash = (__force unsigned int) daddr.addr.a4; } #if IS_ENABLED(CONFIG_IPV6) else if (tw->tw_family == AF_INET6) { if (ipv6_addr_v4mapped(&tw->tw_v6_daddr)) { saddr.family = AF_INET; saddr.addr.a4 = tw->tw_rcv_saddr; daddr.family = AF_INET; daddr.addr.a4 = tw->tw_daddr; hash = (__force unsigned int) daddr.addr.a4; } else { saddr.family = AF_INET6; *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr; daddr.family = AF_INET6; *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr; hash = ipv6_addr_hash(&tw->tw_v6_daddr); } } #endif else return NULL; net = twsk_net(tw); hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; tm = rcu_dereference(tm->tcpm_next)) { if (addr_same(&tm->tcpm_saddr, &saddr) && addr_same(&tm->tcpm_daddr, &daddr)) break; } return tm; }