aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/super.c41
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)
732static 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
729static void nfs_parse_ipv6_address(char *string, size_t str_len, 765static 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;