| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * fs/cifs/connect.c | |||
| 3 | * | |||
| 4 | * Copyright (C) International Business Machines Corp., 2002,2005 | |||
| 5 | * Author(s): Steve French (sfrench@us.ibm.com) | |||
| 6 | * | |||
| 7 | * This library is free software; you can redistribute it and/or modify | |||
| 8 | * it under the terms of the GNU Lesser General Public License as published | |||
| 9 | * by the Free Software Foundation; either version 2.1 of the License, or | |||
| 10 | * (at your option) any later version. | |||
| 11 | * | |||
| 12 | * This library is distributed in the hope that it will be useful, | |||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |||
| 15 | * the GNU Lesser General Public License for more details. | |||
| 16 | * | |||
| 17 | * You should have received a copy of the GNU Lesser General Public License | |||
| 18 | * along with this library; if not, write to the Free Software | |||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 20 | */ | |||
| 21 | #include <linux/fs.h> | |||
| 22 | #include <linux/net.h> | |||
| 23 | #include <linux/string.h> | |||
| 24 | #include <linux/list.h> | |||
| 25 | #include <linux/wait.h> | |||
| 26 | #include <linux/ipv6.h> | |||
| 27 | #include <linux/pagemap.h> | |||
| 28 | #include <linux/ctype.h> | |||
| 29 | #include <linux/utsname.h> | |||
| 30 | #include <linux/mempool.h> | |||
| 31 | #include <linux/delay.h> | |||
| 32 | #include <linux/completion.h> | |||
| 33 | #include <linux/pagevec.h> | |||
| 34 | #include <asm/uaccess.h> | |||
| 35 | #include <asm/processor.h> | |||
| 36 | #include "cifspdu.h" | |||
| 37 | #include "cifsglob.h" | |||
| 38 | #include "cifsproto.h" | |||
| 39 | #include "cifs_unicode.h" | |||
| 40 | #include "cifs_debug.h" | |||
| 41 | #include "cifs_fs_sb.h" | |||
| 42 | #include "ntlmssp.h" | |||
| 43 | #include "nterr.h" | |||
| 44 | #include "rfc1002pdu.h" | |||
| 45 | #include "cn_cifs.h" | |||
| 46 | ||||
| 47 | #define CIFS_PORT 445 | |||
| 48 | #define RFC1001_PORT 139 | |||
| 49 | ||||
| 50 | static DECLARE_COMPLETION(cifsd_complete); | |||
| 51 | ||||
| 52 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | |||
| 53 | unsigned char *p24); | |||
| 54 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | |||
| 55 | unsigned char *p24); | |||
| 56 | ||||
| 57 | extern mempool_t *cifs_req_poolp; | |||
| 58 | ||||
| 59 | struct smb_vol { | |||
| 60 | char *username; | |||
| 61 | char *password; | |||
| 62 | char *domainname; | |||
| 63 | char *UNC; | |||
| 64 | char *UNCip; | |||
| 65 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ | |||
| 66 | char *iocharset; /* local code page for mapping to and from Unicode */ | |||
| 67 | char source_rfc1001_name[16]; /* netbios name of client */ | |||
| 68 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | |||
| 69 | uid_t linux_uid; | |||
| 70 | gid_t linux_gid; | |||
| 71 | mode_t file_mode; | |||
| 72 | mode_t dir_mode; | |||
| 73 | unsigned rw:1; | |||
| 74 | unsigned retry:1; | |||
| 75 | unsigned intr:1; | |||
| 76 | unsigned setuids:1; | |||
| 77 | unsigned noperm:1; | |||
| 78 | unsigned no_psx_acl:1; /* set if posix acl support should be disabled */ | |||
| 79 | unsigned cifs_acl:1; | |||
| 80 | unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ | |||
| 81 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | |||
| 82 | unsigned direct_io:1; | |||
| 83 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | |||
| 84 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ | |||
| 85 | unsigned sfu_emul:1; | |||
| 86 | unsigned krb5:1; | |||
| 87 | unsigned ntlm:1; | |||
| 88 | unsigned ntlmv2:1; | |||
| 89 | unsigned nullauth:1; /* attempt to authenticate with null user */ | |||
| 90 | unsigned sign:1; | |||
| 91 | unsigned seal:1; /* encrypt */ | |||
| 92 | unsigned nocase; /* request case insensitive filenames */ | |||
| 93 | unsigned nobrl; /* disable sending byte range locks to srv */ | |||
| 94 | unsigned int rsize; | |||
| 95 | unsigned int wsize; | |||
| 96 | unsigned int sockopt; | |||
| 97 | unsigned short int port; | |||
| 98 | }; | |||
| 99 | ||||
| 100 | static int ipv4_connect(struct sockaddr_in *psin_server, | |||
| 101 | struct socket **csocket, | |||
| 102 | char * netb_name, | |||
| 103 | char * server_netb_name); | |||
| 104 | static int ipv6_connect(struct sockaddr_in6 *psin_server, | |||
| 105 | struct socket **csocket); | |||
| 106 | ||||
| 107 | ||||
| 108 | /* | |||
| 109 | * cifs tcp session reconnection | |||
| 110 | * | |||
| 111 | * mark tcp session as reconnecting so temporarily locked | |||
| 112 | * mark all smb sessions as reconnecting for tcp session | |||
| 113 | * reconnect tcp session | |||
| 114 | * wake up waiters on reconnection? - (not needed currently) | |||
| 115 | */ | |||
| 116 | ||||
| 117 | int | |||
| 0 | 0 | - | 118 | cifs_reconnect(struct TCP_Server_Info *server) |
| 119 | { | |||
| 120 | int rc = 0; | |||
| 121 | struct list_head *tmp; | |||
| 122 | struct cifsSesInfo *ses; | |||
| 123 | struct cifsTconInfo *tcon; | |||
| 124 | struct mid_q_entry * mid_entry; | |||
| 125 | ||||
| 126 | spin_lock(&GlobalMid_Lock); | |||
| 126 | do | |||
| 0 | 0 | - | 126 | do-while (0) |
| 0 | 0 | - | 126 | do-while (0) |
| 0 | 0 | - | 127 | if(server->tcpStatus == CifsExiting) { |
| 128 | /* the demux thread will exit normally | |||
| 129 | next time through the loop */ | |||
| 130 | spin_unlock(&GlobalMid_Lock); | |||
| 130 | do | |||
| 0 | 0 | - | 130 | do-while (0) |
| 0 | 0 | - | 130 | do-while (0) |
| 0 | - | 131 | return rc; | |
| 132 | } else | |||
| 133 | server->tcpStatus = CifsNeedReconnect; | |||
| 134 | spin_unlock(&GlobalMid_Lock); | |||
| 134 | do | |||
| 0 | 0 | - | 134 | do-while (0) |
| 0 | 0 | - | 134 | do-while (0) |
| 135 | server->maxBuf = 0; | |||
| 136 | ||||
| 0 | 0 | - | 137 | cFYI(1, ("Reconnecting tcp session")); |
| 0 | 0 | - | 137 | if (cifsFYI & 0x01) |
| 138 | ||||
| 139 | /* before reconnecting the tcp session, mark the smb session (uid) | |||
| 140 | and the tid bad so they are not used until reconnected */ | |||
| 141 | read_lock(&GlobalSMBSeslock); | |||
| 141 | do | |||
| 0 | 0 | - | 141 | do-while (0) |
| 0 | 0 | - | 141 | do-while (0) |
| 0 | 0 | - | 142 | list_for_each(tmp, &GlobalSMBSessionList) { |
| 143 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | |||
| 0 | 0 | - | 144 | if (ses->server) { |
| 0 | 0 | - | 145 | if (ses->server == server) { |
| 146 | ses->status = CifsNeedReconnect; | |||
| 147 | ses->ipc_tid = 0; | |||
| 148 | } | |||
| 149 | } | |||
| 150 | /* else tcp and smb sessions need reconnection */ | |||
| 151 | } | |||
| 0 | 0 | - | 152 | list_for_each(tmp, &GlobalTreeConnectionList) { |
| 153 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | |||
| 0 | 0 | - | 154 | if((tcon) && (tcon->ses) && (tcon->ses->server == server)) { |
| 0 | - | 154 | (T) && (T) && (T) | |
| 0 | - | 154 | (T) && (T) && (F) | |
| 0 | - | 154 | (T) && (F) && (_) | |
| 0 | - | 154 | (F) && (_) && (_) | |
| 155 | tcon->tidStatus = CifsNeedReconnect; | |||
| 156 | } | |||
| 157 | } | |||
| 158 | read_unlock(&GlobalSMBSeslock); | |||
| 158 | do | |||
| 0 | 0 | - | 158 | do-while (0) |
| 0 | 0 | - | 158 | do-while (0) |
| 159 | /* do not want to be sending data on a socket we are freeing */ | |||
| 160 | down(&server->tcpSem); | |||
| 0 | 0 | - | 161 | if(server->ssocket) { |
| 0 | 0 | - | 162 | cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, |
| 0 | 0 | - | 162 | if (cifsFYI & 0x01) |
| 163 | server->ssocket->flags)); | |||
| 164 | server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN); | |||
| 0 | 0 | - | 165 | cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state, |
| 0 | 0 | - | 165 | if (cifsFYI & 0x01) |
| 166 | server->ssocket->flags)); | |||
| 167 | sock_release(server->ssocket); | |||
| 168 | server->ssocket = NULL; | |||
| 169 | } | |||
| 170 | ||||
| 171 | spin_lock(&GlobalMid_Lock); | |||
| 171 | do | |||
| 0 | 0 | - | 171 | do-while (0) |
| 0 | 0 | - | 171 | do-while (0) |
| 0 | 0 | - | 172 | list_for_each(tmp, &server->pending_mid_q) { |
| 173 | mid_entry = list_entry(tmp, struct | |||
| 174 | mid_q_entry, | |||
| 175 | qhead); | |||
| 0 | 0 | - | 176 | if(mid_entry) { |
| 0 | 0 | - | 177 | if(mid_entry->midState == MID_REQUEST_SUBMITTED) { |
| 178 | /* Mark other intransit requests as needing | |||
| 179 | retry so we do not immediately mark the | |||
| 180 | session bad again (ie after we reconnect | |||
| 181 | below) as they timeout too */ | |||
| 182 | mid_entry->midState = MID_RETRY_NEEDED; | |||
| 183 | } | |||
| 184 | } | |||
| 185 | } | |||
| 186 | spin_unlock(&GlobalMid_Lock); | |||
| 186 | do | |||
| 0 | 0 | - | 186 | do-while (0) |
| 0 | 0 | - | 186 | do-while (0) |
| 187 | up(&server->tcpSem); | |||
| 188 | ||||
| 0 | 0 | - | 189 | while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) |
| 0 | - | 189 | (T) && (T) | |
| 0 | - | 189 | (T) && (F) | |
| 0 | - | 189 | (F) && (_) | |
| 190 | { | |||
| 0 | 0 | - | 191 | if(server->protocolType == IPV6) { |
| 192 | rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); | |||
| 193 | } else { | |||
| 194 | rc = ipv4_connect(&server->addr.sockAddr, | |||
| 195 | &server->ssocket, | |||
| 196 | server->workstation_RFC1001_name, | |||
| 197 | server->server_RFC1001_name); | |||
| 198 | } | |||
| 0 | 0 | - | 199 | if(rc) { |
| 0 | 0 | - | 200 | cFYI(1,("reconnect error %d",rc)); |
| 0 | 0 | - | 200 | if (cifsFYI & 0x01) |
| 201 | msleep(3000); | |||
| 202 | } else { | |||
| 203 | atomic_inc(&tcpSesReconnectCount); | |||
| 204 | spin_lock(&GlobalMid_Lock); | |||
| 204 | do | |||
| 0 | 0 | - | 204 | do-while (0) |
| 0 | 0 | - | 204 | do-while (0) |
| 0 | 0 | - | 205 | if(server->tcpStatus != CifsExiting) |
| 206 | server->tcpStatus = CifsGood; | |||
| 207 | server->sequence_number = 0; | |||
| 208 | spin_unlock(&GlobalMid_Lock); | |||
| 208 | do | |||
| 0 | 0 | - | 208 | do-while (0) |
| 0 | 0 | - | 208 | do-while (0) |
| 209 | /* atomic_set(&server->inFlight,0);*/ | |||
| 210 | wake_up(&server->response_q); | |||
| 211 | } | |||
| 212 | } | |||
| 0 | - | 213 | return rc; | |
| 214 | } | |||
| 215 | ||||
| 216 | /* | |||
| 217 | return codes: | |||
| 218 | 0 not a transact2, or all data present | |||
| 219 | >0 transact2 with that much data missing | |||
| 220 | -EINVAL = invalid transact2 | |||
| 221 | ||||
| 222 | */ | |||
| 0 | 0 | - | 223 | static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize) |
| 224 | { | |||
| 225 | struct smb_t2_rsp * pSMBt; | |||
| 226 | int total_data_size; | |||
| 227 | int data_in_this_rsp; | |||
| 228 | int remaining; | |||
| 229 | ||||
| 0 | 0 | - | 230 | if(pSMB->Command != SMB_COM_TRANSACTION2) |
| 0 | - | 231 | return 0; | |
| 232 | ||||
| 233 | /* check for plausible wct, bcc and t2 data and parm sizes */ | |||
| 234 | /* check for parm and data offset going beyond end of smb */ | |||
| 0 | 0 | - | 235 | if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */ |
| 0 | 0 | - | 236 | cFYI(1,("invalid transact2 word count")); |
| 0 | 0 | - | 236 | if (cifsFYI & 0x01) |
| 0 | - | 237 | return -EINVAL; | |
| 238 | } | |||
| 239 | ||||
| 240 | pSMBt = (struct smb_t2_rsp *)pSMB; | |||
| 241 | ||||
| 242 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | |||
| 243 | data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount); | |||
| 244 | ||||
| 245 | remaining = total_data_size - data_in_this_rsp; | |||
| 246 | ||||
| 0 | 0 | - | 247 | if(remaining == 0) |
| 0 | - | 248 | return 0; | |
| 0 | 0 | - | 249 | else if(remaining < 0) { |
| 0 | 0 | - | 250 | cFYI(1,("total data %d smaller than data in frame %d", |
| 0 | 0 | - | 250 | if (cifsFYI & 0x01) |
| 251 | total_data_size, data_in_this_rsp)); | |||
| 0 | - | 252 | return -EINVAL; | |
| 253 | } else { | |||
| 0 | 0 | - | 254 | cFYI(1,("missing %d bytes from transact2, check next response", |
| 0 | 0 | - | 254 | if (cifsFYI & 0x01) |
| 255 | remaining)); | |||
| 0 | 0 | - | 256 | if(total_data_size > maxBufSize) { |
| 0 | 0 | - | 257 | cERROR(1,("TotalDataSize %d is over maximum buffer %d", |
| 0 | 0 | - | 257 | if (cifsERROR) |
| 258 | total_data_size,maxBufSize)); | |||
| 0 | - | 259 | return -EINVAL; | |
| 260 | } | |||
| 0 | - | 261 | return remaining; | |
| 262 | } | |||
| 263 | } | |||
| 264 | ||||
| 0 | 0 | - | 265 | static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) |
| 266 | { | |||
| 267 | struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; | |||
| 268 | struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; | |||
| 269 | int total_data_size; | |||
| 270 | int total_in_buf; | |||
| 271 | int remaining; | |||
| 272 | int total_in_buf2; | |||
| 273 | char * data_area_of_target; | |||
| 274 | char * data_area_of_buf2; | |||
| 275 | __u16 byte_count; | |||
| 276 | ||||
| 277 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | |||
| 278 | ||||
| 0 | 0 | - | 279 | if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { |
| 0 | 0 | - | 280 | cFYI(1,("total data sizes of primary and secondary t2 differ")); |
| 0 | 0 | - | 280 | if (cifsFYI & 0x01) |
| 281 | } | |||
| 282 | ||||
| 283 | total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); | |||
| 284 | ||||
| 285 | remaining = total_data_size - total_in_buf; | |||
| 286 | ||||
| 0 | 0 | - | 287 | if(remaining < 0) |
| 0 | - | 288 | return -EINVAL; | |
| 289 | ||||
| 0 | 0 | - | 290 | if(remaining == 0) /* nothing to do, ignore */ |
| 0 | - | 291 | return 0; | |
| 292 | ||||
| 293 | total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); | |||
| 0 | 0 | - | 294 | if(remaining < total_in_buf2) { |
| 0 | 0 | - | 295 | cFYI(1,("transact2 2nd response contains too much data")); |
| 0 | 0 | - | 295 | if (cifsFYI & 0x01) |
| 296 | } | |||
| 297 | ||||
| 298 | /* find end of first SMB data area */ | |||
| 299 | data_area_of_target = (char *)&pSMBt->hdr.Protocol + | |||
| 300 | le16_to_cpu(pSMBt->t2_rsp.DataOffset); | |||
| 301 | /* validate target area */ | |||
| 302 | ||||
| 303 | data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol + | |||
| 304 | le16_to_cpu(pSMB2->t2_rsp.DataOffset); | |||
| 305 | ||||
| 306 | data_area_of_target += total_in_buf; | |||
| 307 | ||||
| 308 | /* copy second buffer into end of first buffer */ | |||
| 309 | memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2); | |||
| 310 | total_in_buf += total_in_buf2; | |||
| 311 | pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); | |||
| 312 | byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); | |||
| 313 | byte_count += total_in_buf2; | |||
| 314 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); | |||
| 315 | ||||
| 316 | byte_count = pTargetSMB->smb_buf_length; | |||
| 317 | byte_count += total_in_buf2; | |||
| 318 | ||||
| 319 | /* BB also add check that we are not beyond maximum buffer size */ | |||
| 320 | ||||
| 321 | pTargetSMB->smb_buf_length = byte_count; | |||
| 322 | ||||
| 0 | 0 | - | 323 | if(remaining == total_in_buf2) { |
| 0 | 0 | - | 324 | cFYI(1,("found the last secondary response")); |
| 0 | 0 | - | 324 | if (cifsFYI & 0x01) |
| 0 | - | 325 | return 0; /* we are done */ | |
| 326 | } else /* more responses to go */ | |||
| 0 | - | 327 | return 1; | |
| 328 | ||||
| 329 | } | |||
| 330 | ||||
| 331 | static int | |||
| 0 | 0 | - | 332 | cifs_demultiplex_thread(struct TCP_Server_Info *server) |
| 333 | { | |||
| 334 | int length; | |||
| 335 | unsigned int pdu_length, total_read; | |||
| 336 | struct smb_hdr *smb_buffer = NULL; | |||
| 337 | struct smb_hdr *bigbuf = NULL; | |||
| 338 | struct smb_hdr *smallbuf = NULL; | |||
| 339 | struct msghdr smb_msg; | |||
| 340 | struct kvec iov; | |||
| 341 | struct socket *csocket = server->ssocket; | |||
| 342 | struct list_head *tmp; | |||
| 343 | struct cifsSesInfo *ses; | |||
| 344 | struct task_struct *task_to_wake = NULL; | |||
| 345 | struct mid_q_entry *mid_entry; | |||
| 346 | char temp; | |||
| 347 | int isLargeBuf = FALSE; | |||
| 348 | int isMultiRsp; | |||
| 349 | int reconnect; | |||
| 350 | ||||
| 351 | daemonize("cifsd"); | |||
| 352 | allow_signal(SIGKILL); | |||
| 353 | current->flags |= PF_MEMALLOC; | |||
| 354 | server->tsk = current; /* save process info to wake at shutdown */ | |||
| 0 | 0 | - | 355 | cFYI(1, ("Demultiplex PID: %d", current->pid)); |
| 0 | 0 | - | 355 | if (cifsFYI & 0x01) |
| 356 | write_lock(&GlobalSMBSeslock); | |||
| 356 | do | |||
| 0 | 0 | - | 356 | do-while (0) |
| 0 | 0 | - | 356 | do-while (0) |
| 357 | atomic_inc(&tcpSesAllocCount); | |||
| 358 | length = tcpSesAllocCount.counter; | |||
| 359 | write_unlock(&GlobalSMBSeslock); | |||
| 359 | do | |||
| 0 | 0 | - | 359 | do-while (0) |
| 0 | 0 | - | 359 | do-while (0) |
| 360 | complete(&cifsd_complete); | |||
| 0 | 0 | - | 361 | if(length > 1) { |
| 362 | mempool_resize(cifs_req_poolp, | |||
| 363 | length + cifs_min_rcv, | |||
| 364 | GFP_KERNEL); | |||
| 365 | } | |||
| 366 | ||||
| 0 | 0 | - | 367 | while (server->tcpStatus != CifsExiting) { |
| 0 | 0 | - | 368 | if (try_to_freeze()) |
| 0 | - | 369 | continue; | |
| 0 | 0 | - | 370 | if (bigbuf == NULL) { |
| 371 | bigbuf = cifs_buf_get(); | |||
| 0 | 0 | - | 372 | if(bigbuf == NULL) { |
| 0 | 0 | - | 373 | cERROR(1,("No memory for large SMB response")); |
| 0 | 0 | - | 373 | if (cifsERROR) |
| 374 | msleep(3000); | |||
| 375 | /* retry will check if exiting */ | |||
| 0 | - | 376 | continue; | |
| 377 | } | |||
| 0 | 0 | - | 378 | } else if(isLargeBuf) { |
| 379 | /* we are reusing a dirtry large buf, clear its start */ | |||
| 380 | memset(bigbuf, 0, sizeof (struct smb_hdr)); | |||
| 381 | } | |||
| 382 | ||||
| 0 | 0 | - | 383 | if (smallbuf == NULL) { |
| 384 | smallbuf = cifs_small_buf_get(); | |||
| 0 | 0 | - | 385 | if(smallbuf == NULL) { |
| 0 | 0 | - | 386 | cERROR(1,("No memory for SMB response")); |
| 0 | 0 | - | 386 | if (cifsERROR) |
| 387 | msleep(1000); | |||
| 388 | /* retry will check if exiting */ | |||
| 0 | - | 389 | continue; | |
| 390 | } | |||
| 391 | /* beginning of smb buffer is cleared in our buf_get */ | |||
| 392 | } else /* if existing small buf clear beginning */ | |||
| 393 | memset(smallbuf, 0, sizeof (struct smb_hdr)); | |||
| 394 | ||||
| 395 | isLargeBuf = FALSE; | |||
| 396 | isMultiRsp = FALSE; | |||
| 397 | smb_buffer = smallbuf; | |||
| 398 | iov.iov_base = smb_buffer; | |||
| 399 | iov.iov_len = 4; | |||
| 400 | smb_msg.msg_control = NULL; | |||
| 401 | smb_msg.msg_controllen = 0; | |||
| 402 | length = | |||
| 403 | kernel_recvmsg(csocket, &smb_msg, | |||
| 404 | &iov, 1, 4, 0 /* BB see socket.h flags */); | |||
| 405 | ||||
| 0 | 0 | - | 406 | if(server->tcpStatus == CifsExiting) { |
| 0 | - | 407 | break; | |
| 0 | 0 | - | 408 | } else if (server->tcpStatus == CifsNeedReconnect) { |
| 0 | 0 | - | 409 | cFYI(1,("Reconnect after server stopped responding")); |
| 0 | 0 | - | 409 | if (cifsFYI & 0x01) |
| 410 | cifs_reconnect(server); | |||
| 0 | 0 | - | 411 | cFYI(1,("call to reconnect done")); |
| 0 | 0 | - | 411 | if (cifsFYI & 0x01) |
| 412 | csocket = server->ssocket; | |||
| 0 | - | 413 | continue; | |
| 0 | 0 | - | 414 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { |
| 0 | - | 414 | (T) || (_) | |
| 0 | - | 414 | (F) || (T) | |
| 0 | - | 414 | (F) || (F) | |
| 415 | msleep(1); /* minimum sleep to prevent looping | |||
| 416 | allowing socket to clear and app threads to set | |||
| 417 | tcpStatus CifsNeedReconnect if server hung */ | |||
| 0 | - | 418 | continue; | |
| 0 | 0 | - | 419 | } else if (length <= 0) { |
| 0 | 0 | - | 420 | if(server->tcpStatus == CifsNew) { |
| 0 | 0 | - | 421 | cFYI(1,("tcp session abend after SMBnegprot")); |
| 0 | 0 | - | 421 | if (cifsFYI & 0x01) |
| 422 | /* some servers kill the TCP session rather than | |||
| 423 | returning an SMB negprot error, in which | |||
| 424 | case reconnecting here is not going to help, | |||
| 425 | and so simply return error to mount */ | |||
| 0 | - | 426 | break; | |
| 427 | } | |||
| 0 | 0 | - | 428 | if(length == -EINTR) { |
| 0 | 0 | - | 429 | cFYI(1,("cifsd thread killed")); |
| 0 | 0 | - | 429 | if (cifsFYI & 0x01) |
| 0 | - | 430 | break; | |
| 431 | } | |||
| 0 | 0 | - | 432 | cFYI(1,("Reconnect after unexpected peek error %d", |
| 0 | 0 | - | 432 | if (cifsFYI & 0x01) |
| 433 | length)); | |||
| 434 | cifs_reconnect(server); | |||
| 435 | csocket = server->ssocket; | |||
| 436 | wake_up(&server->response_q); | |||
| 0 | - | 437 | continue; | |
| 0 | 0 | - | 438 | }& |