| From sjayaraman@suse.de Wed Dec 3 09:30:05 2008 |
| From: Steve French <sfrench@us.ibm.com> |
| Date: Fri, 21 Nov 2008 14:23:07 +0530 |
| Subject: cifs: clean up server protocol handling |
| To: stable@kernel.org |
| Cc: Steve French <smfrench@gmail.com>, Jeff Layton <jlayton@redhat.com> |
| Message-ID: <492676F3.7080004@suse.de> |
| |
| From: Steve French <sfrench@us.ibm.com> |
| |
| commit 3ec332ef7a38c2327e18d087d4120a8e3bd3dc6e upstream. |
| |
| We're currently declaring both a sockaddr_in and sockaddr6_in on the |
| stack, but we really only need storage for one of them. Declare a |
| sockaddr struct and cast it to the proper type. Also, eliminate the |
| protocolType field in the TCP_Server_Info struct. It's redundant since |
| we have a sa_family field in the sockaddr anyway. |
| |
| We may need to revisit this if SCTP is ever implemented, but for now |
| this will simplify the code. |
| |
| CIFS over IPv6 also has a number of problems currently. This fixes all |
| of them that I found. Eventually, it would be nice to move more of the |
| code to be protocol independent, but this is a start. |
| |
| Signed-off-by: Jeff Layton <jlayton@redhat.com> |
| Signed-off-by: Steve French <sfrench@us.ibm.com> |
| Cc: Suresh Jayaraman <sjayaraman@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| |
| --- |
| fs/cifs/cifs_spnego.c | 3 +- |
| fs/cifs/cifsglob.h | 3 -- |
| fs/cifs/connect.c | 57 ++++++++++++++++++++++++++------------------------ |
| 3 files changed, 33 insertions(+), 30 deletions(-) |
| |
| --- a/fs/cifs/cifsglob.h |
| +++ b/fs/cifs/cifsglob.h |
| @@ -85,8 +85,7 @@ enum securityEnum { |
| }; |
| |
| enum protocolEnum { |
| - IPV4 = 0, |
| - IPV6, |
| + TCP = 0, |
| SCTP |
| /* Netbios frames protocol not supported at this time */ |
| }; |
| --- a/fs/cifs/cifs_spnego.c |
| +++ b/fs/cifs/cifs_spnego.c |
| @@ -70,7 +70,8 @@ struct key_type cifs_spnego_key_type = { |
| strlen("ver=0xFF") */ |
| #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg |
| in future could have strlen(";sec=ntlmsspi") */ |
| -#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ |
| +/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */ |
| +#define MAX_IPV6_ADDR_LEN 43 |
| /* get a key struct with a SPNEGO security blob, suitable for session setup */ |
| struct key * |
| cifs_get_spnego_key(struct cifsSesInfo *sesInfo) |
| --- a/fs/cifs/connect.c |
| +++ b/fs/cifs/connect.c |
| @@ -190,7 +190,7 @@ cifs_reconnect(struct TCP_Server_Info *s |
| |
| while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { |
| try_to_freeze(); |
| - if (server->protocolType == IPV6) { |
| + if (server->addr.sockAddr6.sin6_family == AF_INET6) { |
| rc = ipv6_connect(&server->addr.sockAddr6, |
| &server->ssocket, server->noautotune); |
| } else { |
| @@ -1960,10 +1960,10 @@ cifs_mount(struct super_block *sb, struc |
| { |
| int rc = 0; |
| int xid; |
| - int address_type = AF_INET; |
| struct socket *csocket = NULL; |
| - struct sockaddr_in sin_server; |
| - struct sockaddr_in6 sin_server6; |
| + struct sockaddr addr; |
| + struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; |
| + struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; |
| struct smb_vol volume_info; |
| struct cifsSesInfo *pSesInfo = NULL; |
| struct cifsSesInfo *existingCifsSes = NULL; |
| @@ -1974,6 +1974,7 @@ cifs_mount(struct super_block *sb, struc |
| |
| /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ |
| |
| + memset(&addr, 0, sizeof(struct sockaddr)); |
| memset(&volume_info, 0, sizeof(struct smb_vol)); |
| if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { |
| rc = -EINVAL; |
| @@ -1996,16 +1997,16 @@ cifs_mount(struct super_block *sb, struc |
| |
| if (volume_info.UNCip && volume_info.UNC) { |
| rc = cifs_inet_pton(AF_INET, volume_info.UNCip, |
| - &sin_server.sin_addr.s_addr); |
| + &sin_server->sin_addr.s_addr); |
| |
| if (rc <= 0) { |
| /* not ipv4 address, try ipv6 */ |
| rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, |
| - &sin_server6.sin6_addr.in6_u); |
| + &sin_server6->sin6_addr.in6_u); |
| if (rc > 0) |
| - address_type = AF_INET6; |
| + addr.sa_family = AF_INET6; |
| } else { |
| - address_type = AF_INET; |
| + addr.sa_family = AF_INET; |
| } |
| |
| if (rc <= 0) { |
| @@ -2045,39 +2046,38 @@ cifs_mount(struct super_block *sb, struc |
| } |
| } |
| |
| - if (address_type == AF_INET) |
| - existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, |
| + if (addr.sa_family == AF_INET) |
| + existingCifsSes = cifs_find_tcp_session(&sin_server->sin_addr, |
| NULL /* no ipv6 addr */, |
| volume_info.username, &srvTcp); |
| - else if (address_type == AF_INET6) { |
| + else if (addr.sa_family == AF_INET6) { |
| cFYI(1, ("looking for ipv6 address")); |
| existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, |
| - &sin_server6.sin6_addr, |
| + &sin_server6->sin6_addr, |
| volume_info.username, &srvTcp); |
| } else { |
| rc = -EINVAL; |
| goto out; |
| } |
| |
| - if (!srvTcp) { /* create socket */ |
| - if (volume_info.port) |
| - sin_server.sin_port = htons(volume_info.port); |
| - else |
| - sin_server.sin_port = 0; |
| - if (address_type == AF_INET6) { |
| + if (!srvTcp) { |
| + if (addr.sa_family == AF_INET6) { |
| cFYI(1, ("attempting ipv6 connect")); |
| /* BB should we allow ipv6 on port 139? */ |
| /* other OS never observed in Wild doing 139 with v6 */ |
| - rc = ipv6_connect(&sin_server6, &csocket, |
| + sin_server6->sin6_port = htons(volume_info.port); |
| + rc = ipv6_connect(sin_server6, &csocket, |
| volume_info.noblocksnd); |
| - } else |
| - rc = ipv4_connect(&sin_server, &csocket, |
| + } else { |
| + sin_server->sin_port = htons(volume_info.port); |
| + rc = ipv4_connect(sin_server, &csocket, |
| volume_info.source_rfc1001_name, |
| volume_info.target_rfc1001_name, |
| volume_info.noblocksnd, |
| volume_info.noautotune); |
| + } |
| if (rc < 0) { |
| - cERROR(1, ("Error connecting to IPv4 socket. " |
| + cERROR(1, ("Error connecting to socket. " |
| "Aborting operation")); |
| if (csocket != NULL) |
| sock_release(csocket); |
| @@ -2092,12 +2092,15 @@ cifs_mount(struct super_block *sb, struc |
| } else { |
| srvTcp->noblocksnd = volume_info.noblocksnd; |
| srvTcp->noautotune = volume_info.noautotune; |
| - memcpy(&srvTcp->addr.sockAddr, &sin_server, |
| - sizeof(struct sockaddr_in)); |
| + if (addr.sa_family == AF_INET6) |
| + memcpy(&srvTcp->addr.sockAddr6, sin_server6, |
| + sizeof(struct sockaddr_in6)); |
| + else |
| + memcpy(&srvTcp->addr.sockAddr, sin_server, |
| + sizeof(struct sockaddr_in)); |
| atomic_set(&srvTcp->inFlight, 0); |
| /* BB Add code for ipv6 case too */ |
| srvTcp->ssocket = csocket; |
| - srvTcp->protocolType = IPV4; |
| srvTcp->hostname = extract_hostname(volume_info.UNC); |
| if (IS_ERR(srvTcp->hostname)) { |
| rc = PTR_ERR(srvTcp->hostname); |
| @@ -2149,7 +2152,7 @@ cifs_mount(struct super_block *sb, struc |
| else { |
| pSesInfo->server = srvTcp; |
| sprintf(pSesInfo->serverName, "%u.%u.%u.%u", |
| - NIPQUAD(sin_server.sin_addr.s_addr)); |
| + NIPQUAD(sin_server->sin_addr.s_addr)); |
| } |
| |
| if (!rc) { |
| @@ -2187,7 +2190,7 @@ cifs_mount(struct super_block *sb, struc |
| if (!rc) { |
| setup_cifs_sb(&volume_info, cifs_sb); |
| tcon = |
| - find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, |
| + find_unc(sin_server->sin_addr.s_addr, volume_info.UNC, |
| volume_info.username); |
| if (tcon) { |
| cFYI(1, ("Found match on UNC path")); |