if (server->ssocket) {
cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
server->ssocket->flags));
- server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
+ kernel_sock_shutdown(server->ssocket, SHUT_WR);
cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
server->ssocket->state,
server->ssocket->flags));
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
- } else if (length < 4) {
- cFYI(1, ("less than four bytes received (%d bytes)",
- length));
+ } else if (length < pdu_length) {
+ cFYI(1, ("requested %d bytes but only got %d bytes",
+ pdu_length, length));
pdu_length -= length;
msleep(1);
goto incomplete_rcv;
}
write_unlock(&GlobalSMBSeslock);
+ kfree(server->hostname);
kfree(server);
if (length > 0)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
return 0;
}
+/* extract the host portion of the UNC string */
+static char *
+extract_hostname(const char *unc)
+{
+ const char *src;
+ char *dst, *delim;
+ unsigned int len;
+
+ /* skip double chars at beginning of string */
+ /* BB: check validity of these bytes? */
+ src = unc + 2;
+
+ /* delimiter between hostname and sharename is always '\\' now */
+ delim = strchr(src, '\\');
+ if (!delim)
+ return ERR_PTR(-EINVAL);
+
+ len = delim - src;
+ dst = kmalloc((len + 1), GFP_KERNEL);
+ if (dst == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(dst, src, len);
+ dst[len] = '\0';
+
+ return dst;
+}
+
static int
cifs_parse_mount_options(char *options, const char *devname,
struct smb_vol *vol)
vol->linux_gid = current->gid;
vol->dir_mode = S_IRWXUGO;
/* 2767 perms indicate mandatory locking support */
- vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
+ vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
vol->rw = TRUE;
memset(&volume_info, 0, sizeof(struct smb_vol));
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
if (volume_info.nullauth) {
cFYI(1, ("null user"));
- volume_info.username = NULL;
+ volume_info.username = "";
} else if (volume_info.username) {
/* BB fixme parse for domain name here */
cFYI(1, ("Username: %s", volume_info.username));
cifserror("No username specified");
/* In userspace mount helper we can get user name from alternate
locations such as env variables and files on disk */
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
if (volume_info.UNCip && volume_info.UNC) {
if (rc <= 0) {
/* we failed translating address */
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
/* BB using ip addr as server name to connect to the
DFS root below */
cERROR(1, ("Connecting to DFS root not implemented yet"));
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
} else /* which servers DFS root would we conect to */ {
cERROR(1,
("CIFS mount error: No UNC path (e.g. -o "
"unc=//192.168.1.100/public) specified"));
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
/* this is needed for ASCII cp to Unicode converts */
if (cifs_sb->local_nls == NULL) {
cERROR(1, ("CIFS mount error: iocharset %s not found",
volume_info.iocharset));
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return -ELIBACC;
+ rc = -ELIBACC;
+ goto out;
}
}
&sin_server6.sin6_addr,
volume_info.username, &srvTcp);
} else {
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
if (srvTcp) {
"Aborting operation"));
if (csocket != NULL)
sock_release(csocket);
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return rc;
+ goto out;
}
srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
if (!srvTcp) {
rc = -ENOMEM;
sock_release(csocket);
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return rc;
+ goto out;
} else {
memcpy(&srvTcp->addr.sockAddr, &sin_server,
sizeof(struct sockaddr_in));
/* 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);
+ sock_release(csocket);
+ goto out;
+ }
init_waitqueue_head(&srvTcp->response_q);
init_waitqueue_head(&srvTcp->request_q);
INIT_LIST_HEAD(&srvTcp->pending_mid_q);
srvTcp->tcpStatus = CifsNew;
init_MUTEX(&srvTcp->tcpSem);
srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
- if ( IS_ERR(srvTcp->tsk) ) {
+ if (IS_ERR(srvTcp->tsk)) {
rc = PTR_ERR(srvTcp->tsk);
cERROR(1, ("error %d create cifsd thread", rc));
srvTcp->tsk = NULL;
sock_release(csocket);
- kfree(volume_info.UNC);
- kfree(volume_info.password);
- kfree(volume_info.prepath);
- FreeXid(xid);
- return rc;
+ kfree(srvTcp->hostname);
+ goto out;
}
wait_for_completion(&cifsd_complete);
rc = 0;
if (existingCifsSes) {
pSesInfo = existingCifsSes;
- cFYI(1, ("Existing smb sess found"));
- kfree(volume_info.password);
- /* volume_info.UNC freed at end of function */
+ cFYI(1, ("Existing smb sess found (status=%d)",
+ pSesInfo->status));
+ down(&pSesInfo->sesSem);
+ if (pSesInfo->status == CifsNeedReconnect) {
+ cFYI(1, ("Session needs reconnect"));
+ rc = cifs_setup_session(xid, pSesInfo,
+ cifs_sb->local_nls);
+ }
+ up(&pSesInfo->sesSem);
} else if (!rc) {
cFYI(1, ("Existing smb sess not found"));
pSesInfo = sesInfoAlloc();
if (!rc) {
/* volume_info.password freed at unmount */
- if (volume_info.password)
+ if (volume_info.password) {
pSesInfo->password = volume_info.password;
+ /* set to NULL to prevent freeing on exit */
+ volume_info.password = NULL;
+ }
if (volume_info.username)
strncpy(pSesInfo->userName,
volume_info.username,
up(&pSesInfo->sesSem);
if (!rc)
atomic_inc(&srvTcp->socketUseCount);
- } else
- kfree(volume_info.password);
+ }
}
/* search for existing tcon to this server share */
"", cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- kfree(volume_info.UNC);
- FreeXid(xid);
- return -ENODEV;
+ rc = -ENODEV;
+ goto out;
} else {
/* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as
(in which case it is not needed anymore) but when new sesion is created
the password ptr is put in the new session structure (in which case the
password will be freed at unmount time) */
+out:
+ /* zero out password before freeing */
+ if (volume_info.password != NULL) {
+ memset(volume_info.password, 0, strlen(volume_info.password));
+ kfree(volume_info.password);
+ }
kfree(volume_info.UNC);
kfree(volume_info.prepath);
FreeXid(xid);
pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
- &bytes_returned, 1);
+ &bytes_returned, CIFS_LONG_OP);
if (rc) {
/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
} else if ((smb_buffer_response->WordCount == 3)
pSMB->req.ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
- &bytes_returned, 1);
+ &bytes_returned, CIFS_LONG_OP);
if (smb_buffer_response->Status.CifsError ==
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
pSMB->req.ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
- &bytes_returned, 1);
+ &bytes_returned, CIFS_LONG_OP);
if (rc) {
/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
} else if ((smb_buffer_response->WordCount == 3) ||
pSMB->hdr.smb_buf_length += count;
pSMB->ByteCount = cpu_to_le16(count);
- rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
+ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
+ CIFS_STD_OP);
/* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
/* above now done in SendReceive */
sesInfoFree(ses);
FreeXid(xid);
- return rc; /* BB check if we should always return zero here */
+ return rc;
}
int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,