diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-03-26 11:18:44 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-03-26 11:19:03 -0400 |
commit | 7fd52392c56361a40f0c630a82b36b95ca31eac6 (patch) | |
tree | 14091de24c6b28ea4cae9826f98aeedb7be091f5 /net/ipv6/tcp_ipv6.c | |
parent | b01c3a0010aabadf745f3e7fdb9cab682e0a28a2 (diff) | |
parent | e22057c8599373e5caef0bc42bdb95d2a361ab0d (diff) |
Merge branch 'linus' into perf/urgent
Merge reason: we need to fix a non-trivial merge conflict.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 231 |
1 files changed, 57 insertions, 174 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3edd05ae4388..12c6ece67f39 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -540,19 +540,7 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req) | |||
540 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | 540 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, |
541 | const struct in6_addr *addr) | 541 | const struct in6_addr *addr) |
542 | { | 542 | { |
543 | struct tcp_sock *tp = tcp_sk(sk); | 543 | return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6); |
544 | int i; | ||
545 | |||
546 | BUG_ON(tp == NULL); | ||
547 | |||
548 | if (!tp->md5sig_info || !tp->md5sig_info->entries6) | ||
549 | return NULL; | ||
550 | |||
551 | for (i = 0; i < tp->md5sig_info->entries6; i++) { | ||
552 | if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr)) | ||
553 | return &tp->md5sig_info->keys6[i].base; | ||
554 | } | ||
555 | return NULL; | ||
556 | } | 544 | } |
557 | 545 | ||
558 | static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, | 546 | static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, |
@@ -567,136 +555,11 @@ static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, | |||
567 | return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); | 555 | return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); |
568 | } | 556 | } |
569 | 557 | ||
570 | static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer, | ||
571 | char *newkey, u8 newkeylen) | ||
572 | { | ||
573 | /* Add key to the list */ | ||
574 | struct tcp_md5sig_key *key; | ||
575 | struct tcp_sock *tp = tcp_sk(sk); | ||
576 | struct tcp6_md5sig_key *keys; | ||
577 | |||
578 | key = tcp_v6_md5_do_lookup(sk, peer); | ||
579 | if (key) { | ||
580 | /* modify existing entry - just update that one */ | ||
581 | kfree(key->key); | ||
582 | key->key = newkey; | ||
583 | key->keylen = newkeylen; | ||
584 | } else { | ||
585 | /* reallocate new list if current one is full. */ | ||
586 | if (!tp->md5sig_info) { | ||
587 | tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); | ||
588 | if (!tp->md5sig_info) { | ||
589 | kfree(newkey); | ||
590 | return -ENOMEM; | ||
591 | } | ||
592 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); | ||
593 | } | ||
594 | if (tp->md5sig_info->entries6 == 0 && | ||
595 | tcp_alloc_md5sig_pool(sk) == NULL) { | ||
596 | kfree(newkey); | ||
597 | return -ENOMEM; | ||
598 | } | ||
599 | if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) { | ||
600 | keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) * | ||
601 | (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC); | ||
602 | |||
603 | if (!keys) { | ||
604 | kfree(newkey); | ||
605 | if (tp->md5sig_info->entries6 == 0) | ||
606 | tcp_free_md5sig_pool(); | ||
607 | return -ENOMEM; | ||
608 | } | ||
609 | |||
610 | if (tp->md5sig_info->entries6) | ||
611 | memmove(keys, tp->md5sig_info->keys6, | ||
612 | (sizeof (tp->md5sig_info->keys6[0]) * | ||
613 | tp->md5sig_info->entries6)); | ||
614 | |||
615 | kfree(tp->md5sig_info->keys6); | ||
616 | tp->md5sig_info->keys6 = keys; | ||
617 | tp->md5sig_info->alloced6++; | ||
618 | } | ||
619 | |||
620 | tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr = *peer; | ||
621 | tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey; | ||
622 | tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen; | ||
623 | |||
624 | tp->md5sig_info->entries6++; | ||
625 | } | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk, | ||
630 | u8 *newkey, __u8 newkeylen) | ||
631 | { | ||
632 | return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr, | ||
633 | newkey, newkeylen); | ||
634 | } | ||
635 | |||
636 | static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer) | ||
637 | { | ||
638 | struct tcp_sock *tp = tcp_sk(sk); | ||
639 | int i; | ||
640 | |||
641 | for (i = 0; i < tp->md5sig_info->entries6; i++) { | ||
642 | if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) { | ||
643 | /* Free the key */ | ||
644 | kfree(tp->md5sig_info->keys6[i].base.key); | ||
645 | tp->md5sig_info->entries6--; | ||
646 | |||
647 | if (tp->md5sig_info->entries6 == 0) { | ||
648 | kfree(tp->md5sig_info->keys6); | ||
649 | tp->md5sig_info->keys6 = NULL; | ||
650 | tp->md5sig_info->alloced6 = 0; | ||
651 | tcp_free_md5sig_pool(); | ||
652 | } else { | ||
653 | /* shrink the database */ | ||
654 | if (tp->md5sig_info->entries6 != i) | ||
655 | memmove(&tp->md5sig_info->keys6[i], | ||
656 | &tp->md5sig_info->keys6[i+1], | ||
657 | (tp->md5sig_info->entries6 - i) | ||
658 | * sizeof (tp->md5sig_info->keys6[0])); | ||
659 | } | ||
660 | return 0; | ||
661 | } | ||
662 | } | ||
663 | return -ENOENT; | ||
664 | } | ||
665 | |||
666 | static void tcp_v6_clear_md5_list (struct sock *sk) | ||
667 | { | ||
668 | struct tcp_sock *tp = tcp_sk(sk); | ||
669 | int i; | ||
670 | |||
671 | if (tp->md5sig_info->entries6) { | ||
672 | for (i = 0; i < tp->md5sig_info->entries6; i++) | ||
673 | kfree(tp->md5sig_info->keys6[i].base.key); | ||
674 | tp->md5sig_info->entries6 = 0; | ||
675 | tcp_free_md5sig_pool(); | ||
676 | } | ||
677 | |||
678 | kfree(tp->md5sig_info->keys6); | ||
679 | tp->md5sig_info->keys6 = NULL; | ||
680 | tp->md5sig_info->alloced6 = 0; | ||
681 | |||
682 | if (tp->md5sig_info->entries4) { | ||
683 | for (i = 0; i < tp->md5sig_info->entries4; i++) | ||
684 | kfree(tp->md5sig_info->keys4[i].base.key); | ||
685 | tp->md5sig_info->entries4 = 0; | ||
686 | tcp_free_md5sig_pool(); | ||
687 | } | ||
688 | |||
689 | kfree(tp->md5sig_info->keys4); | ||
690 | tp->md5sig_info->keys4 = NULL; | ||
691 | tp->md5sig_info->alloced4 = 0; | ||
692 | } | ||
693 | |||
694 | static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | 558 | static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, |
695 | int optlen) | 559 | int optlen) |
696 | { | 560 | { |
697 | struct tcp_md5sig cmd; | 561 | struct tcp_md5sig cmd; |
698 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; | 562 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; |
699 | u8 *newkey; | ||
700 | 563 | ||
701 | if (optlen < sizeof(cmd)) | 564 | if (optlen < sizeof(cmd)) |
702 | return -EINVAL; | 565 | return -EINVAL; |
@@ -708,36 +571,22 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
708 | return -EINVAL; | 571 | return -EINVAL; |
709 | 572 | ||
710 | if (!cmd.tcpm_keylen) { | 573 | if (!cmd.tcpm_keylen) { |
711 | if (!tcp_sk(sk)->md5sig_info) | ||
712 | return -ENOENT; | ||
713 | if (ipv6_addr_v4mapped(&sin6->sin6_addr)) | 574 | if (ipv6_addr_v4mapped(&sin6->sin6_addr)) |
714 | return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]); | 575 | return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], |
715 | return tcp_v6_md5_do_del(sk, &sin6->sin6_addr); | 576 | AF_INET); |
577 | return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, | ||
578 | AF_INET6); | ||
716 | } | 579 | } |
717 | 580 | ||
718 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) | 581 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) |
719 | return -EINVAL; | 582 | return -EINVAL; |
720 | 583 | ||
721 | if (!tcp_sk(sk)->md5sig_info) { | 584 | if (ipv6_addr_v4mapped(&sin6->sin6_addr)) |
722 | struct tcp_sock *tp = tcp_sk(sk); | 585 | return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], |
723 | struct tcp_md5sig_info *p; | 586 | AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); |
724 | |||
725 | p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); | ||
726 | if (!p) | ||
727 | return -ENOMEM; | ||
728 | 587 | ||
729 | tp->md5sig_info = p; | 588 | return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr, |
730 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); | 589 | AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); |
731 | } | ||
732 | |||
733 | newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); | ||
734 | if (!newkey) | ||
735 | return -ENOMEM; | ||
736 | if (ipv6_addr_v4mapped(&sin6->sin6_addr)) { | ||
737 | return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3], | ||
738 | newkey, cmd.tcpm_keylen); | ||
739 | } | ||
740 | return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); | ||
741 | } | 590 | } |
742 | 591 | ||
743 | static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, | 592 | static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, |
@@ -1074,6 +923,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1074 | const struct tcphdr *th = tcp_hdr(skb); | 923 | const struct tcphdr *th = tcp_hdr(skb); |
1075 | u32 seq = 0, ack_seq = 0; | 924 | u32 seq = 0, ack_seq = 0; |
1076 | struct tcp_md5sig_key *key = NULL; | 925 | struct tcp_md5sig_key *key = NULL; |
926 | #ifdef CONFIG_TCP_MD5SIG | ||
927 | const __u8 *hash_location = NULL; | ||
928 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
929 | unsigned char newhash[16]; | ||
930 | int genhash; | ||
931 | struct sock *sk1 = NULL; | ||
932 | #endif | ||
1077 | 933 | ||
1078 | if (th->rst) | 934 | if (th->rst) |
1079 | return; | 935 | return; |
@@ -1082,8 +938,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1082 | return; | 938 | return; |
1083 | 939 | ||
1084 | #ifdef CONFIG_TCP_MD5SIG | 940 | #ifdef CONFIG_TCP_MD5SIG |
1085 | if (sk) | 941 | hash_location = tcp_parse_md5sig_option(th); |
1086 | key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); | 942 | if (!sk && hash_location) { |
943 | /* | ||
944 | * active side is lost. Try to find listening socket through | ||
945 | * source port, and then find md5 key through listening socket. | ||
946 | * we are not loose security here: | ||
947 | * Incoming packet is checked with md5 hash with finding key, | ||
948 | * no RST generated if md5 hash doesn't match. | ||
949 | */ | ||
950 | sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), | ||
951 | &tcp_hashinfo, &ipv6h->daddr, | ||
952 | ntohs(th->source), inet6_iif(skb)); | ||
953 | if (!sk1) | ||
954 | return; | ||
955 | |||
956 | rcu_read_lock(); | ||
957 | key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr); | ||
958 | if (!key) | ||
959 | goto release_sk1; | ||
960 | |||
961 | genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb); | ||
962 | if (genhash || memcmp(hash_location, newhash, 16) != 0) | ||
963 | goto release_sk1; | ||
964 | } else { | ||
965 | key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; | ||
966 | } | ||
1087 | #endif | 967 | #endif |
1088 | 968 | ||
1089 | if (th->ack) | 969 | if (th->ack) |
@@ -1093,6 +973,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1093 | (th->doff << 2); | 973 | (th->doff << 2); |
1094 | 974 | ||
1095 | tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); | 975 | tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); |
976 | |||
977 | #ifdef CONFIG_TCP_MD5SIG | ||
978 | release_sk1: | ||
979 | if (sk1) { | ||
980 | rcu_read_unlock(); | ||
981 | sock_put(sk1); | ||
982 | } | ||
983 | #endif | ||
1096 | } | 984 | } |
1097 | 985 | ||
1098 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, | 986 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, |
@@ -1394,6 +1282,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1394 | newnp->opt = NULL; | 1282 | newnp->opt = NULL; |
1395 | newnp->mcast_oif = inet6_iif(skb); | 1283 | newnp->mcast_oif = inet6_iif(skb); |
1396 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1284 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
1285 | newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | ||
1397 | 1286 | ||
1398 | /* | 1287 | /* |
1399 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count | 1288 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count |
@@ -1472,6 +1361,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1472 | newnp->opt = NULL; | 1361 | newnp->opt = NULL; |
1473 | newnp->mcast_oif = inet6_iif(skb); | 1362 | newnp->mcast_oif = inet6_iif(skb); |
1474 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1363 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
1364 | newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | ||
1475 | 1365 | ||
1476 | /* Clone native IPv6 options from listening socket (if any) | 1366 | /* Clone native IPv6 options from listening socket (if any) |
1477 | 1367 | ||
@@ -1510,10 +1400,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1510 | * memory, then we end up not copying the key | 1400 | * memory, then we end up not copying the key |
1511 | * across. Shucks. | 1401 | * across. Shucks. |
1512 | */ | 1402 | */ |
1513 | char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); | 1403 | tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newnp->daddr, |
1514 | if (newkey != NULL) | 1404 | AF_INET6, key->key, key->keylen, GFP_ATOMIC); |
1515 | tcp_v6_md5_do_add(newsk, &newnp->daddr, | ||
1516 | newkey, key->keylen); | ||
1517 | } | 1405 | } |
1518 | #endif | 1406 | #endif |
1519 | 1407 | ||
@@ -1676,6 +1564,8 @@ ipv6_pktoptions: | |||
1676 | np->mcast_oif = inet6_iif(opt_skb); | 1564 | np->mcast_oif = inet6_iif(opt_skb); |
1677 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) | 1565 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) |
1678 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; | 1566 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; |
1567 | if (np->rxopt.bits.rxtclass) | ||
1568 | np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | ||
1679 | if (ipv6_opt_accepted(sk, opt_skb)) { | 1569 | if (ipv6_opt_accepted(sk, opt_skb)) { |
1680 | skb_set_owner_r(opt_skb, sk); | 1570 | skb_set_owner_r(opt_skb, sk); |
1681 | opt_skb = xchg(&np->pktoptions, opt_skb); | 1571 | opt_skb = xchg(&np->pktoptions, opt_skb); |
@@ -1898,7 +1788,6 @@ static const struct inet_connection_sock_af_ops ipv6_specific = { | |||
1898 | static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { | 1788 | static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { |
1899 | .md5_lookup = tcp_v6_md5_lookup, | 1789 | .md5_lookup = tcp_v6_md5_lookup, |
1900 | .calc_md5_hash = tcp_v6_md5_hash_skb, | 1790 | .calc_md5_hash = tcp_v6_md5_hash_skb, |
1901 | .md5_add = tcp_v6_md5_add_func, | ||
1902 | .md5_parse = tcp_v6_parse_md5_keys, | 1791 | .md5_parse = tcp_v6_parse_md5_keys, |
1903 | }; | 1792 | }; |
1904 | #endif | 1793 | #endif |
@@ -1930,7 +1819,6 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1930 | static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { | 1819 | static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { |
1931 | .md5_lookup = tcp_v4_md5_lookup, | 1820 | .md5_lookup = tcp_v4_md5_lookup, |
1932 | .calc_md5_hash = tcp_v4_md5_hash_skb, | 1821 | .calc_md5_hash = tcp_v4_md5_hash_skb, |
1933 | .md5_add = tcp_v6_md5_add_func, | ||
1934 | .md5_parse = tcp_v6_parse_md5_keys, | 1822 | .md5_parse = tcp_v6_parse_md5_keys, |
1935 | }; | 1823 | }; |
1936 | #endif | 1824 | #endif |
@@ -2004,11 +1892,6 @@ static int tcp_v6_init_sock(struct sock *sk) | |||
2004 | 1892 | ||
2005 | static void tcp_v6_destroy_sock(struct sock *sk) | 1893 | static void tcp_v6_destroy_sock(struct sock *sk) |
2006 | { | 1894 | { |
2007 | #ifdef CONFIG_TCP_MD5SIG | ||
2008 | /* Clean up the MD5 key list */ | ||
2009 | if (tcp_sk(sk)->md5sig_info) | ||
2010 | tcp_v6_clear_md5_list(sk); | ||
2011 | #endif | ||
2012 | tcp_v4_destroy_sock(sk); | 1895 | tcp_v4_destroy_sock(sk); |
2013 | inet6_destroy_sock(sk); | 1896 | inet6_destroy_sock(sk); |
2014 | } | 1897 | } |