inet6_connection_sock.c revision ca304b6104ffdd120bb6687a88a0625e58bc71cd
18129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo/*
28129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo * INET        An implementation of the TCP/IP protocol suite for the LINUX
38129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *             operating system.  INET is implemented using the  BSD Socket
48129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *             interface as the means of communication with the user level.
58129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *
68129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *             Support for INET6 connection oriented protocols.
78129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *
88129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo * Authors:    See the TCPv6 sources
98129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *
108129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *             This program is free software; you can redistribute it and/or
118129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *             modify it under the terms of the GNU General Public License
128129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *             as published by the Free Software Foundation; either version
138129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo *             2 of the License, or(at your option) any later version.
148129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo */
158129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
168129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <linux/config.h>
178129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <linux/module.h>
188129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <linux/in6.h>
198129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <linux/ipv6.h>
208129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <linux/jhash.h>
218129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
228129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <net/addrconf.h>
238129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <net/inet_connection_sock.h>
248129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo#include <net/sock.h>
258129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
268129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo/*
278129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo * request_sock (formerly open request) hash tables.
288129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo */
298129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melostatic u32 inet6_synq_hash(const struct in6_addr *raddr, const u16 rport,
308129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo			   const u32 rnd, const u16 synq_hsize)
318129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo{
328129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	u32 a = raddr->s6_addr32[0];
338129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	u32 b = raddr->s6_addr32[1];
348129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	u32 c = raddr->s6_addr32[2];
358129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
368129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	a += JHASH_GOLDEN_RATIO;
378129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	b += JHASH_GOLDEN_RATIO;
388129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	c += rnd;
398129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	__jhash_mix(a, b, c);
408129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
418129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	a += raddr->s6_addr32[3];
428129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	b += (u32)rport;
438129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	__jhash_mix(a, b, c);
448129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
458129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	return c & (synq_hsize - 1);
468129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo}
478129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
488129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melostruct request_sock *inet6_csk_search_req(const struct sock *sk,
498129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo					  struct request_sock ***prevp,
508129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo					  const __u16 rport,
518129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo					  const struct in6_addr *raddr,
528129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo					  const struct in6_addr *laddr,
538129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo					  const int iif)
548129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo{
558129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	const struct inet_connection_sock *icsk = inet_csk(sk);
568129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
578129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	struct request_sock *req, **prev;
588129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
598129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport,
608129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo						     lopt->hash_rnd,
618129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo						     lopt->nr_table_entries)];
628129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	     (req = *prev) != NULL;
638129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	     prev = &req->dl_next) {
64ca304b6104ffdd120bb6687a88a0625e58bc71cdArnaldo Carvalho de Melo		const struct inet6_request_sock *treq = inet6_rsk(req);
658129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
668129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo		if (inet_rsk(req)->rmt_port == rport &&
678129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo		    req->rsk_ops->family == AF_INET6 &&
688129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo		    ipv6_addr_equal(&treq->rmt_addr, raddr) &&
698129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo		    ipv6_addr_equal(&treq->loc_addr, laddr) &&
708129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo		    (!treq->iif || treq->iif == iif)) {
718129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo			BUG_TRAP(req->sk == NULL);
728129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo			*prevp = prev;
738129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo			return req;
748129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo		}
758129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	}
768129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
778129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	return NULL;
788129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo}
798129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
808129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de MeloEXPORT_SYMBOL_GPL(inet6_csk_search_req);
818129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
828129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melovoid inet6_csk_reqsk_queue_hash_add(struct sock *sk,
838129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo				    struct request_sock *req,
848129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo				    const unsigned long timeout)
858129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo{
868129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	struct inet_connection_sock *icsk = inet_csk(sk);
878129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
88ca304b6104ffdd120bb6687a88a0625e58bc71cdArnaldo Carvalho de Melo	const u32 h = inet6_synq_hash(&inet6_rsk(req)->rmt_addr,
898129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo				      inet_rsk(req)->rmt_port,
908129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo				      lopt->hash_rnd, lopt->nr_table_entries);
918129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
928129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
938129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo	inet_csk_reqsk_queue_added(sk, timeout);
948129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo}
958129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de Melo
968129765ac07c2455c927051e3a8b048b619b56eeArnaldo Carvalho de MeloEXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
97