diff options
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 75 |
1 files changed, 59 insertions, 16 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e9ea394ee075..da0f4ffa0613 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
26 | #include <linux/ipv6.h> | ||
27 | #include <linux/pagemap.h> | 26 | #include <linux/pagemap.h> |
28 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
29 | #include <linux/utsname.h> | 28 | #include <linux/utsname.h> |
@@ -35,6 +34,7 @@ | |||
35 | #include <linux/freezer.h> | 34 | #include <linux/freezer.h> |
36 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
37 | #include <asm/processor.h> | 36 | #include <asm/processor.h> |
37 | #include <net/ipv6.h> | ||
38 | #include "cifspdu.h" | 38 | #include "cifspdu.h" |
39 | #include "cifsglob.h" | 39 | #include "cifsglob.h" |
40 | #include "cifsproto.h" | 40 | #include "cifsproto.h" |
@@ -1354,7 +1354,7 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1354 | } | 1354 | } |
1355 | 1355 | ||
1356 | static struct TCP_Server_Info * | 1356 | static struct TCP_Server_Info * |
1357 | cifs_find_tcp_session(struct sockaddr *addr) | 1357 | cifs_find_tcp_session(struct sockaddr_storage *addr) |
1358 | { | 1358 | { |
1359 | struct list_head *tmp; | 1359 | struct list_head *tmp; |
1360 | struct TCP_Server_Info *server; | 1360 | struct TCP_Server_Info *server; |
@@ -1374,13 +1374,13 @@ cifs_find_tcp_session(struct sockaddr *addr) | |||
1374 | if (server->tcpStatus == CifsNew) | 1374 | if (server->tcpStatus == CifsNew) |
1375 | continue; | 1375 | continue; |
1376 | 1376 | ||
1377 | if (addr->sa_family == AF_INET && | 1377 | if (addr->ss_family == AF_INET && |
1378 | (addr4->sin_addr.s_addr != | 1378 | (addr4->sin_addr.s_addr != |
1379 | server->addr.sockAddr.sin_addr.s_addr)) | 1379 | server->addr.sockAddr.sin_addr.s_addr)) |
1380 | continue; | 1380 | continue; |
1381 | else if (addr->sa_family == AF_INET6 && | 1381 | else if (addr->ss_family == AF_INET6 && |
1382 | memcmp(&server->addr.sockAddr6.sin6_addr, | 1382 | !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, |
1383 | &addr6->sin6_addr, sizeof(addr6->sin6_addr))) | 1383 | &addr6->sin6_addr)) |
1384 | continue; | 1384 | continue; |
1385 | 1385 | ||
1386 | ++server->srv_count; | 1386 | ++server->srv_count; |
@@ -1419,12 +1419,12 @@ static struct TCP_Server_Info * | |||
1419 | cifs_get_tcp_session(struct smb_vol *volume_info) | 1419 | cifs_get_tcp_session(struct smb_vol *volume_info) |
1420 | { | 1420 | { |
1421 | struct TCP_Server_Info *tcp_ses = NULL; | 1421 | struct TCP_Server_Info *tcp_ses = NULL; |
1422 | struct sockaddr addr; | 1422 | struct sockaddr_storage addr; |
1423 | struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; | 1423 | struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; |
1424 | struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; | 1424 | struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; |
1425 | int rc; | 1425 | int rc; |
1426 | 1426 | ||
1427 | memset(&addr, 0, sizeof(struct sockaddr)); | 1427 | memset(&addr, 0, sizeof(struct sockaddr_storage)); |
1428 | 1428 | ||
1429 | if (volume_info->UNCip && volume_info->UNC) { | 1429 | if (volume_info->UNCip && volume_info->UNC) { |
1430 | rc = cifs_inet_pton(AF_INET, volume_info->UNCip, | 1430 | rc = cifs_inet_pton(AF_INET, volume_info->UNCip, |
@@ -1435,9 +1435,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1435 | rc = cifs_inet_pton(AF_INET6, volume_info->UNCip, | 1435 | rc = cifs_inet_pton(AF_INET6, volume_info->UNCip, |
1436 | &sin_server6->sin6_addr.in6_u); | 1436 | &sin_server6->sin6_addr.in6_u); |
1437 | if (rc > 0) | 1437 | if (rc > 0) |
1438 | addr.sa_family = AF_INET6; | 1438 | addr.ss_family = AF_INET6; |
1439 | } else { | 1439 | } else { |
1440 | addr.sa_family = AF_INET; | 1440 | addr.ss_family = AF_INET; |
1441 | } | 1441 | } |
1442 | 1442 | ||
1443 | if (rc <= 0) { | 1443 | if (rc <= 0) { |
@@ -1502,7 +1502,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1502 | tcp_ses->tcpStatus = CifsNew; | 1502 | tcp_ses->tcpStatus = CifsNew; |
1503 | ++tcp_ses->srv_count; | 1503 | ++tcp_ses->srv_count; |
1504 | 1504 | ||
1505 | if (addr.sa_family == AF_INET6) { | 1505 | if (addr.ss_family == AF_INET6) { |
1506 | cFYI(1, ("attempting ipv6 connect")); | 1506 | cFYI(1, ("attempting ipv6 connect")); |
1507 | /* BB should we allow ipv6 on port 139? */ | 1507 | /* BB should we allow ipv6 on port 139? */ |
1508 | /* other OS never observed in Wild doing 139 with v6 */ | 1508 | /* other OS never observed in Wild doing 139 with v6 */ |
@@ -1802,7 +1802,7 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
1802 | * user space buffer | 1802 | * user space buffer |
1803 | */ | 1803 | */ |
1804 | socket->sk->sk_rcvtimeo = 7 * HZ; | 1804 | socket->sk->sk_rcvtimeo = 7 * HZ; |
1805 | socket->sk->sk_sndtimeo = 3 * HZ; | 1805 | socket->sk->sk_sndtimeo = 5 * HZ; |
1806 | 1806 | ||
1807 | /* make the bufsizes depend on wsize/rsize and max requests */ | 1807 | /* make the bufsizes depend on wsize/rsize and max requests */ |
1808 | if (server->noautotune) { | 1808 | if (server->noautotune) { |
@@ -1860,9 +1860,7 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
1860 | smb_buf = (struct smb_hdr *)ses_init_buf; | 1860 | smb_buf = (struct smb_hdr *)ses_init_buf; |
1861 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | 1861 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ |
1862 | smb_buf->smb_buf_length = 0x81000044; | 1862 | smb_buf->smb_buf_length = 0x81000044; |
1863 | rc = smb_send(socket, smb_buf, 0x44, | 1863 | rc = smb_send(server, smb_buf, 0x44); |
1864 | (struct sockaddr *) &server->addr.sockAddr, | ||
1865 | server->noblocksnd); | ||
1866 | kfree(ses_init_buf); | 1864 | kfree(ses_init_buf); |
1867 | msleep(1); /* RFC1001 layer in at least one server | 1865 | msleep(1); /* RFC1001 layer in at least one server |
1868 | requires very short break before negprot | 1866 | requires very short break before negprot |
@@ -1955,7 +1953,7 @@ ipv6_connect(struct TCP_Server_Info *server) | |||
1955 | * user space buffer | 1953 | * user space buffer |
1956 | */ | 1954 | */ |
1957 | socket->sk->sk_rcvtimeo = 7 * HZ; | 1955 | socket->sk->sk_rcvtimeo = 7 * HZ; |
1958 | socket->sk->sk_sndtimeo = 3 * HZ; | 1956 | socket->sk->sk_sndtimeo = 5 * HZ; |
1959 | server->ssocket = socket; | 1957 | server->ssocket = socket; |
1960 | 1958 | ||
1961 | return rc; | 1959 | return rc; |
@@ -2182,6 +2180,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2182 | "mount option supported")); | 2180 | "mount option supported")); |
2183 | } | 2181 | } |
2184 | 2182 | ||
2183 | static int | ||
2184 | is_path_accessible(int xid, struct cifsTconInfo *tcon, | ||
2185 | struct cifs_sb_info *cifs_sb, const char *full_path) | ||
2186 | { | ||
2187 | int rc; | ||
2188 | __u64 inode_num; | ||
2189 | FILE_ALL_INFO *pfile_info; | ||
2190 | |||
2191 | rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num, | ||
2192 | cifs_sb->local_nls, | ||
2193 | cifs_sb->mnt_cifs_flags & | ||
2194 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
2195 | if (rc != -EOPNOTSUPP) | ||
2196 | return rc; | ||
2197 | |||
2198 | pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
2199 | if (pfile_info == NULL) | ||
2200 | return -ENOMEM; | ||
2201 | |||
2202 | rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info, | ||
2203 | 0 /* not legacy */, cifs_sb->local_nls, | ||
2204 | cifs_sb->mnt_cifs_flags & | ||
2205 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
2206 | kfree(pfile_info); | ||
2207 | return rc; | ||
2208 | } | ||
2209 | |||
2185 | int | 2210 | int |
2186 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 2211 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
2187 | char *mount_data, const char *devname) | 2212 | char *mount_data, const char *devname) |
@@ -2192,6 +2217,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2192 | struct cifsSesInfo *pSesInfo = NULL; | 2217 | struct cifsSesInfo *pSesInfo = NULL; |
2193 | struct cifsTconInfo *tcon = NULL; | 2218 | struct cifsTconInfo *tcon = NULL; |
2194 | struct TCP_Server_Info *srvTcp = NULL; | 2219 | struct TCP_Server_Info *srvTcp = NULL; |
2220 | char *full_path; | ||
2195 | 2221 | ||
2196 | xid = GetXid(); | 2222 | xid = GetXid(); |
2197 | 2223 | ||
@@ -2428,6 +2454,23 @@ mount_fail_check: | |||
2428 | cifs_sb->rsize = min(cifs_sb->rsize, | 2454 | cifs_sb->rsize = min(cifs_sb->rsize, |
2429 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | 2455 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
2430 | 2456 | ||
2457 | if (!rc && cifs_sb->prepathlen) { | ||
2458 | /* build_path_to_root works only when we have a valid tcon */ | ||
2459 | full_path = cifs_build_path_to_root(cifs_sb); | ||
2460 | if (full_path == NULL) { | ||
2461 | rc = -ENOMEM; | ||
2462 | goto mount_fail_check; | ||
2463 | } | ||
2464 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | ||
2465 | if (rc) { | ||
2466 | cERROR(1, ("Path %s in not accessible: %d", | ||
2467 | full_path, rc)); | ||
2468 | kfree(full_path); | ||
2469 | goto mount_fail_check; | ||
2470 | } | ||
2471 | kfree(full_path); | ||
2472 | } | ||
2473 | |||
2431 | /* volume_info->password is freed above when existing session found | 2474 | /* volume_info->password is freed above when existing session found |
2432 | (in which case it is not needed anymore) but when new sesion is created | 2475 | (in which case it is not needed anymore) but when new sesion is created |
2433 | the password ptr is put in the new session structure (in which case the | 2476 | the password ptr is put in the new session structure (in which case the |