summaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c295
1 files changed, 146 insertions, 149 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e17106730168..e8fa46c7cff2 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -49,8 +49,6 @@
#define CIFS_PORT 445
#define RFC1001_PORT 139
-static DECLARE_COMPLETION(cifsd_complete);
-
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
@@ -62,7 +60,7 @@ struct smb_vol {
char *domainname;
char *UNC;
char *UNCip;
- char *in6_addr; /* ipv6 address as human readable form of in6_addr */
+ char *in6_addr; /* ipv6 address as human readable form of in6_addr */
char *iocharset; /* local code page for mapping to and from Unicode */
char source_rfc1001_name[16]; /* netbios name of client */
char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
@@ -71,25 +69,27 @@ struct smb_vol {
mode_t file_mode;
mode_t dir_mode;
unsigned secFlg;
- unsigned rw:1;
- unsigned retry:1;
- unsigned intr:1;
- unsigned setuids:1;
- unsigned override_uid:1;
- unsigned override_gid:1;
- unsigned noperm:1;
- unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
- unsigned cifs_acl:1;
- unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
- unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
- unsigned direct_io:1;
- unsigned remap:1; /* set to remap seven reserved chars in filenames */
- unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
- unsigned no_linux_ext:1;
- unsigned sfu_emul:1;
- unsigned nullauth:1; /* attempt to authenticate with null user */
- unsigned nocase; /* request case insensitive filenames */
- unsigned nobrl; /* disable sending byte range locks to srv */
+ bool rw:1;
+ bool retry:1;
+ bool intr:1;
+ bool setuids:1;
+ bool override_uid:1;
+ bool override_gid:1;
+ bool dynperm:1;
+ bool noperm:1;
+ bool no_psx_acl:1; /* set if posix acl support should be disabled */
+ bool cifs_acl:1;
+ bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
+ bool server_ino:1; /* use inode numbers from server ie UniqueId */
+ bool direct_io:1;
+ bool remap:1; /* set to remap seven reserved chars in filenames */
+ bool posix_paths:1; /* unset to not ask for posix pathnames. */
+ bool no_linux_ext:1;
+ bool sfu_emul:1;
+ bool nullauth:1; /* attempt to authenticate with null user */
+ bool nocase:1; /* request case insensitive filenames */
+ bool nobrl:1; /* disable sending byte range locks to srv */
+ bool seal:1; /* request transport encryption on share */
unsigned int rsize;
unsigned int wsize;
unsigned int sockopt;
@@ -345,18 +345,16 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
char temp;
- int isLargeBuf = FALSE;
- int isMultiRsp;
+ bool isLargeBuf = false;
+ bool isMultiRsp;
int reconnect;
current->flags |= PF_MEMALLOC;
- server->tsk = current; /* save process info to wake at shutdown */
cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
write_lock(&GlobalSMBSeslock);
atomic_inc(&tcpSesAllocCount);
length = tcpSesAllocCount.counter;
write_unlock(&GlobalSMBSeslock);
- complete(&cifsd_complete);
if (length > 1)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL);
@@ -390,8 +388,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} else /* if existing small buf clear beginning */
memset(smallbuf, 0, sizeof(struct smb_hdr));
- isLargeBuf = FALSE;
- isMultiRsp = FALSE;
+ isLargeBuf = false;
+ isMultiRsp = false;
smb_buffer = smallbuf;
iov.iov_base = smb_buffer;
iov.iov_len = 4;
@@ -517,7 +515,7 @@ incomplete_rcv:
reconnect = 0;
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
- isLargeBuf = TRUE;
+ isLargeBuf = true;
memcpy(bigbuf, smallbuf, 4);
smb_buffer = bigbuf;
}
@@ -582,16 +580,18 @@ incomplete_rcv:
(mid_entry->command == smb_buffer->Command)) {
if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
/* We have a multipart transact2 resp */
- isMultiRsp = TRUE;
+ isMultiRsp = true;
if (mid_entry->resp_buf) {
/* merge response - fix up 1st*/
if (coalesce_t2(smb_buffer,
mid_entry->resp_buf)) {
- mid_entry->multiRsp = 1;
+ mid_entry->multiRsp =
+ true;
break;
} else {
/* all parts received */
- mid_entry->multiEnd = 1;
+ mid_entry->multiEnd =
+ true;
goto multi_t2_fnd;
}
} else {
@@ -603,17 +603,15 @@ incomplete_rcv:
/* Have first buffer */
mid_entry->resp_buf =
smb_buffer;
- mid_entry->largeBuf = 1;
+ mid_entry->largeBuf =
+ true;
bigbuf = NULL;
}
}
break;
}
mid_entry->resp_buf = smb_buffer;
- if (isLargeBuf)
- mid_entry->largeBuf = 1;
- else
- mid_entry->largeBuf = 0;
+ mid_entry->largeBuf = isLargeBuf;
multi_t2_fnd:
task_to_wake = mid_entry->tsk;
mid_entry->midState = MID_RESPONSE_RECEIVED;
@@ -638,8 +636,8 @@ multi_t2_fnd:
smallbuf = NULL;
}
wake_up_process(task_to_wake);
- } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
- && (isMultiRsp == FALSE)) {
+ } else if (!is_valid_oplock_break(smb_buffer, server) &&
+ !isMultiRsp) {
cERROR(1, ("No task to wake, unknown frame received! "
"NumMids %d", midCount.counter));
cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
@@ -654,10 +652,21 @@ multi_t2_fnd:
spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting;
- server->tsk = NULL;
+ spin_unlock(&GlobalMid_Lock);
+ wake_up_all(&server->response_q);
+
+ /* don't exit until kthread_stop is called */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ while (!kthread_should_stop()) {
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+
/* check if we have blocked requests that need to free */
/* Note that cifs_max_pending is normally 50, but
can be set at module install time to as little as two */
+ spin_lock(&GlobalMid_Lock);
if (atomic_read(&server->inFlight) >= cifs_max_pending)
atomic_set(&server->inFlight, cifs_max_pending - 1);
/* We do not want to set the max_pending too low or we
@@ -825,7 +834,7 @@ cifs_parse_mount_options(char *options, const char *devname,
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;
+ vol->rw = true;
/* default is always to request posix paths. */
vol->posix_paths = 1;
@@ -1181,7 +1190,7 @@ cifs_parse_mount_options(char *options, const char *devname,
} else if (strnicmp(data, "guest", 5) == 0) {
/* ignore */
} else if (strnicmp(data, "rw", 2) == 0) {
- vol->rw = TRUE;
+ vol->rw = true;
} else if ((strnicmp(data, "suid", 4) == 0) ||
(strnicmp(data, "nosuid", 6) == 0) ||
(strnicmp(data, "exec", 4) == 0) ||
@@ -1197,7 +1206,7 @@ cifs_parse_mount_options(char *options, const char *devname,
is ok to just ignore them */
continue;
} else if (strnicmp(data, "ro", 2) == 0) {
- vol->rw = FALSE;
+ vol->rw = false;
} else if (strnicmp(data, "hard", 4) == 0) {
vol->retry = 1;
} else if (strnicmp(data, "soft", 4) == 0) {
@@ -1240,6 +1249,10 @@ cifs_parse_mount_options(char *options, const char *devname,
vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) {
vol->setuids = 0;
+ } else if (strnicmp(data, "dynperm", 7) == 0) {
+ vol->dynperm = true;
+ } else if (strnicmp(data, "nodynperm", 9) == 0) {
+ vol->dynperm = false;
} else if (strnicmp(data, "nohard", 6) == 0) {
vol->retry = 0;
} else if (strnicmp(data, "nosoft", 6) == 0) {
@@ -1262,8 +1275,12 @@ cifs_parse_mount_options(char *options, const char *devname,
vol->no_psx_acl = 1;
} else if (strnicmp(data, "sign", 4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SIGN;
-/* } else if (strnicmp(data, "seal",4) == 0) {
- vol->secFlg |= CIFSSEC_MUST_SEAL; */
+ } else if (strnicmp(data, "seal", 4) == 0) {
+ /* we do not do the following in secFlags because seal
+ is a per tree connection (mount) not a per socket
+ or per-smb connection option in the protocol */
+ /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
+ vol->seal = 1;
} else if (strnicmp(data, "direct", 6) == 0) {
vol->direct_io = 1;
} else if (strnicmp(data, "forcedirectio", 13) == 0) {
@@ -1305,6 +1322,9 @@ cifs_parse_mount_options(char *options, const char *devname,
"begin with // or \\\\ \n");
return 1;
}
+ value = strpbrk(vol->UNC+2, "/\\");
+ if (value)
+ *value = '\\';
} else {
printk(KERN_WARNING "CIFS: UNC name too long\n");
return 1;
@@ -1318,42 +1338,43 @@ cifs_parse_mount_options(char *options, const char *devname,
static struct cifsSesInfo *
cifs_find_tcp_session(struct in_addr *target_ip_addr,
- struct in6_addr *target_ip6_addr,
- char *userName, struct TCP_Server_Info **psrvTcp)
+ struct in6_addr *target_ip6_addr,
+ char *userName, struct TCP_Server_Info **psrvTcp)
{
struct list_head *tmp;
struct cifsSesInfo *ses;
+
*psrvTcp = NULL;
- read_lock(&GlobalSMBSeslock);
+ read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
- if (ses->server) {
- if ((target_ip_addr &&
- (ses->server->addr.sockAddr.sin_addr.s_addr
- == target_ip_addr->s_addr)) || (target_ip6_addr
- && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
- target_ip6_addr, sizeof(*target_ip6_addr)))) {
- /* BB lock server and tcp session and increment
- use count here?? */
-
- /* found a match on the TCP session */
- *psrvTcp = ses->server;
-
- /* BB check if reconnection needed */
- if (strncmp
- (ses->userName, userName,
- MAX_USERNAME_SIZE) == 0){
- read_unlock(&GlobalSMBSeslock);
- /* Found exact match on both TCP and
- SMB sessions */
- return ses;
- }
- }
+ if (!ses->server)
+ continue;
+
+ if (target_ip_addr &&
+ ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
+ continue;
+ else if (target_ip6_addr &&
+ memcmp(&ses->server->addr.sockAddr6.sin6_addr,
+ target_ip6_addr, sizeof(*target_ip6_addr)))
+ continue;
+ /* BB lock server and tcp session; increment use count here?? */
+
+ /* found a match on the TCP session */
+ *psrvTcp = ses->server;
+
+ /* BB check if reconnection needed */
+ if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
+ read_unlock(&GlobalSMBSeslock);
+ /* Found exact match on both TCP and
+ SMB sessions */
+ return ses;
}
/* else tcp and smb sessions need reconnection */
}
read_unlock(&GlobalSMBSeslock);
+
return NULL;
}
@@ -1362,68 +1383,45 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
{
struct list_head *tmp;
struct cifsTconInfo *tcon;
+ __be32 old_ip;
read_lock(&GlobalSMBSeslock);
+
list_for_each(tmp, &GlobalTreeConnectionList) {
cFYI(1, ("Next tcon"));
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
- if (tcon->ses) {
- if (tcon->ses->server) {
- cFYI(1,
- ("old ip addr: %x == new ip %x ?",
- tcon->ses->server->addr.sockAddr.sin_addr.
- s_addr, new_target_ip_addr));
- if (tcon->ses->server->addr.sockAddr.sin_addr.
- s_addr == new_target_ip_addr) {
- /* BB lock tcon, server and tcp session and increment use count here? */
- /* found a match on the TCP session */
- /* BB check if reconnection needed */
- cFYI(1,
- ("IP match, old UNC: %s new: %s",
- tcon->treeName, uncName));
- if (strncmp
- (tcon->treeName, uncName,
- MAX_TREE_SIZE) == 0) {
- cFYI(1,
- ("and old usr: %s new: %s",
- tcon->treeName, uncName));
- if (strncmp
- (tcon->ses->userName,
- userName,
- MAX_USERNAME_SIZE) == 0) {
- read_unlock(&GlobalSMBSeslock);
- /* matched smb session
- (user name */
- return tcon;
- }
- }
- }
- }
- }
- }
- read_unlock(&GlobalSMBSeslock);
- return NULL;
-}
+ if (!tcon->ses || !tcon->ses->server)
+ continue;
-int
-connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- const char *old_path, const struct nls_table *nls_codepage,
- int remap)
-{
- struct dfs_info3_param *referrals = NULL;
- unsigned int num_referrals;
- int rc = 0;
+ old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
+ cFYI(1, ("old ip addr: %x == new ip %x ?",
+ old_ip, new_target_ip_addr));
- rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
- &num_referrals, &referrals, remap);
+ if (old_ip != new_target_ip_addr)
+ continue;
- /* BB Add in code to: if valid refrl, if not ip address contact
- the helper that resolves tcp names, mount to it, try to
- tcon to it unmount it if fail */
+ /* BB lock tcon, server, tcp session and increment use count? */
+ /* found a match on the TCP session */
+ /* BB check if reconnection needed */
+ cFYI(1, ("IP match, old UNC: %s new: %s",
+ tcon->treeName, uncName));
- kfree(referrals);
+ if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
+ continue;
- return rc;
+ cFYI(1, ("and old usr: %s new: %s",
+ tcon->treeName, uncName));
+
+ if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
+ continue;
+
+ /* matched smb session (user name) */
+ read_unlock(&GlobalSMBSeslock);
+ return tcon;
+ }
+
+ read_unlock(&GlobalSMBSeslock);
+ return NULL;
}
int
@@ -1433,7 +1431,6 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
{
char *temp_unc;
int rc = 0;
- unsigned char *targetUNCs;
*pnum_referrals = 0;
*preferrals = NULL;
@@ -1456,7 +1453,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
kfree(temp_unc);
}
if (rc == 0)
- rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
+ rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
pnum_referrals, nls_codepage, remap);
/* BB map targetUNCs to dfs_info3 structures, here or
in CIFSGetDFSRefer BB */
@@ -1807,7 +1804,7 @@ convert_delimiter(char *path, char delim)
if (path == NULL)
return;
- if (delim == '/')
+ if (delim == '/')
old_delim = '\\';
else
old_delim = '/';
@@ -1982,7 +1979,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
kfree(srvTcp->hostname);
goto out;
}
- wait_for_completion(&cifsd_complete);
rc = 0;
memcpy(srvTcp->workstation_RFC1001_name,
volume_info.source_rfc1001_name, 16);
@@ -2118,11 +2114,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
if (volume_info.override_gid)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+ if (volume_info.dynperm)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
if (volume_info.direct_io) {
cFYI(1, ("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
}
+ if ((volume_info.cifs_acl) && (volume_info.dynperm))
+ cERROR(1, ("mount option dynperm ignored if cifsacl "
+ "mount option supported"));
+
tcon =
find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
volume_info.username);
@@ -2134,6 +2136,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
for the retry flag is used */
tcon->retry = volume_info.retry;
tcon->nocase = volume_info.nocase;
+ if (tcon->seal != volume_info.seal)
+ cERROR(1, ("transport encryption setting "
+ "conflicts with existing tid"));
} else {
tcon = tconInfoAlloc();
if (tcon == NULL)
@@ -2147,10 +2152,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') ==
NULL)) {
- rc = connect_to_dfs_path(xid, pSesInfo,
+/* rc = connect_to_dfs_path(xid, pSesInfo,
"", cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ CIFS_MOUNT_MAP_SPECIAL_CHR);*/
+ cFYI(1, ("DFS root not supported"));
rc = -ENODEV;
goto out;
} else {
@@ -2166,6 +2172,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
atomic_inc(&pSesInfo->inUse);
tcon->retry = volume_info.retry;
tcon->nocase = volume_info.nocase;
+ tcon->seal = volume_info.seal;
}
}
}
@@ -2189,15 +2196,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
srvTcp->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
if (srvTcp->tsk) {
- struct task_struct *tsk;
/* If we could verify that kthread_stop would
always wake up processes blocked in
tcp in recv_mesg then we could remove the
send_sig call */
force_sig(SIGKILL, srvTcp->tsk);
- tsk = srvTcp->tsk;
- if (tsk)
- kthread_stop(tsk);
+ kthread_stop(srvTcp->tsk);
}
}
/* If find_unc succeeded then rc == 0 so we can not end */
@@ -2213,23 +2217,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((temp_rc == -ESHUTDOWN) &&
(pSesInfo->server) &&
(pSesInfo->server->tsk)) {
- struct task_struct *tsk;
force_sig(SIGKILL,
pSesInfo->server->tsk);
- tsk = pSesInfo->server->tsk;
- if (tsk)
- kthread_stop(tsk);
+ kthread_stop(pSesInfo->server->tsk);
}
} else {
cFYI(1, ("No session or bad tcon"));
if ((pSesInfo->server) &&
(pSesInfo->server->tsk)) {
- struct task_struct *tsk;
force_sig(SIGKILL,
pSesInfo->server->tsk);
- tsk = pSesInfo->server->tsk;
- if (tsk)
- kthread_stop(tsk);
+ kthread_stop(pSesInfo->server->tsk);
}
}
sesInfoFree(pSesInfo);
@@ -2316,9 +2314,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
user = ses->userName;
domain = ses->domainName;
smb_buffer = cifs_buf_get();
- if (smb_buffer == NULL) {
+
+ if (smb_buffer == NULL)
return -ENOMEM;
- }
+
smb_buffer_response = smb_buffer;
pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
@@ -2602,7 +2601,7 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings,
static int
CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
- struct cifsSesInfo *ses, int *pNTLMv2_flag,
+ struct cifsSesInfo *ses, bool *pNTLMv2_flag,
const struct nls_table *nls_codepage)
{
struct smb_hdr *smb_buffer;
@@ -2625,7 +2624,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
if (ses == NULL)
return -EINVAL;
domain = ses->domainName;
- *pNTLMv2_flag = FALSE;
+ *pNTLMv2_flag = false;
smb_buffer = cifs_buf_get();
if (smb_buffer == NULL) {
return -ENOMEM;
@@ -2778,7 +2777,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
CIFS_CRYPTO_KEY_SIZE);
if (SecurityBlob2->NegotiateFlags &
cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
- *pNTLMv2_flag = TRUE;
+ *pNTLMv2_flag = true;
if ((SecurityBlob2->NegotiateFlags &
cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
@@ -2939,7 +2938,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
}
static int
CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
- char *ntlm_session_key, int ntlmv2_flag,
+ char *ntlm_session_key, bool ntlmv2_flag,
const struct nls_table *nls_codepage)
{
struct smb_hdr *smb_buffer;
@@ -3556,8 +3555,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
cifs_sb->prepath = NULL;
kfree(tmp);
if (ses)
- schedule_timeout_interruptible(msecs_to_jiffies(500));
- if (ses)
sesInfoFree(ses);
FreeXid(xid);
@@ -3569,7 +3566,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
{
int rc = 0;
char ntlm_session_key[CIFS_SESS_KEY_SIZE];
- int ntlmv2_flag = FALSE;
+ bool ntlmv2_flag = false;
int first_time = 0;
/* what if server changes its buffer size after dropping the session? */