diff options
author | Pavel Shilovsky <piastryyy@gmail.com> | 2010-12-13 11:08:35 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2011-01-06 14:07:53 -0500 |
commit | a9f1b85e5ba80519dea6974e3574fa7a30cc5e29 (patch) | |
tree | 255a962ea1d02110c5b31ebb981ce1f588960688 /fs/cifs/connect.c | |
parent | df8fbc241aa3c451248b1f19fff3a3f604b107f9 (diff) |
CIFS: Simplify ipv*_connect functions into one (try #4)
Make connect logic more ip-protocol independent and move RFC1001 stuff into
a separate function. Also replace union addr in TCP_Server_Info structure
with sockaddr_storage.
Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
Reviewed-and-Tested-by: Jeff Layton <jlayton@samba.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 383 |
1 files changed, 159 insertions, 224 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index cc1a8604a790..b90c7411f4f0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -115,8 +115,8 @@ struct smb_vol { | |||
115 | #define TLINK_ERROR_EXPIRE (1 * HZ) | 115 | #define TLINK_ERROR_EXPIRE (1 * HZ) |
116 | #define TLINK_IDLE_EXPIRE (600 * HZ) | 116 | #define TLINK_IDLE_EXPIRE (600 * HZ) |
117 | 117 | ||
118 | static int ipv4_connect(struct TCP_Server_Info *server); | 118 | static int ip_connect(struct TCP_Server_Info *server); |
119 | static int ipv6_connect(struct TCP_Server_Info *server); | 119 | static int generic_ip_connect(struct TCP_Server_Info *server); |
120 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | 120 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
121 | static void cifs_prune_tlinks(struct work_struct *work); | 121 | static void cifs_prune_tlinks(struct work_struct *work); |
122 | 122 | ||
@@ -200,10 +200,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
200 | while ((server->tcpStatus != CifsExiting) && | 200 | while ((server->tcpStatus != CifsExiting) && |
201 | (server->tcpStatus != CifsGood)) { | 201 | (server->tcpStatus != CifsGood)) { |
202 | try_to_freeze(); | 202 | try_to_freeze(); |
203 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 203 | |
204 | rc = ipv6_connect(server); | 204 | /* we should try only the port we connected to before */ |
205 | else | 205 | rc = generic_ip_connect(server); |
206 | rc = ipv4_connect(server); | ||
207 | if (rc) { | 206 | if (rc) { |
208 | cFYI(1, "reconnect error %d", rc); | 207 | cFYI(1, "reconnect error %d", rc); |
209 | msleep(3000); | 208 | msleep(3000); |
@@ -477,7 +476,7 @@ incomplete_rcv: | |||
477 | * initialize frame) | 476 | * initialize frame) |
478 | */ | 477 | */ |
479 | cifs_set_port((struct sockaddr *) | 478 | cifs_set_port((struct sockaddr *) |
480 | &server->addr.sockAddr, CIFS_PORT); | 479 | &server->dstaddr, CIFS_PORT); |
481 | cifs_reconnect(server); | 480 | cifs_reconnect(server); |
482 | csocket = server->ssocket; | 481 | csocket = server->ssocket; |
483 | wake_up(&server->response_q); | 482 | wake_up(&server->response_q); |
@@ -1459,30 +1458,37 @@ static bool | |||
1459 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, | 1458 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, |
1460 | struct sockaddr *srcaddr) | 1459 | struct sockaddr *srcaddr) |
1461 | { | 1460 | { |
1462 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | ||
1463 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1464 | |||
1465 | switch (addr->sa_family) { | 1461 | switch (addr->sa_family) { |
1466 | case AF_INET: | 1462 | case AF_INET: { |
1467 | if (addr4->sin_addr.s_addr != | 1463 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; |
1468 | server->addr.sockAddr.sin_addr.s_addr) | 1464 | struct sockaddr_in *srv_addr4 = |
1465 | (struct sockaddr_in *)&server->dstaddr; | ||
1466 | |||
1467 | if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr) | ||
1469 | return false; | 1468 | return false; |
1470 | if (addr4->sin_port && | 1469 | if (addr4->sin_port && addr4->sin_port != srv_addr4->sin_port) |
1471 | addr4->sin_port != server->addr.sockAddr.sin_port) | ||
1472 | return false; | 1470 | return false; |
1473 | break; | 1471 | break; |
1474 | case AF_INET6: | 1472 | } |
1473 | case AF_INET6: { | ||
1474 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1475 | struct sockaddr_in6 *srv_addr6 = | ||
1476 | (struct sockaddr_in6 *)&server->dstaddr; | ||
1477 | |||
1475 | if (!ipv6_addr_equal(&addr6->sin6_addr, | 1478 | if (!ipv6_addr_equal(&addr6->sin6_addr, |
1476 | &server->addr.sockAddr6.sin6_addr)) | 1479 | &srv_addr6->sin6_addr)) |
1477 | return false; | 1480 | return false; |
1478 | if (addr6->sin6_scope_id != | 1481 | if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id) |
1479 | server->addr.sockAddr6.sin6_scope_id) | ||
1480 | return false; | 1482 | return false; |
1481 | if (addr6->sin6_port && | 1483 | if (addr6->sin6_port && |
1482 | addr6->sin6_port != server->addr.sockAddr6.sin6_port) | 1484 | addr6->sin6_port != srv_addr6->sin6_port) |
1483 | return false; | 1485 | return false; |
1484 | break; | 1486 | break; |
1485 | } | 1487 | } |
1488 | default: | ||
1489 | WARN_ON(1); | ||
1490 | return false; /* don't expect to be here */ | ||
1491 | } | ||
1486 | 1492 | ||
1487 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) | 1493 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) |
1488 | return false; | 1494 | return false; |
@@ -1681,14 +1687,13 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1681 | cFYI(1, "attempting ipv6 connect"); | 1687 | cFYI(1, "attempting ipv6 connect"); |
1682 | /* BB should we allow ipv6 on port 139? */ | 1688 | /* BB should we allow ipv6 on port 139? */ |
1683 | /* other OS never observed in Wild doing 139 with v6 */ | 1689 | /* other OS never observed in Wild doing 139 with v6 */ |
1684 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1690 | memcpy(&tcp_ses->dstaddr, sin_server6, |
1685 | sizeof(struct sockaddr_in6)); | 1691 | sizeof(struct sockaddr_in6)); |
1686 | rc = ipv6_connect(tcp_ses); | 1692 | } else |
1687 | } else { | 1693 | memcpy(&tcp_ses->dstaddr, sin_server, |
1688 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1694 | sizeof(struct sockaddr_in)); |
1689 | sizeof(struct sockaddr_in)); | 1695 | |
1690 | rc = ipv4_connect(tcp_ses); | 1696 | rc = ip_connect(tcp_ses); |
1691 | } | ||
1692 | if (rc < 0) { | 1697 | if (rc < 0) { |
1693 | cERROR(1, "Error connecting to socket. Aborting operation"); | 1698 | cERROR(1, "Error connecting to socket. Aborting operation"); |
1694 | goto out_err_crypto_release; | 1699 | goto out_err_crypto_release; |
@@ -1793,6 +1798,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1793 | { | 1798 | { |
1794 | int rc = -ENOMEM, xid; | 1799 | int rc = -ENOMEM, xid; |
1795 | struct cifsSesInfo *ses; | 1800 | struct cifsSesInfo *ses; |
1801 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; | ||
1802 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; | ||
1796 | 1803 | ||
1797 | xid = GetXid(); | 1804 | xid = GetXid(); |
1798 | 1805 | ||
@@ -1836,12 +1843,10 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1836 | 1843 | ||
1837 | /* new SMB session uses our server ref */ | 1844 | /* new SMB session uses our server ref */ |
1838 | ses->server = server; | 1845 | ses->server = server; |
1839 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 1846 | if (server->dstaddr.ss_family == AF_INET6) |
1840 | sprintf(ses->serverName, "%pI6", | 1847 | sprintf(ses->serverName, "%pI6", &addr6->sin6_addr); |
1841 | &server->addr.sockAddr6.sin6_addr); | ||
1842 | else | 1848 | else |
1843 | sprintf(ses->serverName, "%pI4", | 1849 | sprintf(ses->serverName, "%pI4", &addr->sin_addr); |
1844 | &server->addr.sockAddr.sin_addr.s_addr); | ||
1845 | 1850 | ||
1846 | if (volume_info->username) | 1851 | if (volume_info->username) |
1847 | strncpy(ses->userName, volume_info->username, | 1852 | strncpy(ses->userName, volume_info->username, |
@@ -2136,19 +2141,106 @@ bind_socket(struct TCP_Server_Info *server) | |||
2136 | } | 2141 | } |
2137 | 2142 | ||
2138 | static int | 2143 | static int |
2139 | ipv4_connect(struct TCP_Server_Info *server) | 2144 | ip_rfc1001_connect(struct TCP_Server_Info *server) |
2140 | { | 2145 | { |
2141 | int rc = 0; | 2146 | int rc = 0; |
2142 | int val; | 2147 | /* |
2143 | bool connected = false; | 2148 | * some servers require RFC1001 sessinit before sending |
2144 | __be16 orig_port = 0; | 2149 | * negprot - BB check reconnection in case where second |
2150 | * sessinit is sent but no second negprot | ||
2151 | */ | ||
2152 | struct rfc1002_session_packet *ses_init_buf; | ||
2153 | struct smb_hdr *smb_buf; | ||
2154 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2155 | GFP_KERNEL); | ||
2156 | if (ses_init_buf) { | ||
2157 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2158 | |||
2159 | if (server->server_RFC1001_name && | ||
2160 | server->server_RFC1001_name[0] != 0) | ||
2161 | rfc1002mangle(ses_init_buf->trailer. | ||
2162 | session_req.called_name, | ||
2163 | server->server_RFC1001_name, | ||
2164 | RFC1001_NAME_LEN_WITH_NULL); | ||
2165 | else | ||
2166 | rfc1002mangle(ses_init_buf->trailer. | ||
2167 | session_req.called_name, | ||
2168 | DEFAULT_CIFS_CALLED_NAME, | ||
2169 | RFC1001_NAME_LEN_WITH_NULL); | ||
2170 | |||
2171 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2172 | |||
2173 | /* | ||
2174 | * calling name ends in null (byte 16) from old smb | ||
2175 | * convention. | ||
2176 | */ | ||
2177 | if (server->workstation_RFC1001_name && | ||
2178 | server->workstation_RFC1001_name[0] != 0) | ||
2179 | rfc1002mangle(ses_init_buf->trailer. | ||
2180 | session_req.calling_name, | ||
2181 | server->workstation_RFC1001_name, | ||
2182 | RFC1001_NAME_LEN_WITH_NULL); | ||
2183 | else | ||
2184 | rfc1002mangle(ses_init_buf->trailer. | ||
2185 | session_req.calling_name, | ||
2186 | "LINUX_CIFS_CLNT", | ||
2187 | RFC1001_NAME_LEN_WITH_NULL); | ||
2188 | |||
2189 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2190 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2191 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2192 | |||
2193 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2194 | smb_buf->smb_buf_length = 0x81000044; | ||
2195 | rc = smb_send(server, smb_buf, 0x44); | ||
2196 | kfree(ses_init_buf); | ||
2197 | /* | ||
2198 | * RFC1001 layer in at least one server | ||
2199 | * requires very short break before negprot | ||
2200 | * presumably because not expecting negprot | ||
2201 | * to follow so fast. This is a simple | ||
2202 | * solution that works without | ||
2203 | * complicating the code and causes no | ||
2204 | * significant slowing down on mount | ||
2205 | * for everyone else | ||
2206 | */ | ||
2207 | usleep_range(1000, 2000); | ||
2208 | } | ||
2209 | /* | ||
2210 | * else the negprot may still work without this | ||
2211 | * even though malloc failed | ||
2212 | */ | ||
2213 | |||
2214 | return rc; | ||
2215 | } | ||
2216 | |||
2217 | static int | ||
2218 | generic_ip_connect(struct TCP_Server_Info *server) | ||
2219 | { | ||
2220 | int rc = 0; | ||
2221 | unsigned short int sport; | ||
2222 | int slen, sfamily; | ||
2145 | struct socket *socket = server->ssocket; | 2223 | struct socket *socket = server->ssocket; |
2224 | struct sockaddr *saddr; | ||
2225 | |||
2226 | saddr = (struct sockaddr *) &server->dstaddr; | ||
2227 | |||
2228 | if (server->dstaddr.ss_family == AF_INET6) { | ||
2229 | sport = ((struct sockaddr_in6 *) saddr)->sin6_port; | ||
2230 | slen = sizeof(struct sockaddr_in6); | ||
2231 | sfamily = AF_INET6; | ||
2232 | } else { | ||
2233 | sport = ((struct sockaddr_in *) saddr)->sin_port; | ||
2234 | slen = sizeof(struct sockaddr_in); | ||
2235 | sfamily = AF_INET; | ||
2236 | } | ||
2146 | 2237 | ||
2147 | if (socket == NULL) { | 2238 | if (socket == NULL) { |
2148 | rc = sock_create_kern(PF_INET, SOCK_STREAM, | 2239 | rc = sock_create_kern(sfamily, SOCK_STREAM, |
2149 | IPPROTO_TCP, &socket); | 2240 | IPPROTO_TCP, &socket); |
2150 | if (rc < 0) { | 2241 | if (rc < 0) { |
2151 | cERROR(1, "Error %d creating socket", rc); | 2242 | cERROR(1, "Error %d creating socket", rc); |
2243 | server->ssocket = NULL; | ||
2152 | return rc; | 2244 | return rc; |
2153 | } | 2245 | } |
2154 | 2246 | ||
@@ -2156,63 +2248,28 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2156 | cFYI(1, "Socket created"); | 2248 | cFYI(1, "Socket created"); |
2157 | server->ssocket = socket; | 2249 | server->ssocket = socket; |
2158 | socket->sk->sk_allocation = GFP_NOFS; | 2250 | socket->sk->sk_allocation = GFP_NOFS; |
2159 | cifs_reclassify_socket4(socket); | 2251 | if (sfamily == AF_INET6) |
2252 | cifs_reclassify_socket6(socket); | ||
2253 | else | ||
2254 | cifs_reclassify_socket4(socket); | ||
2160 | } | 2255 | } |
2161 | 2256 | ||
2162 | rc = bind_socket(server); | 2257 | rc = bind_socket(server); |
2163 | if (rc < 0) | 2258 | if (rc < 0) |
2164 | return rc; | 2259 | return rc; |
2165 | 2260 | ||
2166 | /* user overrode default port */ | 2261 | rc = socket->ops->connect(socket, saddr, slen, 0); |
2167 | if (server->addr.sockAddr.sin_port) { | 2262 | if (rc < 0) { |
2168 | rc = socket->ops->connect(socket, (struct sockaddr *) | 2263 | cFYI(1, "Error %d connecting to server", rc); |
2169 | &server->addr.sockAddr, | ||
2170 | sizeof(struct sockaddr_in), 0); | ||
2171 | if (rc >= 0) | ||
2172 | connected = true; | ||
2173 | } | ||
2174 | |||
2175 | if (!connected) { | ||
2176 | /* save original port so we can retry user specified port | ||
2177 | later if fall back ports fail this time */ | ||
2178 | orig_port = server->addr.sockAddr.sin_port; | ||
2179 | |||
2180 | /* do not retry on the same port we just failed on */ | ||
2181 | if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) { | ||
2182 | server->addr.sockAddr.sin_port = htons(CIFS_PORT); | ||
2183 | rc = socket->ops->connect(socket, | ||
2184 | (struct sockaddr *) | ||
2185 | &server->addr.sockAddr, | ||
2186 | sizeof(struct sockaddr_in), 0); | ||
2187 | if (rc >= 0) | ||
2188 | connected = true; | ||
2189 | } | ||
2190 | } | ||
2191 | if (!connected) { | ||
2192 | server->addr.sockAddr.sin_port = htons(RFC1001_PORT); | ||
2193 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2194 | &server->addr.sockAddr, | ||
2195 | sizeof(struct sockaddr_in), 0); | ||
2196 | if (rc >= 0) | ||
2197 | connected = true; | ||
2198 | } | ||
2199 | |||
2200 | /* give up here - unless we want to retry on different | ||
2201 | protocol families some day */ | ||
2202 | if (!connected) { | ||
2203 | if (orig_port) | ||
2204 | server->addr.sockAddr.sin_port = orig_port; | ||
2205 | cFYI(1, "Error %d connecting to server via ipv4", rc); | ||
2206 | sock_release(socket); | 2264 | sock_release(socket); |
2207 | server->ssocket = NULL; | 2265 | server->ssocket = NULL; |
2208 | return rc; | 2266 | return rc; |
2209 | } | 2267 | } |
2210 | 2268 | ||
2211 | |||
2212 | /* | 2269 | /* |
2213 | * Eventually check for other socket options to change from | 2270 | * Eventually check for other socket options to change from |
2214 | * the default. sock_setsockopt not used because it expects | 2271 | * the default. sock_setsockopt not used because it expects |
2215 | * user space buffer | 2272 | * user space buffer |
2216 | */ | 2273 | */ |
2217 | socket->sk->sk_rcvtimeo = 7 * HZ; | 2274 | socket->sk->sk_rcvtimeo = 7 * HZ; |
2218 | socket->sk->sk_sndtimeo = 5 * HZ; | 2275 | socket->sk->sk_sndtimeo = 5 * HZ; |
@@ -2226,7 +2283,7 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2226 | } | 2283 | } |
2227 | 2284 | ||
2228 | if (server->tcp_nodelay) { | 2285 | if (server->tcp_nodelay) { |
2229 | val = 1; | 2286 | int val = 1; |
2230 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | 2287 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, |
2231 | (char *)&val, sizeof(val)); | 2288 | (char *)&val, sizeof(val)); |
2232 | if (rc) | 2289 | if (rc) |
@@ -2237,161 +2294,39 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2237 | socket->sk->sk_sndbuf, | 2294 | socket->sk->sk_sndbuf, |
2238 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); | 2295 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); |
2239 | 2296 | ||
2240 | /* send RFC1001 sessinit */ | 2297 | if (sport == htons(RFC1001_PORT)) |
2241 | if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) { | 2298 | rc = ip_rfc1001_connect(server); |
2242 | /* some servers require RFC1001 sessinit before sending | ||
2243 | negprot - BB check reconnection in case where second | ||
2244 | sessinit is sent but no second negprot */ | ||
2245 | struct rfc1002_session_packet *ses_init_buf; | ||
2246 | struct smb_hdr *smb_buf; | ||
2247 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2248 | GFP_KERNEL); | ||
2249 | if (ses_init_buf) { | ||
2250 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2251 | if (server->server_RFC1001_name && | ||
2252 | server->server_RFC1001_name[0] != 0) | ||
2253 | rfc1002mangle(ses_init_buf->trailer. | ||
2254 | session_req.called_name, | ||
2255 | server->server_RFC1001_name, | ||
2256 | RFC1001_NAME_LEN_WITH_NULL); | ||
2257 | else | ||
2258 | rfc1002mangle(ses_init_buf->trailer. | ||
2259 | session_req.called_name, | ||
2260 | DEFAULT_CIFS_CALLED_NAME, | ||
2261 | RFC1001_NAME_LEN_WITH_NULL); | ||
2262 | |||
2263 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2264 | |||
2265 | /* calling name ends in null (byte 16) from old smb | ||
2266 | convention. */ | ||
2267 | if (server->workstation_RFC1001_name && | ||
2268 | server->workstation_RFC1001_name[0] != 0) | ||
2269 | rfc1002mangle(ses_init_buf->trailer. | ||
2270 | session_req.calling_name, | ||
2271 | server->workstation_RFC1001_name, | ||
2272 | RFC1001_NAME_LEN_WITH_NULL); | ||
2273 | else | ||
2274 | rfc1002mangle(ses_init_buf->trailer. | ||
2275 | session_req.calling_name, | ||
2276 | "LINUX_CIFS_CLNT", | ||
2277 | RFC1001_NAME_LEN_WITH_NULL); | ||
2278 | |||
2279 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2280 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2281 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2282 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2283 | smb_buf->smb_buf_length = 0x81000044; | ||
2284 | rc = smb_send(server, smb_buf, 0x44); | ||
2285 | kfree(ses_init_buf); | ||
2286 | msleep(1); /* RFC1001 layer in at least one server | ||
2287 | requires very short break before negprot | ||
2288 | presumably because not expecting negprot | ||
2289 | to follow so fast. This is a simple | ||
2290 | solution that works without | ||
2291 | complicating the code and causes no | ||
2292 | significant slowing down on mount | ||
2293 | for everyone else */ | ||
2294 | } | ||
2295 | /* else the negprot may still work without this | ||
2296 | even though malloc failed */ | ||
2297 | |||
2298 | } | ||
2299 | 2299 | ||
2300 | return rc; | 2300 | return rc; |
2301 | } | 2301 | } |
2302 | 2302 | ||
2303 | static int | 2303 | static int |
2304 | ipv6_connect(struct TCP_Server_Info *server) | 2304 | ip_connect(struct TCP_Server_Info *server) |
2305 | { | 2305 | { |
2306 | int rc = 0; | 2306 | unsigned short int *sport; |
2307 | int val; | 2307 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; |
2308 | bool connected = false; | 2308 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
2309 | __be16 orig_port = 0; | ||
2310 | struct socket *socket = server->ssocket; | ||
2311 | 2309 | ||
2312 | if (socket == NULL) { | 2310 | if (server->dstaddr.ss_family == AF_INET6) |
2313 | rc = sock_create_kern(PF_INET6, SOCK_STREAM, | 2311 | sport = &addr6->sin6_port; |
2314 | IPPROTO_TCP, &socket); | 2312 | else |
2315 | if (rc < 0) { | 2313 | sport = &addr->sin_port; |
2316 | cERROR(1, "Error %d creating ipv6 socket", rc); | ||
2317 | socket = NULL; | ||
2318 | return rc; | ||
2319 | } | ||
2320 | 2314 | ||
2321 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | 2315 | if (*sport == 0) { |
2322 | cFYI(1, "ipv6 Socket created"); | 2316 | int rc; |
2323 | server->ssocket = socket; | ||
2324 | socket->sk->sk_allocation = GFP_NOFS; | ||
2325 | cifs_reclassify_socket6(socket); | ||
2326 | } | ||
2327 | 2317 | ||
2328 | rc = bind_socket(server); | 2318 | /* try with 445 port at first */ |
2329 | if (rc < 0) | 2319 | *sport = htons(CIFS_PORT); |
2330 | return rc; | ||
2331 | 2320 | ||
2332 | /* user overrode default port */ | 2321 | rc = generic_ip_connect(server); |
2333 | if (server->addr.sockAddr6.sin6_port) { | ||
2334 | rc = socket->ops->connect(socket, | ||
2335 | (struct sockaddr *) &server->addr.sockAddr6, | ||
2336 | sizeof(struct sockaddr_in6), 0); | ||
2337 | if (rc >= 0) | ||
2338 | connected = true; | ||
2339 | } | ||
2340 | |||
2341 | if (!connected) { | ||
2342 | /* save original port so we can retry user specified port | ||
2343 | later if fall back ports fail this time */ | ||
2344 | |||
2345 | orig_port = server->addr.sockAddr6.sin6_port; | ||
2346 | /* do not retry on the same port we just failed on */ | ||
2347 | if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) { | ||
2348 | server->addr.sockAddr6.sin6_port = htons(CIFS_PORT); | ||
2349 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2350 | &server->addr.sockAddr6, | ||
2351 | sizeof(struct sockaddr_in6), 0); | ||
2352 | if (rc >= 0) | ||
2353 | connected = true; | ||
2354 | } | ||
2355 | } | ||
2356 | if (!connected) { | ||
2357 | server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT); | ||
2358 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2359 | &server->addr.sockAddr6, | ||
2360 | sizeof(struct sockaddr_in6), 0); | ||
2361 | if (rc >= 0) | 2322 | if (rc >= 0) |
2362 | connected = true; | 2323 | return rc; |
2363 | } | ||
2364 | |||
2365 | /* give up here - unless we want to retry on different | ||
2366 | protocol families some day */ | ||
2367 | if (!connected) { | ||
2368 | if (orig_port) | ||
2369 | server->addr.sockAddr6.sin6_port = orig_port; | ||
2370 | cFYI(1, "Error %d connecting to server via ipv6", rc); | ||
2371 | sock_release(socket); | ||
2372 | server->ssocket = NULL; | ||
2373 | return rc; | ||
2374 | } | ||
2375 | |||
2376 | /* | ||
2377 | * Eventually check for other socket options to change from | ||
2378 | * the default. sock_setsockopt not used because it expects | ||
2379 | * user space buffer | ||
2380 | */ | ||
2381 | socket->sk->sk_rcvtimeo = 7 * HZ; | ||
2382 | socket->sk->sk_sndtimeo = 5 * HZ; | ||
2383 | 2324 | ||
2384 | if (server->tcp_nodelay) { | 2325 | /* if it failed, try with 139 port */ |
2385 | val = 1; | 2326 | *sport = htons(RFC1001_PORT); |
2386 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | ||
2387 | (char *)&val, sizeof(val)); | ||
2388 | if (rc) | ||
2389 | cFYI(1, "set TCP_NODELAY socket option error %d", rc); | ||
2390 | } | 2327 | } |
2391 | 2328 | ||
2392 | server->ssocket = socket; | 2329 | return generic_ip_connect(server); |
2393 | |||
2394 | return rc; | ||
2395 | } | 2330 | } |
2396 | 2331 | ||
2397 | void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | 2332 | void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, |