]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/cifs/transport.c
[CIFS] Fix missing permission check on setattr when noperm mount option is
[mirror_ubuntu-artful-kernel.git] / fs / cifs / transport.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/transport.c
3 *
b8643e1b 4 * Copyright (C) International Business Machines Corp., 2002,2005
1da177e4
LT
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
22#include <linux/fs.h>
23#include <linux/list.h>
24#include <linux/wait.h>
25#include <linux/net.h>
26#include <linux/delay.h>
27#include <asm/uaccess.h>
28#include <asm/processor.h>
29#include <linux/mempool.h>
30#include "cifspdu.h"
31#include "cifsglob.h"
32#include "cifsproto.h"
33#include "cifs_debug.h"
34
35extern mempool_t *cifs_mid_poolp;
36extern kmem_cache_t *cifs_oplock_cachep;
37
38static struct mid_q_entry *
39AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
40{
41 struct mid_q_entry *temp;
42
43 if (ses == NULL) {
275cde1a 44 cERROR(1, ("Null session passed in to AllocMidQEntry"));
1da177e4
LT
45 return NULL;
46 }
47 if (ses->server == NULL) {
48 cERROR(1, ("Null TCP session in AllocMidQEntry"));
49 return NULL;
50 }
51
d6e04ae6
SF
52 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53 SLAB_KERNEL | SLAB_NOFS);
1da177e4
LT
54 if (temp == NULL)
55 return temp;
56 else {
57 memset(temp, 0, sizeof (struct mid_q_entry));
58 temp->mid = smb_buffer->Mid; /* always LE */
59 temp->pid = current->pid;
60 temp->command = smb_buffer->Command;
61 cFYI(1, ("For smb_command %d", temp->command));
1047abc1
SF
62 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
63 /* when mid allocated can be before when sent */
64 temp->when_alloc = jiffies;
1da177e4
LT
65 temp->ses = ses;
66 temp->tsk = current;
67 }
68
69 spin_lock(&GlobalMid_Lock);
70 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
71 atomic_inc(&midCount);
72 temp->midState = MID_REQUEST_ALLOCATED;
73 spin_unlock(&GlobalMid_Lock);
74 return temp;
75}
76
77static void
78DeleteMidQEntry(struct mid_q_entry *midEntry)
79{
1047abc1
SF
80#ifdef CONFIG_CIFS_STATS2
81 unsigned long now;
82#endif
1da177e4
LT
83 spin_lock(&GlobalMid_Lock);
84 midEntry->midState = MID_FREE;
85 list_del(&midEntry->qhead);
86 atomic_dec(&midCount);
87 spin_unlock(&GlobalMid_Lock);
b8643e1b
SF
88 if(midEntry->largeBuf)
89 cifs_buf_release(midEntry->resp_buf);
90 else
91 cifs_small_buf_release(midEntry->resp_buf);
1047abc1
SF
92#ifdef CONFIG_CIFS_STATS2
93 now = jiffies;
94 /* commands taking longer than one second are indications that
95 something is wrong, unless it is quite a slow link or server */
96 if((now - midEntry->when_alloc) > HZ) {
97 if((cifsFYI & CIFS_TIMER) &&
98 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
99 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
100 midEntry->command, midEntry->mid);
101 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
102 now - midEntry->when_alloc,
103 now - midEntry->when_sent,
104 now - midEntry->when_received);
105 }
106 }
107#endif
1da177e4
LT
108 mempool_free(midEntry, cifs_mid_poolp);
109}
110
111struct oplock_q_entry *
112AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
113{
114 struct oplock_q_entry *temp;
115 if ((pinode== NULL) || (tcon == NULL)) {
116 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
117 return NULL;
118 }
119 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
120 SLAB_KERNEL);
121 if (temp == NULL)
122 return temp;
123 else {
124 temp->pinode = pinode;
125 temp->tcon = tcon;
126 temp->netfid = fid;
127 spin_lock(&GlobalMid_Lock);
128 list_add_tail(&temp->qhead, &GlobalOplock_Q);
129 spin_unlock(&GlobalMid_Lock);
130 }
131 return temp;
132
133}
134
135void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
136{
137 spin_lock(&GlobalMid_Lock);
138 /* should we check if list empty first? */
139 list_del(&oplockEntry->qhead);
140 spin_unlock(&GlobalMid_Lock);
141 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
142}
143
144int
145smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
146 unsigned int smb_buf_length, struct sockaddr *sin)
147{
148 int rc = 0;
149 int i = 0;
150 struct msghdr smb_msg;
151 struct kvec iov;
152 unsigned len = smb_buf_length + 4;
153
154 if(ssocket == NULL)
155 return -ENOTSOCK; /* BB eventually add reconnect code here */
156 iov.iov_base = smb_buffer;
157 iov.iov_len = len;
158
159 smb_msg.msg_name = sin;
160 smb_msg.msg_namelen = sizeof (struct sockaddr);
161 smb_msg.msg_control = NULL;
162 smb_msg.msg_controllen = 0;
163 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
164
165 /* smb header is converted in header_assemble. bcc and rest of SMB word
166 area, and byte area if necessary, is converted to littleendian in
167 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
168 Flags2 is converted in SendReceive */
169
170 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d 171 cFYI(1, ("Sending smb of length %d", smb_buf_length));
1da177e4
LT
172 dump_smb(smb_buffer, len);
173
174 while (len > 0) {
175 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
176 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
177 i++;
3e84469d
SF
178 /* smaller timeout here than send2 since smaller size */
179 /* Although it may not be required, this also is smaller
180 oplock break time */
68058e75 181 if(i > 12) {
1da177e4 182 cERROR(1,
68058e75 183 ("sends on sock %p stuck for 7 seconds",
1da177e4
LT
184 ssocket));
185 rc = -EAGAIN;
186 break;
187 }
68058e75 188 msleep(1 << i);
1da177e4
LT
189 continue;
190 }
191 if (rc < 0)
192 break;
5e1253b5
SF
193 else
194 i = 0; /* reset i after each successful send */
1da177e4
LT
195 iov.iov_base += rc;
196 iov.iov_len -= rc;
197 len -= rc;
198 }
199
200 if (rc < 0) {
3e84469d 201 cERROR(1,("Error %d sending data on socket to server", rc));
1da177e4
LT
202 } else {
203 rc = 0;
204 }
205
206 return rc;
207}
208
d6e04ae6
SF
209#ifdef CONFIG_CIFS_EXPERIMENTAL
210static int
3e84469d
SF
211smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
212 struct sockaddr *sin)
1da177e4
LT
213{
214 int rc = 0;
215 int i = 0;
216 struct msghdr smb_msg;
3e84469d
SF
217 struct smb_hdr *smb_buffer = iov[0].iov_base;
218 unsigned int len = iov[0].iov_len;
219 unsigned int total_len;
220 int first_vec = 0;
d6e04ae6 221
1da177e4
LT
222 if(ssocket == NULL)
223 return -ENOTSOCK; /* BB eventually add reconnect code here */
3e84469d 224
1da177e4
LT
225 smb_msg.msg_name = sin;
226 smb_msg.msg_namelen = sizeof (struct sockaddr);
227 smb_msg.msg_control = NULL;
228 smb_msg.msg_controllen = 0;
229 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
230
231 /* smb header is converted in header_assemble. bcc and rest of SMB word
232 area, and byte area if necessary, is converted to littleendian in
233 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
234 Flags2 is converted in SendReceive */
235
3e84469d
SF
236
237 total_len = 0;
238 for (i = 0; i < n_vec; i++)
239 total_len += iov[i].iov_len;
240
1da177e4 241 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d 242 cFYI(1, ("Sending smb: total_len %d", total_len));
1da177e4
LT
243 dump_smb(smb_buffer, len);
244
3e84469d
SF
245 while (total_len) {
246 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
247 n_vec - first_vec, total_len);
1da177e4
LT
248 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
249 i++;
68058e75 250 if(i >= 14) {
1da177e4 251 cERROR(1,
68058e75 252 ("sends on sock %p stuck for 15 seconds",
1da177e4
LT
253 ssocket));
254 rc = -EAGAIN;
255 break;
256 }
68058e75 257 msleep(1 << i);
1da177e4
LT
258 continue;
259 }
260 if (rc < 0)
261 break;
3e84469d
SF
262
263 if (rc >= total_len) {
264 WARN_ON(rc > total_len);
265 break;
266 }
267 if(rc == 0) {
268 /* should never happen, letting socket clear before
269 retrying is our only obvious option here */
04c08816 270 cERROR(1,("tcp sent no data"));
3e84469d
SF
271 msleep(500);
272 continue;
d6e04ae6 273 }
3e84469d 274 total_len -= rc;
68058e75 275 /* the line below resets i */
3e84469d
SF
276 for (i = first_vec; i < n_vec; i++) {
277 if (iov[i].iov_len) {
278 if (rc > iov[i].iov_len) {
279 rc -= iov[i].iov_len;
280 iov[i].iov_len = 0;
281 } else {
282 iov[i].iov_base += rc;
283 iov[i].iov_len -= rc;
284 first_vec = i;
285 break;
286 }
287 }
d6e04ae6 288 }
5e1253b5 289 i = 0; /* in case we get ENOSPC on the next send */
1da177e4
LT
290 }
291
292 if (rc < 0) {
3e84469d
SF
293 cERROR(1,("Error %d sending data on socket to server", rc));
294 } else
1da177e4 295 rc = 0;
1da177e4
LT
296
297 return rc;
298}
299
1da177e4 300int
d6e04ae6 301SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
3e84469d
SF
302 struct kvec *iov, int n_vec, int *pbytes_returned,
303 const int long_op)
1da177e4
LT
304{
305 int rc = 0;
d6e04ae6
SF
306 unsigned int receive_len;
307 unsigned long timeout;
308 struct mid_q_entry *midQ;
3e84469d 309 struct smb_hdr *in_buf = iov[0].iov_base;
1da177e4
LT
310
311 if (ses == NULL) {
312 cERROR(1,("Null smb session"));
313 return -EIO;
314 }
315 if(ses->server == NULL) {
316 cERROR(1,("Null tcp session"));
317 return -EIO;
318 }
1da177e4 319
d6e04ae6 320 if(ses->server->tcpStatus == CifsExiting)
31ca3bc3
SF
321 return -ENOENT;
322
1da177e4
LT
323 /* Ensure that we do not send more than 50 overlapping requests
324 to the same server. We may make this configurable later or
325 use ses->maxReq */
326 if(long_op == -1) {
327 /* oplock breaks must not be held up */
328 atomic_inc(&ses->server->inFlight);
329 } else {
330 spin_lock(&GlobalMid_Lock);
331 while(1) {
d6e04ae6
SF
332 if(atomic_read(&ses->server->inFlight) >=
333 cifs_max_pending){
1da177e4 334 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
335#ifdef CONFIG_CIFS_STATS2
336 atomic_inc(&ses->server->num_waiters);
337#endif
1da177e4
LT
338 wait_event(ses->server->request_q,
339 atomic_read(&ses->server->inFlight)
340 < cifs_max_pending);
131afd0b
SF
341#ifdef CONFIG_CIFS_STATS2
342 atomic_dec(&ses->server->num_waiters);
343#endif
1da177e4
LT
344 spin_lock(&GlobalMid_Lock);
345 } else {
346 if(ses->server->tcpStatus == CifsExiting) {
347 spin_unlock(&GlobalMid_Lock);
348 return -ENOENT;
349 }
350
351 /* can not count locking commands against total since
352 they are allowed to block on server */
353
354 if(long_op < 3) {
355 /* update # of requests on the wire to server */
356 atomic_inc(&ses->server->inFlight);
357 }
358 spin_unlock(&GlobalMid_Lock);
359 break;
360 }
361 }
362 }
363 /* make sure that we sign in the same order that we send on this socket
364 and avoid races inside tcp sendmsg code that could cause corruption
365 of smb data */
366
367 down(&ses->server->tcpSem);
368
369 if (ses->server->tcpStatus == CifsExiting) {
370 rc = -ENOENT;
d6e04ae6 371 goto out_unlock2;
1da177e4
LT
372 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
373 cFYI(1,("tcp session dead - return to caller to retry"));
374 rc = -EAGAIN;
d6e04ae6 375 goto out_unlock2;
1da177e4
LT
376 } else if (ses->status != CifsGood) {
377 /* check if SMB session is bad because we are setting it up */
378 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
379 (in_buf->Command != SMB_COM_NEGOTIATE)) {
380 rc = -EAGAIN;
d6e04ae6 381 goto out_unlock2;
1da177e4
LT
382 } /* else ok - we are setting up session */
383 }
384 midQ = AllocMidQEntry(in_buf, ses);
385 if (midQ == NULL) {
386 up(&ses->server->tcpSem);
387 /* If not lock req, update # of requests on wire to server */
388 if(long_op < 3) {
389 atomic_dec(&ses->server->inFlight);
390 wake_up(&ses->server->request_q);
391 }
392 return -ENOMEM;
393 }
394
d6e04ae6 395/* BB FIXME */
4a77118c 396/* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
1da177e4
LT
397
398 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
399#ifdef CONFIG_CIFS_STATS2
400 atomic_inc(&ses->server->inSend);
401#endif
3e84469d 402 rc = smb_send2(ses->server->ssocket, iov, n_vec,
d6e04ae6 403 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
404#ifdef CONFIG_CIFS_STATS2
405 atomic_dec(&ses->server->inSend);
1047abc1 406 midQ->when_sent = jiffies;
131afd0b 407#endif
1da177e4
LT
408 if(rc < 0) {
409 DeleteMidQEntry(midQ);
410 up(&ses->server->tcpSem);
411 /* If not lock req, update # of requests on wire to server */
412 if(long_op < 3) {
413 atomic_dec(&ses->server->inFlight);
414 wake_up(&ses->server->request_q);
415 }
416 return rc;
417 } else
418 up(&ses->server->tcpSem);
d6e04ae6
SF
419 if (long_op == -1)
420 goto cifs_no_response_exit2;
421 else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb46 422 timeout = 180 * HZ;
d6e04ae6
SF
423 else if (long_op == 1)
424 timeout = 45 * HZ; /* should be greater than
425 servers oplock break timeout (about 43 seconds) */
426 else if (long_op > 2) {
427 timeout = MAX_SCHEDULE_TIMEOUT;
428 } else
429 timeout = 15 * HZ;
430 /* wait for 15 seconds or until woken up due to response arriving or
431 due to last connection to this server being unmounted */
432 if (signal_pending(current)) {
433 /* if signal pending do not hold up user for full smb timeout
434 but we still give response a change to complete */
435 timeout = 2 * HZ;
436 }
437
438 /* No user interrupts in wait - wreaks havoc with performance */
439 if(timeout != MAX_SCHEDULE_TIMEOUT) {
440 timeout += jiffies;
441 wait_event(ses->server->response_q,
442 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
443 time_after(jiffies, timeout) ||
444 ((ses->server->tcpStatus != CifsGood) &&
445 (ses->server->tcpStatus != CifsNew)));
446 } else {
447 wait_event(ses->server->response_q,
448 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
449 ((ses->server->tcpStatus != CifsGood) &&
450 (ses->server->tcpStatus != CifsNew)));
451 }
452
453 spin_lock(&GlobalMid_Lock);
454 if (midQ->resp_buf) {
455 spin_unlock(&GlobalMid_Lock);
70ca734a 456 receive_len = midQ->resp_buf->smb_buf_length;
d6e04ae6 457 } else {
37c0eb46
SF
458 cERROR(1,("No response to cmd %d mid %d",
459 midQ->command, midQ->mid));
d6e04ae6
SF
460 if(midQ->midState == MID_REQUEST_SUBMITTED) {
461 if(ses->server->tcpStatus == CifsExiting)
462 rc = -EHOSTDOWN;
463 else {
464 ses->server->tcpStatus = CifsNeedReconnect;
465 midQ->midState = MID_RETRY_NEEDED;
466 }
467 }
468
469 if (rc != -EHOSTDOWN) {
470 if(midQ->midState == MID_RETRY_NEEDED) {
471 rc = -EAGAIN;
472 cFYI(1,("marking request for retry"));
473 } else {
474 rc = -EIO;
475 }
476 }
477 spin_unlock(&GlobalMid_Lock);
478 DeleteMidQEntry(midQ);
479 /* If not lock req, update # of requests on wire to server */
480 if(long_op < 3) {
481 atomic_dec(&ses->server->inFlight);
482 wake_up(&ses->server->request_q);
483 }
484 return rc;
485 }
486
487 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
488 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
489 receive_len, xid));
490 rc = -EIO;
491 } else { /* rcvd frame is ok */
492
493 if (midQ->resp_buf &&
494 (midQ->midState == MID_RESPONSE_RECEIVED)) {
495 in_buf->smb_buf_length = receive_len;
496 /* BB verify that length would not overrun small buf */
497 memcpy((char *)in_buf + 4,
498 (char *)midQ->resp_buf + 4,
499 receive_len);
500
501 dump_smb(in_buf, 80);
502 /* convert the length into a more usable form */
503 if((receive_len > 24) &&
504 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
505 SECMODE_SIGN_ENABLED))) {
506 rc = cifs_verify_signature(in_buf,
507 ses->server->mac_signing_key,
508 midQ->sequence_number+1);
509 if(rc) {
510 cERROR(1,("Unexpected SMB signature"));
511 /* BB FIXME add code to kill session */
512 }
513 }
514
515 *pbytes_returned = in_buf->smb_buf_length;
516
517 /* BB special case reconnect tid and uid here? */
518 rc = map_smb_to_linux_error(in_buf);
519
520 /* convert ByteCount if necessary */
521 if (receive_len >=
522 sizeof (struct smb_hdr) -
523 4 /* do not count RFC1001 header */ +
524 (2 * in_buf->WordCount) + 2 /* bcc */ )
0f2b27c4 525 BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf));
d6e04ae6
SF
526 } else {
527 rc = -EIO;
ab2f218f 528 cFYI(1,("Bad MID state?"));
d6e04ae6
SF
529 }
530 }
531cifs_no_response_exit2:
532 DeleteMidQEntry(midQ);
533
1da177e4 534 if(long_op < 3) {
d6e04ae6 535 atomic_dec(&ses->server->inFlight);
1da177e4
LT
536 wake_up(&ses->server->request_q);
537 }
538
539 return rc;
1da177e4 540
d6e04ae6
SF
541out_unlock2:
542 up(&ses->server->tcpSem);
543 /* If not lock req, update # of requests on wire to server */
544 if(long_op < 3) {
545 atomic_dec(&ses->server->inFlight);
546 wake_up(&ses->server->request_q);
547 }
1da177e4 548
d6e04ae6
SF
549 return rc;
550}
1da177e4
LT
551#endif /* CIFS_EXPERIMENTAL */
552
553int
554SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
555 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
556 int *pbytes_returned, const int long_op)
557{
558 int rc = 0;
559 unsigned int receive_len;
560 unsigned long timeout;
561 struct mid_q_entry *midQ;
562
563 if (ses == NULL) {
564 cERROR(1,("Null smb session"));
565 return -EIO;
566 }
567 if(ses->server == NULL) {
568 cERROR(1,("Null tcp session"));
569 return -EIO;
570 }
571
31ca3bc3
SF
572 if(ses->server->tcpStatus == CifsExiting)
573 return -ENOENT;
574
1da177e4
LT
575 /* Ensure that we do not send more than 50 overlapping requests
576 to the same server. We may make this configurable later or
577 use ses->maxReq */
578 if(long_op == -1) {
579 /* oplock breaks must not be held up */
580 atomic_inc(&ses->server->inFlight);
581 } else {
582 spin_lock(&GlobalMid_Lock);
583 while(1) {
275cde1a
SF
584 if(atomic_read(&ses->server->inFlight) >=
585 cifs_max_pending){
1da177e4 586 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
587#ifdef CONFIG_CIFS_STATS2
588 atomic_inc(&ses->server->num_waiters);
589#endif
1da177e4
LT
590 wait_event(ses->server->request_q,
591 atomic_read(&ses->server->inFlight)
592 < cifs_max_pending);
131afd0b
SF
593#ifdef CONFIG_CIFS_STATS2
594 atomic_dec(&ses->server->num_waiters);
595#endif
1da177e4
LT
596 spin_lock(&GlobalMid_Lock);
597 } else {
598 if(ses->server->tcpStatus == CifsExiting) {
599 spin_unlock(&GlobalMid_Lock);
600 return -ENOENT;
601 }
602
603 /* can not count locking commands against total since
604 they are allowed to block on server */
605
606 if(long_op < 3) {
607 /* update # of requests on the wire to server */
608 atomic_inc(&ses->server->inFlight);
609 }
610 spin_unlock(&GlobalMid_Lock);
611 break;
612 }
613 }
614 }
615 /* make sure that we sign in the same order that we send on this socket
616 and avoid races inside tcp sendmsg code that could cause corruption
617 of smb data */
618
619 down(&ses->server->tcpSem);
620
621 if (ses->server->tcpStatus == CifsExiting) {
622 rc = -ENOENT;
623 goto out_unlock;
624 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
625 cFYI(1,("tcp session dead - return to caller to retry"));
626 rc = -EAGAIN;
627 goto out_unlock;
628 } else if (ses->status != CifsGood) {
629 /* check if SMB session is bad because we are setting it up */
630 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
631 (in_buf->Command != SMB_COM_NEGOTIATE)) {
632 rc = -EAGAIN;
633 goto out_unlock;
634 } /* else ok - we are setting up session */
635 }
636 midQ = AllocMidQEntry(in_buf, ses);
637 if (midQ == NULL) {
638 up(&ses->server->tcpSem);
639 /* If not lock req, update # of requests on wire to server */
640 if(long_op < 3) {
641 atomic_dec(&ses->server->inFlight);
642 wake_up(&ses->server->request_q);
643 }
644 return -ENOMEM;
645 }
646
647 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
648 up(&ses->server->tcpSem);
649 cERROR(1,
650 ("Illegal length, greater than maximum frame, %d ",
651 in_buf->smb_buf_length));
652 DeleteMidQEntry(midQ);
653 /* If not lock req, update # of requests on wire to server */
654 if(long_op < 3) {
655 atomic_dec(&ses->server->inFlight);
656 wake_up(&ses->server->request_q);
657 }
658 return -EIO;
659 }
660
ad009ac9 661 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
662
663 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
664#ifdef CONFIG_CIFS_STATS2
665 atomic_inc(&ses->server->inSend);
666#endif
1da177e4
LT
667 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
668 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
669#ifdef CONFIG_CIFS_STATS2
670 atomic_dec(&ses->server->inSend);
1047abc1 671 midQ->when_sent = jiffies;
131afd0b 672#endif
1da177e4
LT
673 if(rc < 0) {
674 DeleteMidQEntry(midQ);
675 up(&ses->server->tcpSem);
676 /* If not lock req, update # of requests on wire to server */
677 if(long_op < 3) {
678 atomic_dec(&ses->server->inFlight);
679 wake_up(&ses->server->request_q);
680 }
681 return rc;
682 } else
683 up(&ses->server->tcpSem);
684 if (long_op == -1)
685 goto cifs_no_response_exit;
275cde1a 686 else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb46 687 timeout = 180 * HZ;
1da177e4
LT
688 else if (long_op == 1)
689 timeout = 45 * HZ; /* should be greater than
690 servers oplock break timeout (about 43 seconds) */
691 else if (long_op > 2) {
692 timeout = MAX_SCHEDULE_TIMEOUT;
693 } else
694 timeout = 15 * HZ;
695 /* wait for 15 seconds or until woken up due to response arriving or
696 due to last connection to this server being unmounted */
697 if (signal_pending(current)) {
698 /* if signal pending do not hold up user for full smb timeout
699 but we still give response a change to complete */
700 timeout = 2 * HZ;
701 }
702
703 /* No user interrupts in wait - wreaks havoc with performance */
704 if(timeout != MAX_SCHEDULE_TIMEOUT) {
705 timeout += jiffies;
706 wait_event(ses->server->response_q,
707 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
708 time_after(jiffies, timeout) ||
709 ((ses->server->tcpStatus != CifsGood) &&
710 (ses->server->tcpStatus != CifsNew)));
711 } else {
712 wait_event(ses->server->response_q,
713 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
714 ((ses->server->tcpStatus != CifsGood) &&
715 (ses->server->tcpStatus != CifsNew)));
716 }
717
718 spin_lock(&GlobalMid_Lock);
719 if (midQ->resp_buf) {
720 spin_unlock(&GlobalMid_Lock);
70ca734a 721 receive_len = midQ->resp_buf->smb_buf_length;
1da177e4 722 } else {
37c0eb46
SF
723 cERROR(1,("No response for cmd %d mid %d",
724 midQ->command, midQ->mid));
1da177e4
LT
725 if(midQ->midState == MID_REQUEST_SUBMITTED) {
726 if(ses->server->tcpStatus == CifsExiting)
727 rc = -EHOSTDOWN;
728 else {
729 ses->server->tcpStatus = CifsNeedReconnect;
730 midQ->midState = MID_RETRY_NEEDED;
731 }
732 }
733
734 if (rc != -EHOSTDOWN) {
735 if(midQ->midState == MID_RETRY_NEEDED) {
736 rc = -EAGAIN;
737 cFYI(1,("marking request for retry"));
738 } else {
739 rc = -EIO;
740 }
741 }
742 spin_unlock(&GlobalMid_Lock);
743 DeleteMidQEntry(midQ);
744 /* If not lock req, update # of requests on wire to server */
745 if(long_op < 3) {
746 atomic_dec(&ses->server->inFlight);
747 wake_up(&ses->server->request_q);
748 }
749 return rc;
750 }
751
752 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
ad009ac9 753 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1da177e4
LT
754 receive_len, xid));
755 rc = -EIO;
756 } else { /* rcvd frame is ok */
757
758 if (midQ->resp_buf && out_buf
759 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
760 out_buf->smb_buf_length = receive_len;
761 memcpy((char *)out_buf + 4,
762 (char *)midQ->resp_buf + 4,
763 receive_len);
764
765 dump_smb(out_buf, 92);
766 /* convert the length into a more usable form */
767 if((receive_len > 24) &&
ad009ac9
SF
768 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
769 SECMODE_SIGN_ENABLED))) {
770 rc = cifs_verify_signature(out_buf,
771 ses->server->mac_signing_key,
772 midQ->sequence_number+1);
773 if(rc) {
275cde1a
SF
774 cERROR(1,("Unexpected SMB signature"));
775 /* BB FIXME add code to kill session */
ad009ac9 776 }
1da177e4
LT
777 }
778
779 *pbytes_returned = out_buf->smb_buf_length;
780
ad009ac9 781 /* BB special case reconnect tid and uid here? */
1da177e4
LT
782 rc = map_smb_to_linux_error(out_buf);
783
784 /* convert ByteCount if necessary */
785 if (receive_len >=
786 sizeof (struct smb_hdr) -
787 4 /* do not count RFC1001 header */ +
788 (2 * out_buf->WordCount) + 2 /* bcc */ )
0f2b27c4 789 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1da177e4
LT
790 } else {
791 rc = -EIO;
a5a2b489 792 cERROR(1,("Bad MID state? "));
1da177e4
LT
793 }
794 }
795cifs_no_response_exit:
796 DeleteMidQEntry(midQ);
797
798 if(long_op < 3) {
799 atomic_dec(&ses->server->inFlight);
800 wake_up(&ses->server->request_q);
801 }
802
803 return rc;
804
805out_unlock:
806 up(&ses->server->tcpSem);
807 /* If not lock req, update # of requests on wire to server */
808 if(long_op < 3) {
809 atomic_dec(&ses->server->inFlight);
810 wake_up(&ses->server->request_q);
811 }
812
813 return rc;
814}