diff options
-rw-r--r-- | fs/nfs/super.c | 100 | ||||
-rw-r--r-- | include/linux/inet.h | 7 |
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 | /* | 708 | static 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 | */ | ||
716 | static 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) | ||
729 | static 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 | ||
749 | static 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 | */ | ||
764 | static 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 | |||
47 | extern __be32 in_aton(const char *str); | 54 | extern __be32 in_aton(const char *str); |
48 | extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); | 55 | extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); |
49 | extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); | 56 | extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); |