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