aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/cifs/connect.c6
-rw-r--r--fs/cifs/dns_resolve.c4
-rw-r--r--fs/cifs/netmisc.c32
3 files changed, 33 insertions, 9 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c368ad658236..3fb799ff55c9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1386,8 +1386,10 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
1386 server->addr.sockAddr.sin_addr.s_addr)) 1386 server->addr.sockAddr.sin_addr.s_addr))
1387 continue; 1387 continue;
1388 else if (addr->ss_family == AF_INET6 && 1388 else if (addr->ss_family == AF_INET6 &&
1389 !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, 1389 (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
1390 &addr6->sin6_addr)) 1390 &addr6->sin6_addr) ||
1391 server->addr.sockAddr6.sin6_scope_id !=
1392 addr6->sin6_scope_id))
1391 continue; 1393 continue;
1392 1394
1393 ++server->srv_count; 1395 ++server->srv_count;
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 91b5500755bf..87948147d7ec 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -35,7 +35,7 @@
35 * 0 - name is not IP 35 * 0 - name is not IP
36 */ 36 */
37static int 37static int
38is_ip(const char *name) 38is_ip(char *name)
39{ 39{
40 struct sockaddr_storage ss; 40 struct sockaddr_storage ss;
41 41
@@ -57,7 +57,7 @@ dns_resolver_instantiate(struct key *key, const void *data,
57 ip[datalen] = '\0'; 57 ip[datalen] = '\0';
58 58
59 /* make sure this looks like an address */ 59 /* make sure this looks like an address */
60 if (!is_ip((const char *) ip)) { 60 if (!is_ip(ip)) {
61 kfree(ip); 61 kfree(ip);
62 return -EINVAL; 62 return -EINVAL;
63 } 63 }
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/*****************************************************************************