aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/tcp_ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r--net/ipv6/tcp_ipv6.c139
1 files changed, 74 insertions, 65 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 3312cb8742e2..2bc7fafe7668 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -76,26 +76,27 @@ static struct tcp_func ipv6_mapped;
76static struct tcp_func ipv6_specific; 76static struct tcp_func ipv6_specific;
77 77
78/* I have no idea if this is a good hash for v6 or not. -DaveM */ 78/* I have no idea if this is a good hash for v6 or not. -DaveM */
79static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport, 79static inline int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport,
80 struct in6_addr *faddr, u16 fport) 80 const struct in6_addr *faddr, const u16 fport,
81 const int ehash_size)
81{ 82{
82 int hashent = (lport ^ fport); 83 int hashent = (lport ^ fport);
83 84
84 hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); 85 hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
85 hashent ^= hashent>>16; 86 hashent ^= hashent>>16;
86 hashent ^= hashent>>8; 87 hashent ^= hashent>>8;
87 return (hashent & (tcp_hashinfo.ehash_size - 1)); 88 return (hashent & (ehash_size - 1));
88} 89}
89 90
90static __inline__ int tcp_v6_sk_hashfn(struct sock *sk) 91static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size)
91{ 92{
92 struct inet_sock *inet = inet_sk(sk); 93 const struct inet_sock *inet = inet_sk(sk);
93 struct ipv6_pinfo *np = inet6_sk(sk); 94 const struct ipv6_pinfo *np = inet6_sk(sk);
94 struct in6_addr *laddr = &np->rcv_saddr; 95 const struct in6_addr *laddr = &np->rcv_saddr;
95 struct in6_addr *faddr = &np->daddr; 96 const struct in6_addr *faddr = &np->daddr;
96 __u16 lport = inet->num; 97 const __u16 lport = inet->num;
97 __u16 fport = inet->dport; 98 const __u16 fport = inet->dport;
98 return tcp_v6_hashfn(laddr, lport, faddr, fport); 99 return inet6_ehashfn(laddr, lport, faddr, fport, ehash_size);
99} 100}
100 101
101static inline int tcp_v6_bind_conflict(const struct sock *sk, 102static inline int tcp_v6_bind_conflict(const struct sock *sk,
@@ -231,7 +232,7 @@ static __inline__ void __tcp_v6_hash(struct sock *sk)
231 lock = &tcp_hashinfo.lhash_lock; 232 lock = &tcp_hashinfo.lhash_lock;
232 inet_listen_wlock(&tcp_hashinfo); 233 inet_listen_wlock(&tcp_hashinfo);
233 } else { 234 } else {
234 sk->sk_hashent = tcp_v6_sk_hashfn(sk); 235 sk->sk_hashent = inet6_sk_ehashfn(sk, tcp_hashinfo.ehash_size);
235 list = &tcp_hashinfo.ehash[sk->sk_hashent].chain; 236 list = &tcp_hashinfo.ehash[sk->sk_hashent].chain;
236 lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock; 237 lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock;
237 write_lock(lock); 238 write_lock(lock);
@@ -258,7 +259,10 @@ static void tcp_v6_hash(struct sock *sk)
258 } 259 }
259} 260}
260 261
261static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned short hnum, int dif) 262static struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
263 const struct in6_addr *daddr,
264 const unsigned short hnum,
265 const int dif)
262{ 266{
263 struct sock *sk; 267 struct sock *sk;
264 struct hlist_node *node; 268 struct hlist_node *node;
@@ -266,8 +270,8 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
266 int score, hiscore; 270 int score, hiscore;
267 271
268 hiscore=0; 272 hiscore=0;
269 read_lock(&tcp_hashinfo.lhash_lock); 273 read_lock(&hashinfo->lhash_lock);
270 sk_for_each(sk, node, &tcp_hashinfo.listening_hash[inet_lhashfn(hnum)]) { 274 sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) {
271 if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { 275 if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) {
272 struct ipv6_pinfo *np = inet6_sk(sk); 276 struct ipv6_pinfo *np = inet6_sk(sk);
273 277
@@ -294,7 +298,7 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
294 } 298 }
295 if (result) 299 if (result)
296 sock_hold(result); 300 sock_hold(result);
297 read_unlock(&tcp_hashinfo.lhash_lock); 301 read_unlock(&hashinfo->lhash_lock);
298 return result; 302 return result;
299} 303}
300 304
@@ -304,9 +308,13 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
304 * The sockhash lock must be held as a reader here. 308 * The sockhash lock must be held as a reader here.
305 */ 309 */
306 310
307static inline struct sock *__tcp_v6_lookup_established(struct in6_addr *saddr, u16 sport, 311static inline struct sock *
308 struct in6_addr *daddr, u16 hnum, 312 __inet6_lookup_established(struct inet_hashinfo *hashinfo,
309 int dif) 313 const struct in6_addr *saddr,
314 const u16 sport,
315 const struct in6_addr *daddr,
316 const u16 hnum,
317 const int dif)
310{ 318{
311 struct sock *sk; 319 struct sock *sk;
312 const struct hlist_node *node; 320 const struct hlist_node *node;
@@ -314,8 +322,9 @@ static inline struct sock *__tcp_v6_lookup_established(struct in6_addr *saddr, u
314 /* Optimize here for direct hit, only listening connections can 322 /* Optimize here for direct hit, only listening connections can
315 * have wildcards anyways. 323 * have wildcards anyways.
316 */ 324 */
317 const int hash = tcp_v6_hashfn(daddr, hnum, saddr, sport); 325 const int hash = inet6_ehashfn(daddr, hnum, saddr, sport,
318 struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash]; 326 hashinfo->ehash_size);
327 struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
319 328
320 read_lock(&head->lock); 329 read_lock(&head->lock);
321 sk_for_each(sk, node, &head->chain) { 330 sk_for_each(sk, node, &head->chain) {
@@ -324,7 +333,7 @@ static inline struct sock *__tcp_v6_lookup_established(struct in6_addr *saddr, u
324 goto hit; /* You sunk my battleship! */ 333 goto hit; /* You sunk my battleship! */
325 } 334 }
326 /* Must check for a TIME_WAIT'er before going to listener hash. */ 335 /* Must check for a TIME_WAIT'er before going to listener hash. */
327 sk_for_each(sk, node, &(head + tcp_hashinfo.ehash_size)->chain) { 336 sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
328 const struct inet_timewait_sock *tw = inet_twsk(sk); 337 const struct inet_timewait_sock *tw = inet_twsk(sk);
329 338
330 if(*((__u32 *)&(tw->tw_dport)) == ports && 339 if(*((__u32 *)&(tw->tw_dport)) == ports &&
@@ -347,34 +356,36 @@ hit:
347} 356}
348 357
349 358
350static inline struct sock *__tcp_v6_lookup(struct in6_addr *saddr, u16 sport, 359static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo,
351 struct in6_addr *daddr, u16 hnum, 360 const struct in6_addr *saddr,
352 int dif) 361 const u16 sport,
362 const struct in6_addr *daddr,
363 const u16 hnum,
364 const int dif)
353{ 365{
354 struct sock *sk; 366 struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport,
355 367 daddr, hnum, dif);
356 sk = __tcp_v6_lookup_established(saddr, sport, daddr, hnum, dif);
357
358 if (sk) 368 if (sk)
359 return sk; 369 return sk;
360 370
361 return tcp_v6_lookup_listener(daddr, hnum, dif); 371 return inet6_lookup_listener(hashinfo, daddr, hnum, dif);
362} 372}
363 373
364inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, 374inline struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
365 struct in6_addr *daddr, u16 dport, 375 const struct in6_addr *saddr, const u16 sport,
366 int dif) 376 const struct in6_addr *daddr, const u16 dport,
377 const int dif)
367{ 378{
368 struct sock *sk; 379 struct sock *sk;
369 380
370 local_bh_disable(); 381 local_bh_disable();
371 sk = __tcp_v6_lookup(saddr, sport, daddr, ntohs(dport), dif); 382 sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
372 local_bh_enable(); 383 local_bh_enable();
373 384
374 return sk; 385 return sk;
375} 386}
376 387
377EXPORT_SYMBOL_GPL(tcp_v6_lookup); 388EXPORT_SYMBOL_GPL(inet6_lookup);
378 389
379 390
380/* 391/*
@@ -454,16 +465,17 @@ static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
454 } 465 }
455} 466}
456 467
457static int __tcp_v6_check_established(struct sock *sk, __u16 lport, 468static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
458 struct inet_timewait_sock **twp) 469 struct inet_timewait_sock **twp)
459{ 470{
460 struct inet_sock *inet = inet_sk(sk); 471 struct inet_sock *inet = inet_sk(sk);
461 struct ipv6_pinfo *np = inet6_sk(sk); 472 const struct ipv6_pinfo *np = inet6_sk(sk);
462 struct in6_addr *daddr = &np->rcv_saddr; 473 const struct in6_addr *daddr = &np->rcv_saddr;
463 struct in6_addr *saddr = &np->daddr; 474 const struct in6_addr *saddr = &np->daddr;
464 int dif = sk->sk_bound_dev_if; 475 const int dif = sk->sk_bound_dev_if;
465 const u32 ports = INET_COMBINED_PORTS(inet->dport, lport); 476 const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
466 const int hash = tcp_v6_hashfn(daddr, inet->num, saddr, inet->dport); 477 const int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport,
478 tcp_hashinfo.ehash_size);
467 struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash]; 479 struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
468 struct sock *sk2; 480 struct sock *sk2;
469 const struct hlist_node *node; 481 const struct hlist_node *node;
@@ -637,11 +649,6 @@ out:
637 } 649 }
638} 650}
639 651
640static __inline__ int tcp_v6_iif(struct sk_buff *skb)
641{
642 return IP6CB(skb)->iif;
643}
644
645static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 652static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
646 int addr_len) 653 int addr_len)
647{ 654{
@@ -833,14 +840,15 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
833 int type, int code, int offset, __u32 info) 840 int type, int code, int offset, __u32 info)
834{ 841{
835 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; 842 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
836 struct tcphdr *th = (struct tcphdr *)(skb->data+offset); 843 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
837 struct ipv6_pinfo *np; 844 struct ipv6_pinfo *np;
838 struct sock *sk; 845 struct sock *sk;
839 int err; 846 int err;
840 struct tcp_sock *tp; 847 struct tcp_sock *tp;
841 __u32 seq; 848 __u32 seq;
842 849
843 sk = tcp_v6_lookup(&hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex); 850 sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
851 th->source, skb->dev->ifindex);
844 852
845 if (sk == NULL) { 853 if (sk == NULL) {
846 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); 854 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
@@ -927,7 +935,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
927 goto out; 935 goto out;
928 936
929 req = tcp_v6_search_req(sk, &prev, th->dest, &hdr->daddr, 937 req = tcp_v6_search_req(sk, &prev, th->dest, &hdr->daddr,
930 &hdr->saddr, tcp_v6_iif(skb)); 938 &hdr->saddr, inet6_iif(skb));
931 if (!req) 939 if (!req)
932 goto out; 940 goto out;
933 941
@@ -1138,7 +1146,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
1138 buff->csum); 1146 buff->csum);
1139 1147
1140 fl.proto = IPPROTO_TCP; 1148 fl.proto = IPPROTO_TCP;
1141 fl.oif = tcp_v6_iif(skb); 1149 fl.oif = inet6_iif(skb);
1142 fl.fl_ip_dport = t1->dest; 1150 fl.fl_ip_dport = t1->dest;
1143 fl.fl_ip_sport = t1->source; 1151 fl.fl_ip_sport = t1->source;
1144 1152
@@ -1207,7 +1215,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
1207 buff->csum); 1215 buff->csum);
1208 1216
1209 fl.proto = IPPROTO_TCP; 1217 fl.proto = IPPROTO_TCP;
1210 fl.oif = tcp_v6_iif(skb); 1218 fl.oif = inet6_iif(skb);
1211 fl.fl_ip_dport = t1->dest; 1219 fl.fl_ip_dport = t1->dest;
1212 fl.fl_ip_sport = t1->source; 1220 fl.fl_ip_sport = t1->source;
1213 1221
@@ -1245,20 +1253,18 @@ static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
1245static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) 1253static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1246{ 1254{
1247 struct request_sock *req, **prev; 1255 struct request_sock *req, **prev;
1248 struct tcphdr *th = skb->h.th; 1256 const struct tcphdr *th = skb->h.th;
1249 struct sock *nsk; 1257 struct sock *nsk;
1250 1258
1251 /* Find possible connection requests. */ 1259 /* Find possible connection requests. */
1252 req = tcp_v6_search_req(sk, &prev, th->source, &skb->nh.ipv6h->saddr, 1260 req = tcp_v6_search_req(sk, &prev, th->source, &skb->nh.ipv6h->saddr,
1253 &skb->nh.ipv6h->daddr, tcp_v6_iif(skb)); 1261 &skb->nh.ipv6h->daddr, inet6_iif(skb));
1254 if (req) 1262 if (req)
1255 return tcp_check_req(sk, skb, req, prev); 1263 return tcp_check_req(sk, skb, req, prev);
1256 1264
1257 nsk = __tcp_v6_lookup_established(&skb->nh.ipv6h->saddr, 1265 nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr,
1258 th->source, 1266 th->source, &skb->nh.ipv6h->daddr,
1259 &skb->nh.ipv6h->daddr, 1267 ntohs(th->dest), inet6_iif(skb));
1260 ntohs(th->dest),
1261 tcp_v6_iif(skb));
1262 1268
1263 if (nsk) { 1269 if (nsk) {
1264 if (nsk->sk_state != TCP_TIME_WAIT) { 1270 if (nsk->sk_state != TCP_TIME_WAIT) {
@@ -1346,7 +1352,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1346 /* So that link locals have meaning */ 1352 /* So that link locals have meaning */
1347 if (!sk->sk_bound_dev_if && 1353 if (!sk->sk_bound_dev_if &&
1348 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) 1354 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1349 treq->iif = tcp_v6_iif(skb); 1355 treq->iif = inet6_iif(skb);
1350 1356
1351 if (isn == 0) 1357 if (isn == 0)
1352 isn = tcp_v6_init_sequence(sk,skb); 1358 isn = tcp_v6_init_sequence(sk,skb);
@@ -1411,7 +1417,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1411 newsk->sk_backlog_rcv = tcp_v4_do_rcv; 1417 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
1412 newnp->pktoptions = NULL; 1418 newnp->pktoptions = NULL;
1413 newnp->opt = NULL; 1419 newnp->opt = NULL;
1414 newnp->mcast_oif = tcp_v6_iif(skb); 1420 newnp->mcast_oif = inet6_iif(skb);
1415 newnp->mcast_hops = skb->nh.ipv6h->hop_limit; 1421 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
1416 1422
1417 /* 1423 /*
@@ -1516,7 +1522,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1516 skb_set_owner_r(newnp->pktoptions, newsk); 1522 skb_set_owner_r(newnp->pktoptions, newsk);
1517 } 1523 }
1518 newnp->opt = NULL; 1524 newnp->opt = NULL;
1519 newnp->mcast_oif = tcp_v6_iif(skb); 1525 newnp->mcast_oif = inet6_iif(skb);
1520 newnp->mcast_hops = skb->nh.ipv6h->hop_limit; 1526 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
1521 1527
1522 /* Clone native IPv6 options from listening socket (if any) 1528 /* Clone native IPv6 options from listening socket (if any)
@@ -1691,7 +1697,7 @@ ipv6_pktoptions:
1691 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt && 1697 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1692 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { 1698 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
1693 if (np->rxopt.bits.rxinfo) 1699 if (np->rxopt.bits.rxinfo)
1694 np->mcast_oif = tcp_v6_iif(opt_skb); 1700 np->mcast_oif = inet6_iif(opt_skb);
1695 if (np->rxopt.bits.rxhlim) 1701 if (np->rxopt.bits.rxhlim)
1696 np->mcast_hops = opt_skb->nh.ipv6h->hop_limit; 1702 np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
1697 if (ipv6_opt_accepted(sk, opt_skb)) { 1703 if (ipv6_opt_accepted(sk, opt_skb)) {
@@ -1746,8 +1752,9 @@ static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
1746 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h); 1752 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
1747 TCP_SKB_CB(skb)->sacked = 0; 1753 TCP_SKB_CB(skb)->sacked = 0;
1748 1754
1749 sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source, 1755 sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source,
1750 &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb)); 1756 &skb->nh.ipv6h->daddr, ntohs(th->dest),
1757 inet6_iif(skb));
1751 1758
1752 if (!sk) 1759 if (!sk)
1753 goto no_tcp_socket; 1760 goto no_tcp_socket;
@@ -1818,7 +1825,9 @@ do_time_wait:
1818 { 1825 {
1819 struct sock *sk2; 1826 struct sock *sk2;
1820 1827
1821 sk2 = tcp_v6_lookup_listener(&skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb)); 1828 sk2 = inet6_lookup_listener(&tcp_hashinfo,
1829 &skb->nh.ipv6h->daddr,
1830 ntohs(th->dest), inet6_iif(skb));
1822 if (sk2 != NULL) { 1831 if (sk2 != NULL) {
1823 struct inet_timewait_sock *tw = inet_twsk(sk); 1832 struct inet_timewait_sock *tw = inet_twsk(sk);
1824 inet_twsk_deschedule(tw, &tcp_death_row); 1833 inet_twsk_deschedule(tw, &tcp_death_row);