aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/tcp_ipv6.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-03-26 11:18:44 -0400
committerIngo Molnar <mingo@kernel.org>2012-03-26 11:19:03 -0400
commit7fd52392c56361a40f0c630a82b36b95ca31eac6 (patch)
tree14091de24c6b28ea4cae9826f98aeedb7be091f5 /net/ipv6/tcp_ipv6.c
parentb01c3a0010aabadf745f3e7fdb9cab682e0a28a2 (diff)
parente22057c8599373e5caef0bc42bdb95d2a361ab0d (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.c231
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)
540static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, 540static 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
558static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, 546static 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
570static 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
629static 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
636static 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
666static 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
694static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, 558static 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
743static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, 592static 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
978release_sk1:
979 if (sk1) {
980 rcu_read_unlock();
981 sock_put(sk1);
982 }
983#endif
1096} 984}
1097 985
1098static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, 986static 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 = {
1898static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { 1788static 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 = {
1930static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { 1819static 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
2005static void tcp_v6_destroy_sock(struct sock *sk) 1893static 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}