aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/super.c100
-rw-r--r--include/linux/inet.h7
2 files changed, 77 insertions, 30 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ea4abd266a7a..d27aa1db0074 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -705,38 +705,76 @@ static int nfs_verify_server_address(struct sockaddr *addr)
705 return 0; 705 return 0;
706} 706}
707 707
708/* 708static void nfs_parse_ipv4_address(char *string, size_t str_len,
709 * Parse string addresses passed in via a mount option, 709 struct sockaddr *sap, size_t *addr_len)
710 * and construct a sockaddr based on the result.
711 *
712 * If address parsing fails, set the sockaddr's address
713 * family to AF_UNSPEC to force nfs_verify_server_address()
714 * to punt the mount.
715 */
716static void nfs_parse_server_address(char *value,
717 struct sockaddr *sap,
718 size_t *len)
719{ 710{
720 if (strchr(value, ':')) { 711 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
721 struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; 712 u8 *addr = (u8 *)&sin->sin_addr.s_addr;
722 u8 *addr = (u8 *)&ap->sin6_addr.in6_u;
723 713
724 ap->sin6_family = AF_INET6; 714 if (str_len <= INET_ADDRSTRLEN) {
725 *len = sizeof(*ap); 715 dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n",
726 if (in6_pton(value, -1, addr, '\0', NULL)) 716 (int)str_len, string);
717
718 sin->sin_family = AF_INET;
719 *addr_len = sizeof(*sin);
720 if (in4_pton(string, str_len, addr, '\0', NULL))
727 return; 721 return;
728 } else { 722 }
729 struct sockaddr_in *ap = (struct sockaddr_in *)sap; 723
730 u8 *addr = (u8 *)&ap->sin_addr.s_addr; 724 sap->sa_family = AF_UNSPEC;
725 *addr_len = 0;
726}
727
728#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
729static void nfs_parse_ipv6_address(char *string, size_t str_len,
730 struct sockaddr *sap, size_t *addr_len)
731{
732 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
733 u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
734
735 if (str_len <= INET6_ADDRSTRLEN) {
736 dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n",
737 (int)str_len, string);
731 738
732 ap->sin_family = AF_INET; 739 sin6->sin6_family = AF_INET6;
733 *len = sizeof(*ap); 740 *addr_len = sizeof(*sin6);
734 if (in4_pton(value, -1, addr, '\0', NULL)) 741 if (in6_pton(string, str_len, addr, '\0', NULL))
735 return; 742 return;
736 } 743 }
737 744
738 sap->sa_family = AF_UNSPEC; 745 sap->sa_family = AF_UNSPEC;
739 *len = 0; 746 *addr_len = 0;
747}
748#else
749static void nfs_parse_ipv6_address(char *string, size_t str_len,
750 struct sockaddr *sap, size_t *addr_len)
751{
752 sap->sa_family = AF_UNSPEC;
753 *addr_len = 0;
754}
755#endif
756
757/*
758 * Construct a sockaddr based on the contents of a string that contains
759 * an IP address in presentation format.
760 *
761 * If there is a problem constructing the new sockaddr, set the address
762 * family to AF_UNSPEC.
763 */
764static void nfs_parse_ip_address(char *string, size_t str_len,
765 struct sockaddr *sap, size_t *addr_len)
766{
767 unsigned int i, colons;
768
769 colons = 0;
770 for (i = 0; i < str_len; i++)
771 if (string[i] == ':')
772 colons++;
773
774 if (colons >= 2)
775 nfs_parse_ipv6_address(string, str_len, sap, addr_len);
776 else
777 nfs_parse_ipv4_address(string, str_len, sap, addr_len);
740} 778}
741 779
742/* 780/*
@@ -1070,9 +1108,10 @@ static int nfs_parse_mount_options(char *raw,
1070 string = match_strdup(args); 1108 string = match_strdup(args);
1071 if (string == NULL) 1109 if (string == NULL)
1072 goto out_nomem; 1110 goto out_nomem;
1073 nfs_parse_server_address(string, (struct sockaddr *) 1111 nfs_parse_ip_address(string, strlen(string),
1074 &mnt->nfs_server.address, 1112 (struct sockaddr *)
1075 &mnt->nfs_server.addrlen); 1113 &mnt->nfs_server.address,
1114 &mnt->nfs_server.addrlen);
1076 kfree(string); 1115 kfree(string);
1077 break; 1116 break;
1078 case Opt_clientaddr: 1117 case Opt_clientaddr:
@@ -1093,9 +1132,10 @@ static int nfs_parse_mount_options(char *raw,
1093 string = match_strdup(args); 1132 string = match_strdup(args);
1094 if (string == NULL) 1133 if (string == NULL)
1095 goto out_nomem; 1134 goto out_nomem;
1096 nfs_parse_server_address(string, (struct sockaddr *) 1135 nfs_parse_ip_address(string, strlen(string),
1097 &mnt->mount_server.address, 1136 (struct sockaddr *)
1098 &mnt->mount_server.addrlen); 1137 &mnt->mount_server.address,
1138 &mnt->mount_server.addrlen);
1099 kfree(string); 1139 kfree(string);
1100 break; 1140 break;
1101 1141
diff --git a/include/linux/inet.h b/include/linux/inet.h
index 1354080cf8cf..4cca05c9678e 100644
--- a/include/linux/inet.h
+++ b/include/linux/inet.h
@@ -44,6 +44,13 @@
44 44
45#include <linux/types.h> 45#include <linux/types.h>
46 46
47/*
48 * These mimic similar macros defined in user-space for inet_ntop(3).
49 * See /usr/include/netinet/in.h .
50 */
51#define INET_ADDRSTRLEN (16)
52#define INET6_ADDRSTRLEN (48)
53
47extern __be32 in_aton(const char *str); 54extern __be32 in_aton(const char *str);
48extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); 55extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end);
49extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); 56extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end);