aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/netmisc.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2009-06-11 10:27:31 -0400
committerSteve French <sfrench@us.ibm.com>2009-06-24 21:14:36 -0400
commit681bf72e4893a187cf6b6b62c08fc193f81c8c2f (patch)
tree5c580474a21edf38140407bd42f28853e9354e25 /fs/cifs/netmisc.c
parent268875b9d1dd1bf0b523c59e736da9bc20c8ce1f (diff)
cifs: have cifs parse scope_id out of IPv6 addresses and use it
This patch has CIFS look for a '%' in an IPv6 address. If one is present then it will try to treat that value as a numeric interface index suitable for stuffing into the sin6_scope_id field. This should allow people to mount servers on IPv6 link-local addresses. Signed-off-by: Jeff Layton <jlayton@redhat.com> Acked-by: David Holder <david@erion.co.uk> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/netmisc.c')
-rw-r--r--fs/cifs/netmisc.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index f9a54da97d34..bd6d6895730d 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -158,25 +158,47 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
158/* 158/*
159 * Try to convert a string to an IPv4 address and then attempt to convert 159 * Try to convert a string to an IPv4 address and then attempt to convert
160 * it to an IPv6 address if that fails. Set the family field if either 160 * it to an IPv6 address if that fails. Set the family field if either
161 * succeeds. 161 * succeeds. If it's an IPv6 address and it has a '%' sign in it, try to
162 * treat the part following it as a numeric sin6_scope_id.
162 * 163 *
163 * Returns 0 on failure. 164 * Returns 0 on failure.
164 */ 165 */
165int 166int
166cifs_convert_address(char *src, void *dst) 167cifs_convert_address(char *src, void *dst)
167{ 168{
169 int rc;
170 char *pct, *endp;
168 struct sockaddr_in *s4 = (struct sockaddr_in *) dst; 171 struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
169 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; 172 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
170 173
174 /* IPv4 address */
171 if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) { 175 if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
172 s4->sin_family = AF_INET; 176 s4->sin_family = AF_INET;
173 return 1; 177 return 1;
174 } else if (cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr)) {
175 s6->sin6_family = AF_INET6;
176 return 1;
177 } 178 }
178 179
179 return 0; 180 /* temporarily terminate string */
181 pct = strchr(src, '%');
182 if (pct)
183 *pct = '\0';
184
185 rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
186
187 /* repair temp termination (if any) and make pct point to scopeid */
188 if (pct)
189 *pct++ = '%';
190
191 if (!rc)
192 return rc;
193
194 s6->sin6_family = AF_INET6;
195 if (pct) {
196 s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
197 if (!*pct || *endp)
198 return 0;
199 }
200
201 return rc;
180} 202}
181 203
182/***************************************************************************** 204/*****************************************************************************