diff options
Diffstat (limited to 'include/net/ipv6.h')
-rw-r--r-- | include/net/ipv6.h | 152 |
1 files changed, 125 insertions, 27 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 5af66b26ebdd..64d12e77719a 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <linux/ipv6.h> | 16 | #include <linux/ipv6.h> |
17 | #include <linux/hardirq.h> | 17 | #include <linux/hardirq.h> |
18 | #include <linux/jhash.h> | ||
18 | #include <net/if_inet6.h> | 19 | #include <net/if_inet6.h> |
19 | #include <net/ndisc.h> | 20 | #include <net/ndisc.h> |
20 | #include <net/flow.h> | 21 | #include <net/flow.h> |
@@ -222,6 +223,7 @@ struct ip6_flowlabel { | |||
222 | struct in6_addr dst; | 223 | struct in6_addr dst; |
223 | struct ipv6_txoptions *opt; | 224 | struct ipv6_txoptions *opt; |
224 | unsigned long linger; | 225 | unsigned long linger; |
226 | struct rcu_head rcu; | ||
225 | u8 share; | 227 | u8 share; |
226 | union { | 228 | union { |
227 | struct pid *pid; | 229 | struct pid *pid; |
@@ -238,6 +240,7 @@ struct ip6_flowlabel { | |||
238 | struct ipv6_fl_socklist { | 240 | struct ipv6_fl_socklist { |
239 | struct ipv6_fl_socklist *next; | 241 | struct ipv6_fl_socklist *next; |
240 | struct ip6_flowlabel *fl; | 242 | struct ip6_flowlabel *fl; |
243 | struct rcu_head rcu; | ||
241 | }; | 244 | }; |
242 | 245 | ||
243 | extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); | 246 | extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); |
@@ -288,12 +291,12 @@ static inline int ip6_frag_nqueues(struct net *net) | |||
288 | 291 | ||
289 | static inline int ip6_frag_mem(struct net *net) | 292 | static inline int ip6_frag_mem(struct net *net) |
290 | { | 293 | { |
291 | return atomic_read(&net->ipv6.frags.mem); | 294 | return sum_frag_mem_limit(&net->ipv6.frags); |
292 | } | 295 | } |
293 | #endif | 296 | #endif |
294 | 297 | ||
295 | #define IPV6_FRAG_HIGH_THRESH (256 * 1024) /* 262144 */ | 298 | #define IPV6_FRAG_HIGH_THRESH (4 * 1024*1024) /* 4194304 */ |
296 | #define IPV6_FRAG_LOW_THRESH (192 * 1024) /* 196608 */ | 299 | #define IPV6_FRAG_LOW_THRESH (3 * 1024*1024) /* 3145728 */ |
297 | #define IPV6_FRAG_TIMEOUT (60 * HZ) /* 60 seconds */ | 300 | #define IPV6_FRAG_TIMEOUT (60 * HZ) /* 60 seconds */ |
298 | 301 | ||
299 | extern int __ipv6_addr_type(const struct in6_addr *addr); | 302 | extern int __ipv6_addr_type(const struct in6_addr *addr); |
@@ -355,14 +358,32 @@ static inline void ipv6_addr_prefix(struct in6_addr *pfx, | |||
355 | pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b); | 358 | pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b); |
356 | } | 359 | } |
357 | 360 | ||
361 | static inline void __ipv6_addr_set_half(__be32 *addr, | ||
362 | __be32 wh, __be32 wl) | ||
363 | { | ||
364 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 | ||
365 | #if defined(__BIG_ENDIAN) | ||
366 | if (__builtin_constant_p(wh) && __builtin_constant_p(wl)) { | ||
367 | *(__force u64 *)addr = ((__force u64)(wh) << 32 | (__force u64)(wl)); | ||
368 | return; | ||
369 | } | ||
370 | #elif defined(__LITTLE_ENDIAN) | ||
371 | if (__builtin_constant_p(wl) && __builtin_constant_p(wh)) { | ||
372 | *(__force u64 *)addr = ((__force u64)(wl) << 32 | (__force u64)(wh)); | ||
373 | return; | ||
374 | } | ||
375 | #endif | ||
376 | #endif | ||
377 | addr[0] = wh; | ||
378 | addr[1] = wl; | ||
379 | } | ||
380 | |||
358 | static inline void ipv6_addr_set(struct in6_addr *addr, | 381 | static inline void ipv6_addr_set(struct in6_addr *addr, |
359 | __be32 w1, __be32 w2, | 382 | __be32 w1, __be32 w2, |
360 | __be32 w3, __be32 w4) | 383 | __be32 w3, __be32 w4) |
361 | { | 384 | { |
362 | addr->s6_addr32[0] = w1; | 385 | __ipv6_addr_set_half(&addr->s6_addr32[0], w1, w2); |
363 | addr->s6_addr32[1] = w2; | 386 | __ipv6_addr_set_half(&addr->s6_addr32[2], w3, w4); |
364 | addr->s6_addr32[2] = w3; | ||
365 | addr->s6_addr32[3] = w4; | ||
366 | } | 387 | } |
367 | 388 | ||
368 | static inline bool ipv6_addr_equal(const struct in6_addr *a1, | 389 | static inline bool ipv6_addr_equal(const struct in6_addr *a1, |
@@ -381,9 +402,37 @@ static inline bool ipv6_addr_equal(const struct in6_addr *a1, | |||
381 | #endif | 402 | #endif |
382 | } | 403 | } |
383 | 404 | ||
384 | static inline bool __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2, | 405 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 |
385 | unsigned int prefixlen) | 406 | static inline bool __ipv6_prefix_equal64_half(const __be64 *a1, |
407 | const __be64 *a2, | ||
408 | unsigned int len) | ||
409 | { | ||
410 | if (len && ((*a1 ^ *a2) & cpu_to_be64((~0UL) << (64 - len)))) | ||
411 | return false; | ||
412 | return true; | ||
413 | } | ||
414 | |||
415 | static inline bool ipv6_prefix_equal(const struct in6_addr *addr1, | ||
416 | const struct in6_addr *addr2, | ||
417 | unsigned int prefixlen) | ||
418 | { | ||
419 | const __be64 *a1 = (const __be64 *)addr1; | ||
420 | const __be64 *a2 = (const __be64 *)addr2; | ||
421 | |||
422 | if (prefixlen >= 64) { | ||
423 | if (a1[0] ^ a2[0]) | ||
424 | return false; | ||
425 | return __ipv6_prefix_equal64_half(a1 + 1, a2 + 1, prefixlen - 64); | ||
426 | } | ||
427 | return __ipv6_prefix_equal64_half(a1, a2, prefixlen); | ||
428 | } | ||
429 | #else | ||
430 | static inline bool ipv6_prefix_equal(const struct in6_addr *addr1, | ||
431 | const struct in6_addr *addr2, | ||
432 | unsigned int prefixlen) | ||
386 | { | 433 | { |
434 | const __be32 *a1 = addr1->s6_addr32; | ||
435 | const __be32 *a2 = addr2->s6_addr32; | ||
387 | unsigned int pdw, pbi; | 436 | unsigned int pdw, pbi; |
388 | 437 | ||
389 | /* check complete u32 in prefix */ | 438 | /* check complete u32 in prefix */ |
@@ -398,14 +447,7 @@ static inline bool __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2, | |||
398 | 447 | ||
399 | return true; | 448 | return true; |
400 | } | 449 | } |
401 | 450 | #endif | |
402 | static inline bool ipv6_prefix_equal(const struct in6_addr *a1, | ||
403 | const struct in6_addr *a2, | ||
404 | unsigned int prefixlen) | ||
405 | { | ||
406 | return __ipv6_prefix_equal(a1->s6_addr32, a2->s6_addr32, | ||
407 | prefixlen); | ||
408 | } | ||
409 | 451 | ||
410 | struct inet_frag_queue; | 452 | struct inet_frag_queue; |
411 | 453 | ||
@@ -473,16 +515,38 @@ static inline u32 ipv6_addr_hash(const struct in6_addr *a) | |||
473 | #endif | 515 | #endif |
474 | } | 516 | } |
475 | 517 | ||
518 | /* more secured version of ipv6_addr_hash() */ | ||
519 | static inline u32 ipv6_addr_jhash(const struct in6_addr *a) | ||
520 | { | ||
521 | u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1]; | ||
522 | |||
523 | return jhash_3words(v, | ||
524 | (__force u32)a->s6_addr32[2], | ||
525 | (__force u32)a->s6_addr32[3], | ||
526 | ipv6_hash_secret); | ||
527 | } | ||
528 | |||
476 | static inline bool ipv6_addr_loopback(const struct in6_addr *a) | 529 | static inline bool ipv6_addr_loopback(const struct in6_addr *a) |
477 | { | 530 | { |
531 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 | ||
532 | const unsigned long *ul = (const unsigned long *)a; | ||
533 | |||
534 | return (ul[0] | (ul[1] ^ cpu_to_be64(1))) == 0UL; | ||
535 | #else | ||
478 | return (a->s6_addr32[0] | a->s6_addr32[1] | | 536 | return (a->s6_addr32[0] | a->s6_addr32[1] | |
479 | a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0; | 537 | a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0; |
538 | #endif | ||
480 | } | 539 | } |
481 | 540 | ||
482 | static inline bool ipv6_addr_v4mapped(const struct in6_addr *a) | 541 | static inline bool ipv6_addr_v4mapped(const struct in6_addr *a) |
483 | { | 542 | { |
484 | return (a->s6_addr32[0] | a->s6_addr32[1] | | 543 | return ( |
485 | (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0; | 544 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 |
545 | *(__be64 *)a | | ||
546 | #else | ||
547 | (a->s6_addr32[0] | a->s6_addr32[1]) | | ||
548 | #endif | ||
549 | (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0UL; | ||
486 | } | 550 | } |
487 | 551 | ||
488 | /* | 552 | /* |
@@ -507,7 +571,7 @@ static inline void ipv6_addr_set_v4mapped(const __be32 addr, | |||
507 | * find the first different bit between two addresses | 571 | * find the first different bit between two addresses |
508 | * length of address must be a multiple of 32bits | 572 | * length of address must be a multiple of 32bits |
509 | */ | 573 | */ |
510 | static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen) | 574 | static inline int __ipv6_addr_diff32(const void *token1, const void *token2, int addrlen) |
511 | { | 575 | { |
512 | const __be32 *a1 = token1, *a2 = token2; | 576 | const __be32 *a1 = token1, *a2 = token2; |
513 | int i; | 577 | int i; |
@@ -539,6 +603,33 @@ static inline int __ipv6_addr_diff(const void *token1, const void *token2, int a | |||
539 | return addrlen << 5; | 603 | return addrlen << 5; |
540 | } | 604 | } |
541 | 605 | ||
606 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 | ||
607 | static inline int __ipv6_addr_diff64(const void *token1, const void *token2, int addrlen) | ||
608 | { | ||
609 | const __be64 *a1 = token1, *a2 = token2; | ||
610 | int i; | ||
611 | |||
612 | addrlen >>= 3; | ||
613 | |||
614 | for (i = 0; i < addrlen; i++) { | ||
615 | __be64 xb = a1[i] ^ a2[i]; | ||
616 | if (xb) | ||
617 | return i * 64 + 63 - __fls(be64_to_cpu(xb)); | ||
618 | } | ||
619 | |||
620 | return addrlen << 6; | ||
621 | } | ||
622 | #endif | ||
623 | |||
624 | static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen) | ||
625 | { | ||
626 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 | ||
627 | if (__builtin_constant_p(addrlen) && !(addrlen & 7)) | ||
628 | return __ipv6_addr_diff64(token1, token2, addrlen); | ||
629 | #endif | ||
630 | return __ipv6_addr_diff32(token1, token2, addrlen); | ||
631 | } | ||
632 | |||
542 | static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2) | 633 | static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2) |
543 | { | 634 | { |
544 | return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); | 635 | return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); |
@@ -547,6 +638,20 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add | |||
547 | extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt); | 638 | extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt); |
548 | 639 | ||
549 | /* | 640 | /* |
641 | * Header manipulation | ||
642 | */ | ||
643 | static inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass, | ||
644 | __be32 flowlabel) | ||
645 | { | ||
646 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel; | ||
647 | } | ||
648 | |||
649 | static inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr) | ||
650 | { | ||
651 | return *(__be32 *)hdr & IPV6_FLOWINFO_MASK; | ||
652 | } | ||
653 | |||
654 | /* | ||
550 | * Prototypes exported by ipv6 | 655 | * Prototypes exported by ipv6 |
551 | */ | 656 | */ |
552 | 657 | ||
@@ -570,13 +675,6 @@ extern int ip6_xmit(struct sock *sk, | |||
570 | struct ipv6_txoptions *opt, | 675 | struct ipv6_txoptions *opt, |
571 | int tclass); | 676 | int tclass); |
572 | 677 | ||
573 | extern int ip6_nd_hdr(struct sock *sk, | ||
574 | struct sk_buff *skb, | ||
575 | struct net_device *dev, | ||
576 | const struct in6_addr *saddr, | ||
577 | const struct in6_addr *daddr, | ||
578 | int proto, int len); | ||
579 | |||
580 | extern int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); | 678 | extern int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); |
581 | 679 | ||
582 | extern int ip6_append_data(struct sock *sk, | 680 | extern int ip6_append_data(struct sock *sk, |