diff options
-rw-r--r-- | fs/nfs/super.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index d27aa1db0074..73a8e5970f02 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/inet.h> | 47 | #include <linux/inet.h> |
48 | #include <linux/in6.h> | 48 | #include <linux/in6.h> |
49 | #include <net/ipv6.h> | 49 | #include <net/ipv6.h> |
50 | #include <linux/netdevice.h> | ||
50 | #include <linux/nfs_xdr.h> | 51 | #include <linux/nfs_xdr.h> |
51 | #include <linux/magic.h> | 52 | #include <linux/magic.h> |
52 | #include <linux/parser.h> | 53 | #include <linux/parser.h> |
@@ -725,12 +726,48 @@ static void nfs_parse_ipv4_address(char *string, size_t str_len, | |||
725 | *addr_len = 0; | 726 | *addr_len = 0; |
726 | } | 727 | } |
727 | 728 | ||
729 | #define IPV6_SCOPE_DELIMITER '%' | ||
730 | |||
728 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 731 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
732 | static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | ||
733 | const char *delim, | ||
734 | struct sockaddr_in6 *sin6) | ||
735 | { | ||
736 | char *p; | ||
737 | size_t len; | ||
738 | |||
739 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | ||
740 | return ; | ||
741 | if (*delim != IPV6_SCOPE_DELIMITER) | ||
742 | return; | ||
743 | |||
744 | len = (string + str_len) - delim - 1; | ||
745 | p = kstrndup(delim + 1, len, GFP_KERNEL); | ||
746 | if (p) { | ||
747 | unsigned long scope_id = 0; | ||
748 | struct net_device *dev; | ||
749 | |||
750 | dev = dev_get_by_name(&init_net, p); | ||
751 | if (dev != NULL) { | ||
752 | scope_id = dev->ifindex; | ||
753 | dev_put(dev); | ||
754 | } else { | ||
755 | /* scope_id is set to zero on error */ | ||
756 | strict_strtoul(p, 10, &scope_id); | ||
757 | } | ||
758 | |||
759 | kfree(p); | ||
760 | sin6->sin6_scope_id = scope_id; | ||
761 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); | ||
762 | } | ||
763 | } | ||
764 | |||
729 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | 765 | static void nfs_parse_ipv6_address(char *string, size_t str_len, |
730 | struct sockaddr *sap, size_t *addr_len) | 766 | struct sockaddr *sap, size_t *addr_len) |
731 | { | 767 | { |
732 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | 768 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; |
733 | u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; | 769 | u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; |
770 | const char *delim; | ||
734 | 771 | ||
735 | if (str_len <= INET6_ADDRSTRLEN) { | 772 | if (str_len <= INET6_ADDRSTRLEN) { |
736 | dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", | 773 | dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", |
@@ -738,8 +775,10 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len, | |||
738 | 775 | ||
739 | sin6->sin6_family = AF_INET6; | 776 | sin6->sin6_family = AF_INET6; |
740 | *addr_len = sizeof(*sin6); | 777 | *addr_len = sizeof(*sin6); |
741 | if (in6_pton(string, str_len, addr, '\0', NULL)) | 778 | if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) { |
779 | nfs_parse_ipv6_scope_id(string, str_len, delim, sin6); | ||
742 | return; | 780 | return; |
781 | } | ||
743 | } | 782 | } |
744 | 783 | ||
745 | sap->sa_family = AF_UNSPEC; | 784 | sap->sa_family = AF_UNSPEC; |