ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / cifs / transport.c
1 /*
2  *   fs/cifs/transport.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2004
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 <asm/uaccess.h>
27 #include <asm/processor.h>
28 #include "cifspdu.h"
29 #include "cifsglob.h"
30 #include "cifsproto.h"
31 #include "cifs_debug.h"
32   
33 extern kmem_cache_t *cifs_mid_cachep;
34 extern kmem_cache_t *cifs_oplock_cachep;
35
36 struct mid_q_entry *
37 AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
38 {
39         struct mid_q_entry *temp;
40
41         if (ses == NULL) {
42                 cERROR(1, ("Null session passed in to AllocMidQEntry "));
43                 return NULL;
44         }
45         if (ses->server == NULL) {
46                 cERROR(1, ("Null TCP session in AllocMidQEntry"));
47                 return NULL;
48         }
49         
50         temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep,
51                                                        SLAB_KERNEL);
52         if (temp == NULL)
53                 return temp;
54         else {
55                 memset(temp, 0, sizeof (struct mid_q_entry));
56                 temp->mid = smb_buffer->Mid;    /* always LE */
57                 temp->pid = current->pid;
58                 temp->command = smb_buffer->Command;
59                 cFYI(1, ("For smb_command %d", temp->command));
60                 do_gettimeofday(&temp->when_sent);
61                 temp->ses = ses;
62                 temp->tsk = current;
63         }
64
65         spin_lock(&GlobalMid_Lock);
66         list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
67         atomic_inc(&midCount);
68         temp->midState = MID_REQUEST_ALLOCATED;
69         spin_unlock(&GlobalMid_Lock);
70         return temp;
71 }
72
73 void
74 DeleteMidQEntry(struct mid_q_entry *midEntry)
75 {
76         spin_lock(&GlobalMid_Lock);
77         midEntry->midState = MID_FREE;
78         list_del(&midEntry->qhead);
79         atomic_dec(&midCount);
80         spin_unlock(&GlobalMid_Lock);
81         cifs_buf_release(midEntry->resp_buf);
82         kmem_cache_free(cifs_mid_cachep, midEntry);
83 }
84
85 struct oplock_q_entry *
86 AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
87 {
88         struct oplock_q_entry *temp;
89         if ((pinode== NULL) || (tcon == NULL)) {
90                 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
91                 return NULL;
92         }
93         temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
94                                                        SLAB_KERNEL);
95         if (temp == NULL)
96                 return temp;
97         else {
98                 temp->pinode = pinode;
99                 temp->tcon = tcon;
100                 temp->netfid = fid;
101                 spin_lock(&GlobalMid_Lock);
102                 list_add_tail(&temp->qhead, &GlobalOplock_Q);
103                 spin_unlock(&GlobalMid_Lock);
104         }
105         return temp;
106
107 }
108
109 void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
110 {
111         spin_lock(&GlobalMid_Lock); 
112     /* should we check if list empty first? */
113         list_del(&oplockEntry->qhead);
114         spin_unlock(&GlobalMid_Lock);
115         kmem_cache_free(cifs_oplock_cachep, oplockEntry);
116 }
117
118 int
119 smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
120          unsigned int smb_buf_length, struct sockaddr *sin)
121 {
122         int rc = 0;
123         struct msghdr smb_msg;
124         struct iovec iov;
125         mm_segment_t temp_fs;
126
127         if(ssocket == NULL)
128                 return -ENOTSOCK; /* BB eventually add reconnect code here */
129 /*  ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */
130         iov.iov_base = smb_buffer;
131         iov.iov_len = smb_buf_length + 4;
132
133         smb_msg.msg_name = sin;
134         smb_msg.msg_namelen = sizeof (struct sockaddr);
135         smb_msg.msg_iov = &iov;
136         smb_msg.msg_iovlen = 1;
137         smb_msg.msg_control = NULL;
138         smb_msg.msg_controllen = 0;
139         smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
140
141         /* smb header is converted in header_assemble. bcc and rest of SMB word
142            area, and byte area if necessary, is converted to littleendian in 
143            cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
144            Flags2 is converted in SendReceive */
145
146         smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
147         cFYI(1, ("Sending smb of length %d ", smb_buf_length));
148         dump_smb(smb_buffer, smb_buf_length + 4);
149
150         temp_fs = get_fs();     /* we must turn off socket api parm checking */
151         set_fs(get_ds());
152         while(iov.iov_len > 0) {
153                 rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4);
154                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
155                         set_current_state(TASK_INTERRUPTIBLE);
156                         schedule_timeout(HZ/2);
157                         continue;
158                 }
159                 if (rc < 0) 
160                         break;
161                 iov.iov_base += rc;
162                 iov.iov_len -= rc;
163         }
164         set_fs(temp_fs);
165
166         if (rc < 0) {
167                 cERROR(1,("Error %d sending data on socket to server.", rc));
168         } else {
169                 rc = 0;
170         }
171
172         return rc;
173 }
174
175 int
176 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
177             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
178             int *pbytes_returned, const int long_op)
179 {
180         int rc = 0;
181         unsigned int receive_len;
182         long timeout;
183         struct mid_q_entry *midQ;
184
185         if ((ses == NULL) || (ses->server == NULL)) {
186                 cERROR(1,("Null tcp session or smb session: %p",ses));
187                 return -EIO;
188         }
189
190         if (ses->server->tcpStatus == CifsExiting) {
191                 return -ENOENT;
192         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
193                 cFYI(1,("tcp session dead - return to caller to retry"));
194                 return -EAGAIN;
195         } else if (ses->status != CifsGood) {
196                 /* check if SMB session is bad because we are setting it up */
197                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
198                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
199                         return -EAGAIN;
200                 } /* else ok - we are setting up session */
201         }
202         /* make sure that we sign in the same order that we send on this socket 
203                 and avoid races inside tcp sendmsg code that could cause corruption
204                 of smb data */
205         down(&ses->server->tcpSem); 
206         midQ = AllocMidQEntry(in_buf, ses);
207         if (midQ == NULL) {
208                 up(&ses->server->tcpSem);
209                 return -EIO;
210         }
211
212         if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
213                 up(&ses->server->tcpSem);
214                 cERROR(1,
215                        ("Illegal length, greater than maximum frame, %d ",
216                         in_buf->smb_buf_length));
217                 DeleteMidQEntry(midQ);
218                 return -EIO;
219         }
220
221         if (in_buf->smb_buf_length > 12)
222                 in_buf->Flags2 = cpu_to_le16(in_buf->Flags2);
223         
224         rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
225
226         midQ->midState = MID_REQUEST_SUBMITTED;
227         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
228                       (struct sockaddr *) &(ses->server->addr.sockAddr));
229         up(&ses->server->tcpSem);
230         if (long_op == -1)
231                 goto cifs_no_response_exit;
232         else if (long_op == 2) /* writes past end of file can take looooong time */
233                 timeout = 300 * HZ;
234         else if (long_op == 1)
235                 timeout = 45 * HZ; /* should be greater than 
236                         servers oplock break timeout (about 43 seconds) */
237         else if (long_op > 2) {
238                 timeout = MAX_SCHEDULE_TIMEOUT;
239         } else
240                 timeout = 15 * HZ;
241         /* wait for 15 seconds or until woken up due to response arriving or 
242            due to last connection to this server being unmounted */
243         if (signal_pending(current)) {
244                 /* if signal pending do not hold up user for full smb timeout
245                 but we still give response a change to complete */
246                 if(midQ->midState & MID_REQUEST_SUBMITTED) {
247                         set_current_state(TASK_UNINTERRUPTIBLE);
248                         timeout = sleep_on_timeout(&ses->server->response_q,2 * HZ);
249                 }
250         } else { /* using normal timeout */
251                 /* timeout = wait_event_interruptible_timeout(ses->server->response_q,
252                         (midQ->midState & MID_RESPONSE_RECEIVED) || 
253                         ((ses->server->tcpStatus != CifsGood) &&
254                          (ses->server->tcpStatus != CifsNew)),
255                         timeout); */ 
256                 /* Can not allow user interrupts- wreaks havoc with performance */
257                 if(midQ->midState & MID_REQUEST_SUBMITTED) {
258                         set_current_state(TASK_UNINTERRUPTIBLE);
259                         timeout = sleep_on_timeout(&ses->server->response_q,timeout);
260                 }
261         }
262     
263         spin_lock(&GlobalMid_Lock);
264         if (midQ->resp_buf) {
265                 spin_unlock(&GlobalMid_Lock);
266                 receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
267         } else {
268                 cERROR(1,("No response buffer"));
269                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
270                         if(ses->server->tcpStatus == CifsExiting)
271                                 rc = -EHOSTDOWN;
272                         else {
273                                 ses->server->tcpStatus = CifsNeedReconnect;
274                                 midQ->midState = MID_RETRY_NEEDED;
275                         }
276                 }
277
278                 if (rc != -EHOSTDOWN) {
279                         if(midQ->midState == MID_RETRY_NEEDED) {
280                                 rc = -EAGAIN;
281                                 cFYI(1,("marking request for retry"));
282                         } else {
283                                 rc = -EIO;
284                         }
285                 }
286                 spin_unlock(&GlobalMid_Lock);
287                 DeleteMidQEntry(midQ);
288                 return rc;
289         }
290   
291
292         if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
293                 cERROR(1,
294                        ("Frame too large received.  Length: %d  Xid: %d",
295                         receive_len, xid));
296                 rc = -EIO;
297         } else {                /* rcvd frame is ok */
298
299                 if (midQ->resp_buf && out_buf
300                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
301                         memcpy(out_buf, midQ->resp_buf,
302                                receive_len +
303                                4 /* include 4 byte RFC1001 header */ );
304
305                         dump_smb(out_buf, 92);
306                         /* convert the length into a more usable form */
307                         out_buf->smb_buf_length =
308                             be32_to_cpu(out_buf->smb_buf_length);
309                         if((out_buf->smb_buf_length > 24) &&
310                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
311                                 rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
312                                 if(rc)
313                                         cFYI(1,("Unexpected signature received from server"));
314                         }
315
316                         if (out_buf->smb_buf_length > 12)
317                                 out_buf->Flags2 = le16_to_cpu(out_buf->Flags2);
318                         if (out_buf->smb_buf_length > 28)
319                                 out_buf->Pid = le16_to_cpu(out_buf->Pid);
320                         if (out_buf->smb_buf_length > 28)
321                                 out_buf->PidHigh =
322                                     le16_to_cpu(out_buf->PidHigh);
323
324                         *pbytes_returned = out_buf->smb_buf_length;
325
326                         /* BB special case reconnect tid and reconnect uid here? */
327                         rc = map_smb_to_linux_error(out_buf);
328
329                         /* convert ByteCount if necessary */
330                         if (receive_len >=
331                             sizeof (struct smb_hdr) -
332                             4 /* do not count RFC1001 header */  +
333                             (2 * out_buf->WordCount) + 2 /* bcc */ )
334                                 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
335                 } else {
336                         rc = -EIO;
337                         cFYI(1,("Bad MID state? "));
338                 }
339         }
340 cifs_no_response_exit:
341         DeleteMidQEntry(midQ);  /* BB what if process is killed?
342                          - BB add background daemon to clean up Mid entries from
343                          killed processes & test killing process with active mid */
344         return rc;
345 }