[IPV6]: Generalise tcp_v6_search_req & tcp_v6_synq_add
More work is needed tho to introduce inet6_request_sock from tcp6_request_sock, in the same layout considerations as ipv6_pinfo in inet_sock, next changeset will do that. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
c2977c2213
commit
8129765ac0
31
include/net/inet6_connection_sock.h
Normal file
31
include/net/inet6_connection_sock.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* NET Generic infrastructure for INET6 connection oriented protocols.
|
||||||
|
*
|
||||||
|
* Authors: Many people, see the TCPv6 sources
|
||||||
|
*
|
||||||
|
* From code originally in TCPv6
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the License, or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
#ifndef _INET6_CONNECTION_SOCK_H
|
||||||
|
#define _INET6_CONNECTION_SOCK_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct sock;
|
||||||
|
struct request_sock;
|
||||||
|
|
||||||
|
extern struct request_sock *inet6_csk_search_req(const struct sock *sk,
|
||||||
|
struct request_sock ***prevp,
|
||||||
|
const __u16 rport,
|
||||||
|
const struct in6_addr *raddr,
|
||||||
|
const struct in6_addr *laddr,
|
||||||
|
const int iif);
|
||||||
|
|
||||||
|
extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
|
||||||
|
struct request_sock *req,
|
||||||
|
const unsigned long timeout);
|
||||||
|
#endif /* _INET6_CONNECTION_SOCK_H */
|
@@ -244,7 +244,7 @@ static inline int reqsk_queue_is_full(const struct request_sock_queue *queue)
|
|||||||
|
|
||||||
static inline void reqsk_queue_hash_req(struct request_sock_queue *queue,
|
static inline void reqsk_queue_hash_req(struct request_sock_queue *queue,
|
||||||
u32 hash, struct request_sock *req,
|
u32 hash, struct request_sock *req,
|
||||||
unsigned timeout)
|
unsigned long timeout)
|
||||||
{
|
{
|
||||||
struct listen_sock *lopt = queue->listen_opt;
|
struct listen_sock *lopt = queue->listen_opt;
|
||||||
|
|
||||||
|
@@ -8,7 +8,8 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
|
|||||||
route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
|
route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
|
||||||
protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
|
protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
|
||||||
exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
|
exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
|
||||||
ip6_flowlabel.o ipv6_syms.o netfilter.o
|
ip6_flowlabel.o ipv6_syms.o netfilter.o \
|
||||||
|
inet6_connection_sock.o
|
||||||
|
|
||||||
ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
|
ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
|
||||||
xfrm6_output.o
|
xfrm6_output.o
|
||||||
|
96
net/ipv6/inet6_connection_sock.c
Normal file
96
net/ipv6/inet6_connection_sock.c
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* INET An implementation of the TCP/IP protocol suite for the LINUX
|
||||||
|
* operating system. INET is implemented using the BSD Socket
|
||||||
|
* interface as the means of communication with the user level.
|
||||||
|
*
|
||||||
|
* Support for INET6 connection oriented protocols.
|
||||||
|
*
|
||||||
|
* Authors: See the TCPv6 sources
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the License, or(at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/config.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/in6.h>
|
||||||
|
#include <linux/ipv6.h>
|
||||||
|
#include <linux/jhash.h>
|
||||||
|
|
||||||
|
#include <net/addrconf.h>
|
||||||
|
#include <net/inet_connection_sock.h>
|
||||||
|
#include <net/sock.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* request_sock (formerly open request) hash tables.
|
||||||
|
*/
|
||||||
|
static u32 inet6_synq_hash(const struct in6_addr *raddr, const u16 rport,
|
||||||
|
const u32 rnd, const u16 synq_hsize)
|
||||||
|
{
|
||||||
|
u32 a = raddr->s6_addr32[0];
|
||||||
|
u32 b = raddr->s6_addr32[1];
|
||||||
|
u32 c = raddr->s6_addr32[2];
|
||||||
|
|
||||||
|
a += JHASH_GOLDEN_RATIO;
|
||||||
|
b += JHASH_GOLDEN_RATIO;
|
||||||
|
c += rnd;
|
||||||
|
__jhash_mix(a, b, c);
|
||||||
|
|
||||||
|
a += raddr->s6_addr32[3];
|
||||||
|
b += (u32)rport;
|
||||||
|
__jhash_mix(a, b, c);
|
||||||
|
|
||||||
|
return c & (synq_hsize - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct request_sock *inet6_csk_search_req(const struct sock *sk,
|
||||||
|
struct request_sock ***prevp,
|
||||||
|
const __u16 rport,
|
||||||
|
const struct in6_addr *raddr,
|
||||||
|
const struct in6_addr *laddr,
|
||||||
|
const int iif)
|
||||||
|
{
|
||||||
|
const struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
|
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
|
||||||
|
struct request_sock *req, **prev;
|
||||||
|
|
||||||
|
for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport,
|
||||||
|
lopt->hash_rnd,
|
||||||
|
lopt->nr_table_entries)];
|
||||||
|
(req = *prev) != NULL;
|
||||||
|
prev = &req->dl_next) {
|
||||||
|
const struct tcp6_request_sock *treq = tcp6_rsk(req);
|
||||||
|
|
||||||
|
if (inet_rsk(req)->rmt_port == rport &&
|
||||||
|
req->rsk_ops->family == AF_INET6 &&
|
||||||
|
ipv6_addr_equal(&treq->rmt_addr, raddr) &&
|
||||||
|
ipv6_addr_equal(&treq->loc_addr, laddr) &&
|
||||||
|
(!treq->iif || treq->iif == iif)) {
|
||||||
|
BUG_TRAP(req->sk == NULL);
|
||||||
|
*prevp = prev;
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL_GPL(inet6_csk_search_req);
|
||||||
|
|
||||||
|
void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
|
||||||
|
struct request_sock *req,
|
||||||
|
const unsigned long timeout)
|
||||||
|
{
|
||||||
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
|
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
|
||||||
|
const u32 h = inet6_synq_hash(&tcp6_rsk(req)->rmt_addr,
|
||||||
|
inet_rsk(req)->rmt_port,
|
||||||
|
lopt->hash_rnd, lopt->nr_table_entries);
|
||||||
|
|
||||||
|
reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
|
||||||
|
inet_csk_reqsk_queue_added(sk, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
|
@@ -48,6 +48,7 @@
|
|||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
#include <net/ndisc.h>
|
#include <net/ndisc.h>
|
||||||
#include <net/inet6_hashtables.h>
|
#include <net/inet6_hashtables.h>
|
||||||
|
#include <net/inet6_connection_sock.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/transp_v6.h>
|
#include <net/transp_v6.h>
|
||||||
#include <net/addrconf.h>
|
#include <net/addrconf.h>
|
||||||
@@ -118,60 +119,6 @@ static void tcp_v6_hash(struct sock *sk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Open request hash tables.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static u32 tcp_v6_synq_hash(const struct in6_addr *raddr, const u16 rport, const u32 rnd)
|
|
||||||
{
|
|
||||||
u32 a, b, c;
|
|
||||||
|
|
||||||
a = raddr->s6_addr32[0];
|
|
||||||
b = raddr->s6_addr32[1];
|
|
||||||
c = raddr->s6_addr32[2];
|
|
||||||
|
|
||||||
a += JHASH_GOLDEN_RATIO;
|
|
||||||
b += JHASH_GOLDEN_RATIO;
|
|
||||||
c += rnd;
|
|
||||||
__jhash_mix(a, b, c);
|
|
||||||
|
|
||||||
a += raddr->s6_addr32[3];
|
|
||||||
b += (u32) rport;
|
|
||||||
__jhash_mix(a, b, c);
|
|
||||||
|
|
||||||
return c & (TCP_SYNQ_HSIZE - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct request_sock *tcp_v6_search_req(const struct sock *sk,
|
|
||||||
struct request_sock ***prevp,
|
|
||||||
__u16 rport,
|
|
||||||
struct in6_addr *raddr,
|
|
||||||
struct in6_addr *laddr,
|
|
||||||
int iif)
|
|
||||||
{
|
|
||||||
const struct inet_connection_sock *icsk = inet_csk(sk);
|
|
||||||
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
|
|
||||||
struct request_sock *req, **prev;
|
|
||||||
|
|
||||||
for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport, lopt->hash_rnd)];
|
|
||||||
(req = *prev) != NULL;
|
|
||||||
prev = &req->dl_next) {
|
|
||||||
const struct tcp6_request_sock *treq = tcp6_rsk(req);
|
|
||||||
|
|
||||||
if (inet_rsk(req)->rmt_port == rport &&
|
|
||||||
req->rsk_ops->family == AF_INET6 &&
|
|
||||||
ipv6_addr_equal(&treq->rmt_addr, raddr) &&
|
|
||||||
ipv6_addr_equal(&treq->loc_addr, laddr) &&
|
|
||||||
(!treq->iif || treq->iif == iif)) {
|
|
||||||
BUG_TRAP(req->sk == NULL);
|
|
||||||
*prevp = prev;
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
|
static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
|
||||||
struct in6_addr *saddr,
|
struct in6_addr *saddr,
|
||||||
struct in6_addr *daddr,
|
struct in6_addr *daddr,
|
||||||
@@ -662,8 +609,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
|||||||
if (sock_owned_by_user(sk))
|
if (sock_owned_by_user(sk))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
req = tcp_v6_search_req(sk, &prev, th->dest, &hdr->daddr,
|
req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
|
||||||
&hdr->saddr, inet6_iif(skb));
|
&hdr->saddr, inet6_iif(skb));
|
||||||
if (!req)
|
if (!req)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -978,8 +925,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
|
|||||||
struct sock *nsk;
|
struct sock *nsk;
|
||||||
|
|
||||||
/* Find possible connection requests. */
|
/* Find possible connection requests. */
|
||||||
req = tcp_v6_search_req(sk, &prev, th->source, &skb->nh.ipv6h->saddr,
|
req = inet6_csk_search_req(sk, &prev, th->source,
|
||||||
&skb->nh.ipv6h->daddr, inet6_iif(skb));
|
&skb->nh.ipv6h->saddr,
|
||||||
|
&skb->nh.ipv6h->daddr, inet6_iif(skb));
|
||||||
if (req)
|
if (req)
|
||||||
return tcp_check_req(sk, skb, req, prev);
|
return tcp_check_req(sk, skb, req, prev);
|
||||||
|
|
||||||
@@ -1003,17 +951,6 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
|
|||||||
return sk;
|
return sk;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcp_v6_synq_add(struct sock *sk, struct request_sock *req)
|
|
||||||
{
|
|
||||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
||||||
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
|
|
||||||
const u32 h = tcp_v6_synq_hash(&tcp6_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port, lopt->hash_rnd);
|
|
||||||
|
|
||||||
reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, TCP_TIMEOUT_INIT);
|
|
||||||
inet_csk_reqsk_queue_added(sk, TCP_TIMEOUT_INIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* FIXME: this is substantially similar to the ipv4 code.
|
/* FIXME: this is substantially similar to the ipv4 code.
|
||||||
* Can some kind of merge be done? -- erics
|
* Can some kind of merge be done? -- erics
|
||||||
*/
|
*/
|
||||||
@@ -1083,8 +1020,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
|
|||||||
if (tcp_v6_send_synack(sk, req, NULL))
|
if (tcp_v6_send_synack(sk, req, NULL))
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
tcp_v6_synq_add(sk, req);
|
inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
|
Reference in New Issue
Block a user