aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c282
1 files changed, 150 insertions, 132 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 65c121940060..56095b24d5b9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1417,6 +1417,148 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
1417 force_sig(SIGKILL, task); 1417 force_sig(SIGKILL, task);
1418} 1418}
1419 1419
1420static struct TCP_Server_Info *
1421cifs_get_tcp_session(struct smb_vol *volume_info)
1422{
1423 struct TCP_Server_Info *tcp_ses = NULL;
1424 struct sockaddr addr;
1425 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1426 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1427 int rc;
1428
1429 memset(&addr, 0, sizeof(struct sockaddr));
1430
1431 if (volume_info->UNCip && volume_info->UNC) {
1432 rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
1433 &sin_server->sin_addr.s_addr);
1434
1435 if (rc <= 0) {
1436 /* not ipv4 address, try ipv6 */
1437 rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
1438 &sin_server6->sin6_addr.in6_u);
1439 if (rc > 0)
1440 addr.sa_family = AF_INET6;
1441 } else {
1442 addr.sa_family = AF_INET;
1443 }
1444
1445 if (rc <= 0) {
1446 /* we failed translating address */
1447 rc = -EINVAL;
1448 goto out_err;
1449 }
1450
1451 cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
1452 volume_info->UNCip));
1453 } else if (volume_info->UNCip) {
1454 /* BB using ip addr as tcp_ses name to connect to the
1455 DFS root below */
1456 cERROR(1, ("Connecting to DFS root not implemented yet"));
1457 rc = -EINVAL;
1458 goto out_err;
1459 } else /* which tcp_sess DFS root would we conect to */ {
1460 cERROR(1,
1461 ("CIFS mount error: No UNC path (e.g. -o "
1462 "unc=//192.168.1.100/public) specified"));
1463 rc = -EINVAL;
1464 goto out_err;
1465 }
1466
1467 /* see if we already have a matching tcp_ses */
1468 tcp_ses = cifs_find_tcp_session(&addr);
1469 if (tcp_ses)
1470 return tcp_ses;
1471
1472 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1473 if (!tcp_ses) {
1474 rc = -ENOMEM;
1475 goto out_err;
1476 }
1477
1478 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1479 if (IS_ERR(tcp_ses->hostname)) {
1480 rc = PTR_ERR(tcp_ses->hostname);
1481 goto out_err;
1482 }
1483
1484 tcp_ses->noblocksnd = volume_info->noblocksnd;
1485 tcp_ses->noautotune = volume_info->noautotune;
1486 atomic_set(&tcp_ses->inFlight, 0);
1487 init_waitqueue_head(&tcp_ses->response_q);
1488 init_waitqueue_head(&tcp_ses->request_q);
1489 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1490 mutex_init(&tcp_ses->srv_mutex);
1491 memcpy(tcp_ses->workstation_RFC1001_name,
1492 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1493 memcpy(tcp_ses->server_RFC1001_name,
1494 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1495 tcp_ses->sequence_number = 0;
1496 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1497 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1498
1499 /*
1500 * at this point we are the only ones with the pointer
1501 * to the struct since the kernel thread not created yet
1502 * no need to spinlock this init of tcpStatus or srv_count
1503 */
1504 tcp_ses->tcpStatus = CifsNew;
1505 ++tcp_ses->srv_count;
1506
1507 if (addr.sa_family == AF_INET6) {
1508 cFYI(1, ("attempting ipv6 connect"));
1509 /* BB should we allow ipv6 on port 139? */
1510 /* other OS never observed in Wild doing 139 with v6 */
1511 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1512 sizeof(struct sockaddr_in6));
1513 sin_server6->sin6_port = htons(volume_info->port);
1514 rc = ipv6_connect(sin_server6, &tcp_ses->ssocket,
1515 volume_info->noblocksnd);
1516 } else {
1517 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1518 sizeof(struct sockaddr_in));
1519 sin_server->sin_port = htons(volume_info->port);
1520 rc = ipv4_connect(sin_server, &tcp_ses->ssocket,
1521 volume_info->source_rfc1001_name,
1522 volume_info->target_rfc1001_name,
1523 volume_info->noblocksnd,
1524 volume_info->noautotune);
1525 }
1526 if (rc < 0) {
1527 cERROR(1, ("Error connecting to socket. Aborting operation"));
1528 goto out_err;
1529 }
1530
1531 /*
1532 * since we're in a cifs function already, we know that
1533 * this will succeed. No need for try_module_get().
1534 */
1535 __module_get(THIS_MODULE);
1536 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1537 tcp_ses, "cifsd");
1538 if (IS_ERR(tcp_ses->tsk)) {
1539 rc = PTR_ERR(tcp_ses->tsk);
1540 cERROR(1, ("error %d create cifsd thread", rc));
1541 module_put(THIS_MODULE);
1542 goto out_err;
1543 }
1544
1545 /* thread spawned, put it on the list */
1546 write_lock(&cifs_tcp_ses_lock);
1547 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1548 write_unlock(&cifs_tcp_ses_lock);
1549
1550 return tcp_ses;
1551
1552out_err:
1553 if (tcp_ses) {
1554 kfree(tcp_ses->hostname);
1555 if (tcp_ses->ssocket)
1556 sock_release(tcp_ses->ssocket);
1557 kfree(tcp_ses);
1558 }
1559 return ERR_PTR(rc);
1560}
1561
1420static struct cifsSesInfo * 1562static struct cifsSesInfo *
1421cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) 1563cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
1422{ 1564{
@@ -2043,10 +2185,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2043{ 2185{
2044 int rc = 0; 2186 int rc = 0;
2045 int xid; 2187 int xid;
2046 struct socket *csocket = NULL;
2047 struct sockaddr addr;
2048 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
2049 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
2050 struct smb_vol volume_info; 2188 struct smb_vol volume_info;
2051 struct cifsSesInfo *pSesInfo = NULL; 2189 struct cifsSesInfo *pSesInfo = NULL;
2052 struct cifsTconInfo *tcon = NULL; 2190 struct cifsTconInfo *tcon = NULL;
@@ -2056,7 +2194,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2056 2194
2057/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ 2195/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
2058 2196
2059 memset(&addr, 0, sizeof(struct sockaddr));
2060 memset(&volume_info, 0, sizeof(struct smb_vol)); 2197 memset(&volume_info, 0, sizeof(struct smb_vol));
2061 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { 2198 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
2062 rc = -EINVAL; 2199 rc = -EINVAL;
@@ -2077,42 +2214,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2077 goto out; 2214 goto out;
2078 } 2215 }
2079 2216
2080 if (volume_info.UNCip && volume_info.UNC) {
2081 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
2082 &sin_server->sin_addr.s_addr);
2083
2084 if (rc <= 0) {
2085 /* not ipv4 address, try ipv6 */
2086 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
2087 &sin_server6->sin6_addr.in6_u);
2088 if (rc > 0)
2089 addr.sa_family = AF_INET6;
2090 } else {
2091 addr.sa_family = AF_INET;
2092 }
2093
2094 if (rc <= 0) {
2095 /* we failed translating address */
2096 rc = -EINVAL;
2097 goto out;
2098 }
2099
2100 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
2101 /* success */
2102 rc = 0;
2103 } else if (volume_info.UNCip) {
2104 /* BB using ip addr as server name to connect to the
2105 DFS root below */
2106 cERROR(1, ("Connecting to DFS root not implemented yet"));
2107 rc = -EINVAL;
2108 goto out;
2109 } else /* which servers DFS root would we conect to */ {
2110 cERROR(1,
2111 ("CIFS mount error: No UNC path (e.g. -o "
2112 "unc=//192.168.1.100/public) specified"));
2113 rc = -EINVAL;
2114 goto out;
2115 }
2116 2217
2117 /* this is needed for ASCII cp to Unicode converts */ 2218 /* this is needed for ASCII cp to Unicode converts */
2118 if (volume_info.iocharset == NULL) { 2219 if (volume_info.iocharset == NULL) {
@@ -2128,94 +2229,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2128 } 2229 }
2129 } 2230 }
2130 2231
2131 srvTcp = cifs_find_tcp_session(&addr); 2232 /* get a reference to a tcp session */
2132 if (!srvTcp) { /* create socket */ 2233 srvTcp = cifs_get_tcp_session(&volume_info);
2133 if (addr.sa_family == AF_INET6) { 2234 if (IS_ERR(srvTcp)) {
2134 cFYI(1, ("attempting ipv6 connect")); 2235 rc = PTR_ERR(srvTcp);
2135 /* BB should we allow ipv6 on port 139? */ 2236 goto out;
2136 /* other OS never observed in Wild doing 139 with v6 */
2137 sin_server6->sin6_port = htons(volume_info.port);
2138 rc = ipv6_connect(sin_server6, &csocket,
2139 volume_info.noblocksnd);
2140 } else {
2141 sin_server->sin_port = htons(volume_info.port);
2142 rc = ipv4_connect(sin_server, &csocket,
2143 volume_info.source_rfc1001_name,
2144 volume_info.target_rfc1001_name,
2145 volume_info.noblocksnd,
2146 volume_info.noautotune);
2147 }
2148 if (rc < 0) {
2149 cERROR(1, ("Error connecting to socket. "
2150 "Aborting operation"));
2151 if (csocket != NULL)
2152 sock_release(csocket);
2153 goto out;
2154 }
2155
2156 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2157 if (!srvTcp) {
2158 rc = -ENOMEM;
2159 sock_release(csocket);
2160 goto out;
2161 } else {
2162 srvTcp->noblocksnd = volume_info.noblocksnd;
2163 srvTcp->noautotune = volume_info.noautotune;
2164 if (addr.sa_family == AF_INET6)
2165 memcpy(&srvTcp->addr.sockAddr6, sin_server6,
2166 sizeof(struct sockaddr_in6));
2167 else
2168 memcpy(&srvTcp->addr.sockAddr, sin_server,
2169 sizeof(struct sockaddr_in));
2170 atomic_set(&srvTcp->inFlight, 0);
2171 /* BB Add code for ipv6 case too */
2172 srvTcp->ssocket = csocket;
2173 srvTcp->hostname = extract_hostname(volume_info.UNC);
2174 if (IS_ERR(srvTcp->hostname)) {
2175 rc = PTR_ERR(srvTcp->hostname);
2176 sock_release(csocket);
2177 goto out;
2178 }
2179 init_waitqueue_head(&srvTcp->response_q);
2180 init_waitqueue_head(&srvTcp->request_q);
2181 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
2182 /* at this point we are the only ones with the pointer
2183 to the struct since the kernel thread not created yet
2184 so no need to spinlock this init of tcpStatus */
2185 srvTcp->tcpStatus = CifsNew;
2186 mutex_init(&srvTcp->srv_mutex);
2187
2188 /*
2189 * since we're in a cifs function already, we know that
2190 * this will succeed. No need for try_module_get().
2191 */
2192 __module_get(THIS_MODULE);
2193 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
2194 if (IS_ERR(srvTcp->tsk)) {
2195 rc = PTR_ERR(srvTcp->tsk);
2196 cERROR(1, ("error %d create cifsd thread", rc));
2197 module_put(THIS_MODULE);
2198 srvTcp->tsk = NULL;
2199 sock_release(csocket);
2200 kfree(srvTcp->hostname);
2201 goto out;
2202 }
2203 rc = 0;
2204 memcpy(srvTcp->workstation_RFC1001_name,
2205 volume_info.source_rfc1001_name,
2206 RFC1001_NAME_LEN_WITH_NULL);
2207 memcpy(srvTcp->server_RFC1001_name,
2208 volume_info.target_rfc1001_name,
2209 RFC1001_NAME_LEN_WITH_NULL);
2210 srvTcp->sequence_number = 0;
2211 INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
2212 INIT_LIST_HEAD(&srvTcp->smb_ses_list);
2213 ++srvTcp->srv_count;
2214 write_lock(&cifs_tcp_ses_lock);
2215 list_add(&srvTcp->tcp_ses_list,
2216 &cifs_tcp_ses_list);
2217 write_unlock(&cifs_tcp_ses_lock);
2218 }
2219 } 2237 }
2220 2238
2221 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); 2239 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
@@ -2245,12 +2263,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2245 2263
2246 /* new SMB session uses our srvTcp ref */ 2264 /* new SMB session uses our srvTcp ref */
2247 pSesInfo->server = srvTcp; 2265 pSesInfo->server = srvTcp;
2248 if (addr.sa_family == AF_INET6) 2266 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
2249 sprintf(pSesInfo->serverName, NIP6_FMT, 2267 sprintf(pSesInfo->serverName, NIP6_FMT,
2250 NIP6(sin_server6->sin6_addr)); 2268 NIP6(srvTcp->addr.sockAddr6.sin6_addr));
2251 else 2269 else
2252 sprintf(pSesInfo->serverName, NIPQUAD_FMT, 2270 sprintf(pSesInfo->serverName, NIPQUAD_FMT,
2253 NIPQUAD(sin_server->sin_addr.s_addr)); 2271 NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr));
2254 2272
2255 write_lock(&cifs_tcp_ses_lock); 2273 write_lock(&cifs_tcp_ses_lock);
2256 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); 2274 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);