[CIFS] Fix authentication choice so we do not force NTLMv2 unless the
[pandora-kernel.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2006
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44         int index;
45         char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48         {LANMAN_PROT, "\2LM1.2X002"},
49 #endif /* weak password hashing for legacy clients */
50         {CIFS_PROT, "\2NT LM 0.12"}, 
51         {POSIX_PROT, "\2POSIX 2"},
52         {BAD_PROT, "\2"}
53 };
54 #else
55 static struct {
56         int index;
57         char *name;
58 } protocols[] = {
59 #ifdef CONFIG_CIFS_WEAK_PW_HASH
60         {LANMAN_PROT, "\2LM1.2X002"},
61 #endif /* weak password hashing for legacy clients */
62         {CIFS_PROT, "\2NT LM 0.12"}, 
63         {BAD_PROT, "\2"}
64 };
65 #endif
66
67 /* define the number of elements in the cifs dialect array */
68 #ifdef CONFIG_CIFS_POSIX
69 #ifdef CONFIG_CIFS_WEAK_PW_HASH
70 #define CIFS_NUM_PROT 3
71 #else
72 #define CIFS_NUM_PROT 2
73 #endif /* CIFS_WEAK_PW_HASH */
74 #else /* not posix */
75 #ifdef CONFIG_CIFS_WEAK_PW_HASH
76 #define CIFS_NUM_PROT 2
77 #else
78 #define CIFS_NUM_PROT 1
79 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
80 #endif /* CIFS_POSIX */
81
82
83 /* Mark as invalid, all open files on tree connections since they
84    were closed when session to server was lost */
85 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
86 {
87         struct cifsFileInfo *open_file = NULL;
88         struct list_head * tmp;
89         struct list_head * tmp1;
90
91 /* list all files open on tree connection and mark them invalid */
92         write_lock(&GlobalSMBSeslock);
93         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
94                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
95                 if(open_file) {
96                         open_file->invalidHandle = TRUE;
97                 }
98         }
99         write_unlock(&GlobalSMBSeslock);
100         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101            to this tcon */
102 }
103
104 /* If the return code is zero, this function must fill in request_buf pointer */
105 static int
106 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
107          void **request_buf /* returned */)
108 {
109         int rc = 0;
110
111         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
112            check for tcp and smb session status done differently
113            for those three - in the calling routine */
114         if(tcon) {
115                 if(tcon->tidStatus == CifsExiting) {
116                         /* only tree disconnect, open, and write,
117                         (and ulogoff which does not have tcon)
118                         are allowed as we start force umount */
119                         if((smb_command != SMB_COM_WRITE_ANDX) && 
120                            (smb_command != SMB_COM_OPEN_ANDX) && 
121                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
122                                 cFYI(1,("can not send cmd %d while umounting",
123                                         smb_command));
124                                 return -ENODEV;
125                         }
126                 }
127                 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
128                                   (tcon->ses->server)){
129                         struct nls_table *nls_codepage;
130                                 /* Give Demultiplex thread up to 10 seconds to 
131                                    reconnect, should be greater than cifs socket
132                                    timeout which is 7 seconds */
133                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
134                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
135                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
136                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
137                                         /* on "soft" mounts we wait once */
138                                         if((tcon->retry == FALSE) || 
139                                            (tcon->ses->status == CifsExiting)) {
140                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
141                                                 return -EHOSTDOWN;
142                                         } /* else "hard" mount - keep retrying
143                                              until process is killed or server
144                                              comes back on-line */
145                                 } else /* TCP session is reestablished now */
146                                         break;
147                                  
148                         }
149                         
150                         nls_codepage = load_nls_default();
151                 /* need to prevent multiple threads trying to
152                 simultaneously reconnect the same SMB session */
153                         down(&tcon->ses->sesSem);
154                         if(tcon->ses->status == CifsNeedReconnect)
155                                 rc = cifs_setup_session(0, tcon->ses, 
156                                                         nls_codepage);
157                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
158                                 mark_open_files_invalid(tcon);
159                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
160                                         , nls_codepage);
161                                 up(&tcon->ses->sesSem);
162                                 /* BB FIXME add code to check if wsize needs
163                                    update due to negotiated smb buffer size
164                                    shrinking */
165                                 if(rc == 0)
166                                         atomic_inc(&tconInfoReconnectCount);
167
168                                 cFYI(1, ("reconnect tcon rc = %d", rc));
169                                 /* Removed call to reopen open files here - 
170                                    it is safer (and faster) to reopen files
171                                    one at a time as needed in read and write */
172
173                                 /* Check if handle based operation so we 
174                                    know whether we can continue or not without
175                                    returning to caller to reset file handle */
176                                 switch(smb_command) {
177                                         case SMB_COM_READ_ANDX:
178                                         case SMB_COM_WRITE_ANDX:
179                                         case SMB_COM_CLOSE:
180                                         case SMB_COM_FIND_CLOSE2:
181                                         case SMB_COM_LOCKING_ANDX: {
182                                                 unload_nls(nls_codepage);
183                                                 return -EAGAIN;
184                                         }
185                                 }
186                         } else {
187                                 up(&tcon->ses->sesSem);
188                         }
189                         unload_nls(nls_codepage);
190
191                 } else {
192                         return -EIO;
193                 }
194         }
195         if(rc)
196                 return rc;
197
198         *request_buf = cifs_small_buf_get();
199         if (*request_buf == NULL) {
200                 /* BB should we add a retry in here if not a writepage? */
201                 return -ENOMEM;
202         }
203
204         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
205
206         if(tcon != NULL)
207                 cifs_stats_inc(&tcon->num_smbs_sent);
208
209         return rc;
210 }
211
212 int
213 small_smb_init_no_tc(const int smb_command, const int wct, 
214                      struct cifsSesInfo *ses, void **request_buf)
215 {
216         int rc;
217         struct smb_hdr * buffer;
218
219         rc = small_smb_init(smb_command, wct, NULL, request_buf);
220         if(rc)
221                 return rc;
222
223         buffer = (struct smb_hdr *)*request_buf;
224         buffer->Mid = GetNextMid(ses->server);
225         if (ses->capabilities & CAP_UNICODE)
226                 buffer->Flags2 |= SMBFLG2_UNICODE;
227         if (ses->capabilities & CAP_STATUS32)
228                 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
229
230         /* uid, tid can stay at zero as set in header assemble */
231
232         /* BB add support for turning on the signing when 
233         this function is used after 1st of session setup requests */
234
235         return rc;
236 }
237
238 /* If the return code is zero, this function must fill in request_buf pointer */
239 static int
240 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
241          void **request_buf /* returned */ ,
242          void **response_buf /* returned */ )
243 {
244         int rc = 0;
245
246         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
247            check for tcp and smb session status done differently
248            for those three - in the calling routine */
249         if(tcon) {
250                 if(tcon->tidStatus == CifsExiting) {
251                         /* only tree disconnect, open, and write,
252                           (and ulogoff which does not have tcon)
253                           are allowed as we start force umount */
254                         if((smb_command != SMB_COM_WRITE_ANDX) &&
255                            (smb_command != SMB_COM_OPEN_ANDX) &&
256                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
257                                 cFYI(1,("can not send cmd %d while umounting",
258                                         smb_command));
259                                 return -ENODEV;
260                         }
261                 }
262
263                 if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
264                                   (tcon->ses->server)){
265                         struct nls_table *nls_codepage;
266                                 /* Give Demultiplex thread up to 10 seconds to
267                                    reconnect, should be greater than cifs socket
268                                    timeout which is 7 seconds */
269                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
270                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
271                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
272                                 if(tcon->ses->server->tcpStatus == 
273                                                 CifsNeedReconnect) {
274                                         /* on "soft" mounts we wait once */
275                                         if((tcon->retry == FALSE) || 
276                                            (tcon->ses->status == CifsExiting)) {
277                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
278                                                 return -EHOSTDOWN;
279                                         } /* else "hard" mount - keep retrying
280                                              until process is killed or server
281                                              comes on-line */
282                                 } else /* TCP session is reestablished now */
283                                         break;
284                                  
285                         }
286                         
287                         nls_codepage = load_nls_default();
288                 /* need to prevent multiple threads trying to
289                 simultaneously reconnect the same SMB session */
290                         down(&tcon->ses->sesSem);
291                         if(tcon->ses->status == CifsNeedReconnect)
292                                 rc = cifs_setup_session(0, tcon->ses, 
293                                                         nls_codepage);
294                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
295                                 mark_open_files_invalid(tcon);
296                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
297                                               tcon, nls_codepage);
298                                 up(&tcon->ses->sesSem);
299                                 /* BB FIXME add code to check if wsize needs
300                                 update due to negotiated smb buffer size
301                                 shrinking */
302                                 if(rc == 0)
303                                         atomic_inc(&tconInfoReconnectCount);
304
305                                 cFYI(1, ("reconnect tcon rc = %d", rc));
306                                 /* Removed call to reopen open files here - 
307                                    it is safer (and faster) to reopen files
308                                    one at a time as needed in read and write */
309
310                                 /* Check if handle based operation so we 
311                                    know whether we can continue or not without
312                                    returning to caller to reset file handle */
313                                 switch(smb_command) {
314                                         case SMB_COM_READ_ANDX:
315                                         case SMB_COM_WRITE_ANDX:
316                                         case SMB_COM_CLOSE:
317                                         case SMB_COM_FIND_CLOSE2:
318                                         case SMB_COM_LOCKING_ANDX: {
319                                                 unload_nls(nls_codepage);
320                                                 return -EAGAIN;
321                                         }
322                                 }
323                         } else {
324                                 up(&tcon->ses->sesSem);
325                         }
326                         unload_nls(nls_codepage);
327
328                 } else {
329                         return -EIO;
330                 }
331         }
332         if(rc)
333                 return rc;
334
335         *request_buf = cifs_buf_get();
336         if (*request_buf == NULL) {
337                 /* BB should we add a retry in here if not a writepage? */
338                 return -ENOMEM;
339         }
340     /* Although the original thought was we needed the response buf for  */
341     /* potential retries of smb operations it turns out we can determine */
342     /* from the mid flags when the request buffer can be resent without  */
343     /* having to use a second distinct buffer for the response */
344         if(response_buf)
345                 *response_buf = *request_buf; 
346
347         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
348                         wct /*wct */ );
349
350         if(tcon != NULL)
351                 cifs_stats_inc(&tcon->num_smbs_sent);
352
353         return rc;
354 }
355
356 static int validate_t2(struct smb_t2_rsp * pSMB) 
357 {
358         int rc = -EINVAL;
359         int total_size;
360         char * pBCC;
361
362         /* check for plausible wct, bcc and t2 data and parm sizes */
363         /* check for parm and data offset going beyond end of smb */
364         if(pSMB->hdr.WordCount >= 10) {
365                 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
366                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
367                         /* check that bcc is at least as big as parms + data */
368                         /* check that bcc is less than negotiated smb buffer */
369                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
370                         if(total_size < 512) {
371                                 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
372                                 /* BCC le converted in SendReceive */
373                                 pBCC = (pSMB->hdr.WordCount * 2) + 
374                                         sizeof(struct smb_hdr) +
375                                         (char *)pSMB;
376                                 if((total_size <= (*(u16 *)pBCC)) && 
377                                    (total_size < 
378                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
379                                         return 0;
380                                 }
381                                 
382                         }
383                 }
384         }
385         cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
386                 sizeof(struct smb_t2_rsp) + 16);
387         return rc;
388 }
389 int
390 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
391 {
392         NEGOTIATE_REQ *pSMB;
393         NEGOTIATE_RSP *pSMBr;
394         int rc = 0;
395         int bytes_returned;
396         int i;
397         struct TCP_Server_Info * server;
398         u16 count;
399         unsigned int secFlags;
400
401         if(ses->server)
402                 server = ses->server;
403         else {
404                 rc = -EIO;
405                 return rc;
406         }
407         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
408                       (void **) &pSMB, (void **) &pSMBr);
409         if (rc)
410                 return rc;
411
412         /* if any of auth flags (ie not sign or seal) are overriden use them */
413         if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
414                 secFlags = ses->overrideSecFlg;
415         else /* if override flags set only sign/seal OR them with global auth */
416                 secFlags = extended_security | ses->overrideSecFlg;
417
418         cFYI(1,("secFlags 0x%x",secFlags));
419
420         pSMB->hdr.Mid = GetNextMid(server);
421         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
422         if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
423                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
424         
425         count = 0;
426         for(i=0;i<CIFS_NUM_PROT;i++) {
427                 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
428                 count += strlen(protocols[i].name) + 1;
429                 /* null at end of source and target buffers anyway */
430         }
431         pSMB->hdr.smb_buf_length += count;
432         pSMB->ByteCount = cpu_to_le16(count);
433
434         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
435                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
436         if (rc != 0) 
437                 goto neg_err_exit;
438
439         cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
440         /* Check wct = 1 error case */
441         if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
442                 /* core returns wct = 1, but we do not ask for core - otherwise
443                 small wct just comes when dialect index is -1 indicating we 
444                 could not negotiate a common dialect */
445                 rc = -EOPNOTSUPP;
446                 goto neg_err_exit;
447 #ifdef CONFIG_CIFS_WEAK_PW_HASH 
448         } else if((pSMBr->hdr.WordCount == 13)
449                         && (pSMBr->DialectIndex == LANMAN_PROT)) {
450                 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
451
452                 if((secFlags & CIFSSEC_MAY_LANMAN) || 
453                         (secFlags & CIFSSEC_MAY_PLNTXT))
454                         server->secType = LANMAN;
455                 else {
456                         cERROR(1, ("mount failed weak security disabled"
457                                    " in /proc/fs/cifs/SecurityFlags"));
458                         rc = -EOPNOTSUPP;
459                         goto neg_err_exit;
460                 }       
461                 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
462                 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
463                 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
464                                 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
465                 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
466                 /* even though we do not use raw we might as well set this
467                 accurately, in case we ever find a need for it */
468                 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
469                         server->maxRw = 0xFF00;
470                         server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
471                 } else {
472                         server->maxRw = 0;/* we do not need to use raw anyway */
473                         server->capabilities = CAP_MPX_MODE;
474                 }
475                 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
476
477                 /* BB get server time for time conversions and add
478                 code to use it and timezone since this is not UTC */    
479
480                 if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
481                         memcpy(server->cryptKey, rsp->EncryptionKey,
482                                 CIFS_CRYPTO_KEY_SIZE);
483                 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
484                         rc = -EIO; /* need cryptkey unless plain text */
485                         goto neg_err_exit;
486                 }
487
488                 cFYI(1,("LANMAN negotiated"));
489                 /* we will not end up setting signing flags - as no signing
490                 was in LANMAN and server did not return the flags on */
491                 goto signing_check;
492 #else /* weak security disabled */
493         } else if(pSMBr->hdr.WordCount == 13) {
494                 cERROR(1,("mount failed, cifs module not built "
495                           "with CIFS_WEAK_PW_HASH support"));
496                         rc = -EOPNOTSUPP;
497 #endif /* WEAK_PW_HASH */
498                 goto neg_err_exit;
499         } else if(pSMBr->hdr.WordCount != 17) {
500                 /* unknown wct */
501                 rc = -EOPNOTSUPP;
502                 goto neg_err_exit;
503         }
504         /* else wct == 17 NTLM */
505         server->secMode = pSMBr->SecurityMode;
506         if((server->secMode & SECMODE_USER) == 0)
507                 cFYI(1,("share mode security"));
508
509         if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
510 #ifdef CONFIG_CIFS_WEAK_PW_HASH
511                 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
512 #endif /* CIFS_WEAK_PW_HASH */
513                         cERROR(1,("Server requests plain text password"
514                                   " but client support disabled"));
515
516         if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
517                 server->secType = NTLMv2;
518         else if(secFlags & CIFSSEC_MAY_NTLM)
519                 server->secType = NTLM;
520         else if(secFlags & CIFSSEC_MAY_NTLMV2)
521                 server->secType = NTLMv2;
522         /* else krb5 ... any others ... */
523
524         /* one byte, so no need to convert this or EncryptionKeyLen from
525            little endian */
526         server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
527         /* probably no need to store and check maxvcs */
528         server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
529                         (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
530         server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
531         cFYI(0, ("Max buf = %d", ses->server->maxBuf));
532         GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
533         server->capabilities = le32_to_cpu(pSMBr->Capabilities);
534         server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
535         if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
536                 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
537                        CIFS_CRYPTO_KEY_SIZE);
538         } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
539                         && (pSMBr->EncryptionKeyLength == 0)) {
540                 /* decode security blob */
541         } else if (server->secMode & SECMODE_PW_ENCRYPT) {
542                 rc = -EIO; /* no crypt key only if plain text pwd */
543                 goto neg_err_exit;
544         }
545
546         /* BB might be helpful to save off the domain of server here */
547
548         if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
549                 (server->capabilities & CAP_EXTENDED_SECURITY)) {
550                 count = pSMBr->ByteCount;
551                 if (count < 16)
552                         rc = -EIO;
553                 else if (count == 16) {
554                         server->secType = RawNTLMSSP;
555                         if (server->socketUseCount.counter > 1) {
556                                 if (memcmp(server->server_GUID,
557                                            pSMBr->u.extended_response.
558                                            GUID, 16) != 0) {
559                                         cFYI(1, ("server UID changed"));
560                                         memcpy(server->server_GUID,
561                                                 pSMBr->u.extended_response.GUID,
562                                                 16);
563                                 }
564                         } else
565                                 memcpy(server->server_GUID,
566                                        pSMBr->u.extended_response.GUID, 16);
567                 } else {
568                         rc = decode_negTokenInit(pSMBr->u.extended_response.
569                                                  SecurityBlob,
570                                                  count - 16,
571                                                  &server->secType);
572                         if(rc == 1) {
573                         /* BB Need to fill struct for sessetup here */
574                                 rc = -EOPNOTSUPP;
575                         } else {
576                                 rc = -EINVAL;
577                         }
578                 }
579         } else
580                 server->capabilities &= ~CAP_EXTENDED_SECURITY;
581
582 #ifdef CONFIG_CIFS_WEAK_PW_HASH
583 signing_check:
584 #endif
585         if(sign_CIFS_PDUs == FALSE) {        
586                 if(server->secMode & SECMODE_SIGN_REQUIRED)
587                         cERROR(1,("Server requires "
588                                  "/proc/fs/cifs/PacketSigningEnabled to be on"));
589                 server->secMode &= 
590                         ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
591         } else if(sign_CIFS_PDUs == 1) {
592                 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
593                         server->secMode &= 
594                                 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
595         } else if(sign_CIFS_PDUs == 2) {
596                 if((server->secMode & 
597                         (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
598                         cERROR(1,("signing required but server lacks support"));
599                 }
600         }
601 neg_err_exit:   
602         cifs_buf_release(pSMB);
603
604         cFYI(1,("negprot rc %d",rc));
605         return rc;
606 }
607
608 int
609 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
610 {
611         struct smb_hdr *smb_buffer;
612         struct smb_hdr *smb_buffer_response; /* BB removeme BB */
613         int rc = 0;
614         int length;
615
616         cFYI(1, ("In tree disconnect"));
617         /*
618          *  If last user of the connection and
619          *  connection alive - disconnect it
620          *  If this is the last connection on the server session disconnect it
621          *  (and inside session disconnect we should check if tcp socket needs 
622          *  to be freed and kernel thread woken up).
623          */
624         if (tcon)
625                 down(&tcon->tconSem);
626         else
627                 return -EIO;
628
629         atomic_dec(&tcon->useCount);
630         if (atomic_read(&tcon->useCount) > 0) {
631                 up(&tcon->tconSem);
632                 return -EBUSY;
633         }
634
635         /* No need to return error on this operation if tid invalidated and 
636         closed on server already e.g. due to tcp session crashing */
637         if(tcon->tidStatus == CifsNeedReconnect) {
638                 up(&tcon->tconSem);
639                 return 0;  
640         }
641
642         if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
643                 up(&tcon->tconSem);
644                 return -EIO;
645         }
646         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
647                             (void **)&smb_buffer);
648         if (rc) {
649                 up(&tcon->tconSem);
650                 return rc;
651         } else {
652                 smb_buffer_response = smb_buffer; /* BB removeme BB */
653         }
654         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
655                          &length, 0);
656         if (rc)
657                 cFYI(1, ("Tree disconnect failed %d", rc));
658
659         if (smb_buffer)
660                 cifs_small_buf_release(smb_buffer);
661         up(&tcon->tconSem);
662
663         /* No need to return error on this operation if tid invalidated and 
664         closed on server already e.g. due to tcp session crashing */
665         if (rc == -EAGAIN)
666                 rc = 0;
667
668         return rc;
669 }
670
671 int
672 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
673 {
674         struct smb_hdr *smb_buffer_response;
675         LOGOFF_ANDX_REQ *pSMB;
676         int rc = 0;
677         int length;
678
679         cFYI(1, ("In SMBLogoff for session disconnect"));
680         if (ses)
681                 down(&ses->sesSem);
682         else
683                 return -EIO;
684
685         atomic_dec(&ses->inUse);
686         if (atomic_read(&ses->inUse) > 0) {
687                 up(&ses->sesSem);
688                 return -EBUSY;
689         }
690         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
691         if (rc) {
692                 up(&ses->sesSem);
693                 return rc;
694         }
695
696         smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
697         
698         if(ses->server) {
699                 pSMB->hdr.Mid = GetNextMid(ses->server);
700
701                 if(ses->server->secMode & 
702                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
703                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
704         }
705
706         pSMB->hdr.Uid = ses->Suid;
707
708         pSMB->AndXCommand = 0xFF;
709         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
710                          smb_buffer_response, &length, 0);
711         if (ses->server) {
712                 atomic_dec(&ses->server->socketUseCount);
713                 if (atomic_read(&ses->server->socketUseCount) == 0) {
714                         spin_lock(&GlobalMid_Lock);
715                         ses->server->tcpStatus = CifsExiting;
716                         spin_unlock(&GlobalMid_Lock);
717                         rc = -ESHUTDOWN;
718                 }
719         }
720         up(&ses->sesSem);
721         cifs_small_buf_release(pSMB);
722
723         /* if session dead then we do not need to do ulogoff,
724                 since server closed smb session, no sense reporting 
725                 error */
726         if (rc == -EAGAIN)
727                 rc = 0;
728         return rc;
729 }
730
731 int
732 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
733                const struct nls_table *nls_codepage, int remap)
734 {
735         DELETE_FILE_REQ *pSMB = NULL;
736         DELETE_FILE_RSP *pSMBr = NULL;
737         int rc = 0;
738         int bytes_returned;
739         int name_len;
740
741 DelFileRetry:
742         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
743                       (void **) &pSMBr);
744         if (rc)
745                 return rc;
746
747         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
748                 name_len =
749                     cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
750                                      PATH_MAX, nls_codepage, remap);
751                 name_len++;     /* trailing null */
752                 name_len *= 2;
753         } else {                /* BB improve check for buffer overruns BB */
754                 name_len = strnlen(fileName, PATH_MAX);
755                 name_len++;     /* trailing null */
756                 strncpy(pSMB->fileName, fileName, name_len);
757         }
758         pSMB->SearchAttributes =
759             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
760         pSMB->BufferFormat = 0x04;
761         pSMB->hdr.smb_buf_length += name_len + 1;
762         pSMB->ByteCount = cpu_to_le16(name_len + 1);
763         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
764                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
765         cifs_stats_inc(&tcon->num_deletes);
766         if (rc) {
767                 cFYI(1, ("Error in RMFile = %d", rc));
768         } 
769
770         cifs_buf_release(pSMB);
771         if (rc == -EAGAIN)
772                 goto DelFileRetry;
773
774         return rc;
775 }
776
777 int
778 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
779              const struct nls_table *nls_codepage, int remap)
780 {
781         DELETE_DIRECTORY_REQ *pSMB = NULL;
782         DELETE_DIRECTORY_RSP *pSMBr = NULL;
783         int rc = 0;
784         int bytes_returned;
785         int name_len;
786
787         cFYI(1, ("In CIFSSMBRmDir"));
788 RmDirRetry:
789         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
790                       (void **) &pSMBr);
791         if (rc)
792                 return rc;
793
794         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
795                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
796                                          PATH_MAX, nls_codepage, remap);
797                 name_len++;     /* trailing null */
798                 name_len *= 2;
799         } else {                /* BB improve check for buffer overruns BB */
800                 name_len = strnlen(dirName, PATH_MAX);
801                 name_len++;     /* trailing null */
802                 strncpy(pSMB->DirName, dirName, name_len);
803         }
804
805         pSMB->BufferFormat = 0x04;
806         pSMB->hdr.smb_buf_length += name_len + 1;
807         pSMB->ByteCount = cpu_to_le16(name_len + 1);
808         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
809                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
810         cifs_stats_inc(&tcon->num_rmdirs);
811         if (rc) {
812                 cFYI(1, ("Error in RMDir = %d", rc));
813         }
814
815         cifs_buf_release(pSMB);
816         if (rc == -EAGAIN)
817                 goto RmDirRetry;
818         return rc;
819 }
820
821 int
822 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
823              const char *name, const struct nls_table *nls_codepage, int remap)
824 {
825         int rc = 0;
826         CREATE_DIRECTORY_REQ *pSMB = NULL;
827         CREATE_DIRECTORY_RSP *pSMBr = NULL;
828         int bytes_returned;
829         int name_len;
830
831         cFYI(1, ("In CIFSSMBMkDir"));
832 MkDirRetry:
833         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
834                       (void **) &pSMBr);
835         if (rc)
836                 return rc;
837
838         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
839                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
840                                             PATH_MAX, nls_codepage, remap);
841                 name_len++;     /* trailing null */
842                 name_len *= 2;
843         } else {                /* BB improve check for buffer overruns BB */
844                 name_len = strnlen(name, PATH_MAX);
845                 name_len++;     /* trailing null */
846                 strncpy(pSMB->DirName, name, name_len);
847         }
848
849         pSMB->BufferFormat = 0x04;
850         pSMB->hdr.smb_buf_length += name_len + 1;
851         pSMB->ByteCount = cpu_to_le16(name_len + 1);
852         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
853                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
854         cifs_stats_inc(&tcon->num_mkdirs);
855         if (rc) {
856                 cFYI(1, ("Error in Mkdir = %d", rc));
857         }
858
859         cifs_buf_release(pSMB);
860         if (rc == -EAGAIN)
861                 goto MkDirRetry;
862         return rc;
863 }
864
865 static __u16 convert_disposition(int disposition)
866 {
867         __u16 ofun = 0;
868
869         switch (disposition) {
870                 case FILE_SUPERSEDE:
871                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
872                         break;
873                 case FILE_OPEN:
874                         ofun = SMBOPEN_OAPPEND;
875                         break;
876                 case FILE_CREATE:
877                         ofun = SMBOPEN_OCREATE;
878                         break;
879                 case FILE_OPEN_IF:
880                         ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
881                         break;
882                 case FILE_OVERWRITE:
883                         ofun = SMBOPEN_OTRUNC;
884                         break;
885                 case FILE_OVERWRITE_IF:
886                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
887                         break;
888                 default:
889                         cFYI(1,("unknown disposition %d",disposition));
890                         ofun =  SMBOPEN_OAPPEND; /* regular open */
891         }
892         return ofun;
893 }
894
895 int
896 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
897             const char *fileName, const int openDisposition,
898             const int access_flags, const int create_options, __u16 * netfid,
899             int *pOplock, FILE_ALL_INFO * pfile_info,
900             const struct nls_table *nls_codepage, int remap)
901 {
902         int rc = -EACCES;
903         OPENX_REQ *pSMB = NULL;
904         OPENX_RSP *pSMBr = NULL;
905         int bytes_returned;
906         int name_len;
907         __u16 count;
908
909 OldOpenRetry:
910         rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
911                       (void **) &pSMBr);
912         if (rc)
913                 return rc;
914
915         pSMB->AndXCommand = 0xFF;       /* none */
916
917         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
918                 count = 1;      /* account for one byte pad to word boundary */
919                 name_len =
920                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
921                                     fileName, PATH_MAX, nls_codepage, remap);
922                 name_len++;     /* trailing null */
923                 name_len *= 2;
924         } else {                /* BB improve check for buffer overruns BB */
925                 count = 0;      /* no pad */
926                 name_len = strnlen(fileName, PATH_MAX);
927                 name_len++;     /* trailing null */
928                 strncpy(pSMB->fileName, fileName, name_len);
929         }
930         if (*pOplock & REQ_OPLOCK)
931                 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
932         else if (*pOplock & REQ_BATCHOPLOCK) {
933                 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
934         }
935         pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
936         /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
937         /* 0 = read
938            1 = write
939            2 = rw
940            3 = execute
941         */
942         pSMB->Mode = cpu_to_le16(2);
943         pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
944         /* set file as system file if special file such
945            as fifo and server expecting SFU style and
946            no Unix extensions */
947
948         if(create_options & CREATE_OPTION_SPECIAL)
949                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
950         else
951                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
952
953         /* if ((omode & S_IWUGO) == 0)
954                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
955         /*  Above line causes problems due to vfs splitting create into two
956             pieces - need to set mode after file created not while it is
957             being created */
958
959         /* BB FIXME BB */
960 /*      pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
961         /* BB FIXME END BB */
962
963         pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
964         pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
965         count += name_len;
966         pSMB->hdr.smb_buf_length += count;
967
968         pSMB->ByteCount = cpu_to_le16(count);
969         /* long_op set to 1 to allow for oplock break timeouts */
970         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
971                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
972         cifs_stats_inc(&tcon->num_opens);
973         if (rc) {
974                 cFYI(1, ("Error in Open = %d", rc));
975         } else {
976         /* BB verify if wct == 15 */
977
978 /*              *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
979
980                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
981                 /* Let caller know file was created so we can set the mode. */
982                 /* Do we care about the CreateAction in any other cases? */
983         /* BB FIXME BB */
984 /*              if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
985                         *pOplock |= CIFS_CREATE_ACTION; */
986         /* BB FIXME END */
987
988                 if(pfile_info) {
989                         pfile_info->CreationTime = 0; /* BB convert CreateTime*/
990                         pfile_info->LastAccessTime = 0; /* BB fixme */
991                         pfile_info->LastWriteTime = 0; /* BB fixme */
992                         pfile_info->ChangeTime = 0;  /* BB fixme */
993                         pfile_info->Attributes =
994                                 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
995                         /* the file_info buf is endian converted by caller */
996                         pfile_info->AllocationSize =
997                                 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
998                         pfile_info->EndOfFile = pfile_info->AllocationSize;
999                         pfile_info->NumberOfLinks = cpu_to_le32(1);
1000                 }
1001         }
1002
1003         cifs_buf_release(pSMB);
1004         if (rc == -EAGAIN)
1005                 goto OldOpenRetry;
1006         return rc;
1007 }
1008
1009 int
1010 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1011             const char *fileName, const int openDisposition,
1012             const int access_flags, const int create_options, __u16 * netfid,
1013             int *pOplock, FILE_ALL_INFO * pfile_info, 
1014             const struct nls_table *nls_codepage, int remap)
1015 {
1016         int rc = -EACCES;
1017         OPEN_REQ *pSMB = NULL;
1018         OPEN_RSP *pSMBr = NULL;
1019         int bytes_returned;
1020         int name_len;
1021         __u16 count;
1022
1023 openRetry:
1024         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1025                       (void **) &pSMBr);
1026         if (rc)
1027                 return rc;
1028
1029         pSMB->AndXCommand = 0xFF;       /* none */
1030
1031         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1032                 count = 1;      /* account for one byte pad to word boundary */
1033                 name_len =
1034                     cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1035                                      fileName, PATH_MAX, nls_codepage, remap);
1036                 name_len++;     /* trailing null */
1037                 name_len *= 2;
1038                 pSMB->NameLength = cpu_to_le16(name_len);
1039         } else {                /* BB improve check for buffer overruns BB */
1040                 count = 0;      /* no pad */
1041                 name_len = strnlen(fileName, PATH_MAX);
1042                 name_len++;     /* trailing null */
1043                 pSMB->NameLength = cpu_to_le16(name_len);
1044                 strncpy(pSMB->fileName, fileName, name_len);
1045         }
1046         if (*pOplock & REQ_OPLOCK)
1047                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1048         else if (*pOplock & REQ_BATCHOPLOCK) {
1049                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1050         }
1051         pSMB->DesiredAccess = cpu_to_le32(access_flags);
1052         pSMB->AllocationSize = 0;
1053         /* set file as system file if special file such
1054            as fifo and server expecting SFU style and
1055            no Unix extensions */
1056         if(create_options & CREATE_OPTION_SPECIAL)
1057                 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1058         else
1059                 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1060         /* XP does not handle ATTR_POSIX_SEMANTICS */
1061         /* but it helps speed up case sensitive checks for other
1062         servers such as Samba */
1063         if (tcon->ses->capabilities & CAP_UNIX)
1064                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1065
1066         /* if ((omode & S_IWUGO) == 0)
1067                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1068         /*  Above line causes problems due to vfs splitting create into two
1069                 pieces - need to set mode after file created not while it is
1070                 being created */
1071         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1072         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1073         pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1074         /* BB Expirement with various impersonation levels and verify */
1075         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1076         pSMB->SecurityFlags =
1077             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1078
1079         count += name_len;
1080         pSMB->hdr.smb_buf_length += count;
1081
1082         pSMB->ByteCount = cpu_to_le16(count);
1083         /* long_op set to 1 to allow for oplock break timeouts */
1084         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1085                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1086         cifs_stats_inc(&tcon->num_opens);
1087         if (rc) {
1088                 cFYI(1, ("Error in Open = %d", rc));
1089         } else {
1090                 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1091                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1092                 /* Let caller know file was created so we can set the mode. */
1093                 /* Do we care about the CreateAction in any other cases? */
1094                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1095                         *pOplock |= CIFS_CREATE_ACTION; 
1096                 if(pfile_info) {
1097                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1098                         36 /* CreationTime to Attributes */);
1099                     /* the file_info buf is endian converted by caller */
1100                     pfile_info->AllocationSize = pSMBr->AllocationSize;
1101                     pfile_info->EndOfFile = pSMBr->EndOfFile;
1102                     pfile_info->NumberOfLinks = cpu_to_le32(1);
1103                 }
1104         }
1105
1106         cifs_buf_release(pSMB);
1107         if (rc == -EAGAIN)
1108                 goto openRetry;
1109         return rc;
1110 }
1111
1112 int
1113 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
1114             const int netfid, const unsigned int count,
1115             const __u64 lseek, unsigned int *nbytes, char **buf,
1116             int * pbuf_type)
1117 {
1118         int rc = -EACCES;
1119         READ_REQ *pSMB = NULL;
1120         READ_RSP *pSMBr = NULL;
1121         char *pReadData = NULL;
1122         int wct;
1123         int resp_buf_type = 0;
1124         struct kvec iov[1];
1125
1126         cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1127         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1128                 wct = 12;
1129         else
1130                 wct = 10; /* old style read */
1131
1132         *nbytes = 0;
1133         rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1134         if (rc)
1135                 return rc;
1136
1137         /* tcon and ses pointer are checked in smb_init */
1138         if (tcon->ses->server == NULL)
1139                 return -ECONNABORTED;
1140
1141         pSMB->AndXCommand = 0xFF;       /* none */
1142         pSMB->Fid = netfid;
1143         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1144         if(wct == 12)
1145                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1146         else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1147                 return -EIO;
1148
1149         pSMB->Remaining = 0;
1150         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1151         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1152         if(wct == 12)
1153                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1154         else {
1155                 /* old style read */
1156                 struct smb_com_readx_req * pSMBW =
1157                         (struct smb_com_readx_req *)pSMB;
1158                 pSMBW->ByteCount = 0;
1159         }
1160
1161         iov[0].iov_base = (char *)pSMB;
1162         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1163         rc = SendReceive2(xid, tcon->ses, iov, 
1164                           1 /* num iovecs */,
1165                           &resp_buf_type, 0); 
1166         cifs_stats_inc(&tcon->num_reads);
1167         pSMBr = (READ_RSP *)iov[0].iov_base;
1168         if (rc) {
1169                 cERROR(1, ("Send error in read = %d", rc));
1170         } else {
1171                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1172                 data_length = data_length << 16;
1173                 data_length += le16_to_cpu(pSMBr->DataLength);
1174                 *nbytes = data_length;
1175
1176                 /*check that DataLength would not go beyond end of SMB */
1177                 if ((data_length > CIFSMaxBufSize)
1178                                 || (data_length > count)) {
1179                         cFYI(1,("bad length %d for count %d",data_length,count));
1180                         rc = -EIO;
1181                         *nbytes = 0;
1182                 } else {
1183                         pReadData = (char *) (&pSMBr->hdr.Protocol) +
1184                             le16_to_cpu(pSMBr->DataOffset);
1185 /*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
1186                                 cERROR(1,("Faulting on read rc = %d",rc));
1187                                 rc = -EFAULT;
1188                         }*/ /* can not use copy_to_user when using page cache*/
1189                         if(*buf)
1190                                 memcpy(*buf,pReadData,data_length);
1191                 }
1192         }
1193
1194 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1195         if(*buf) {
1196                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1197                         cifs_small_buf_release(iov[0].iov_base);
1198                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1199                         cifs_buf_release(iov[0].iov_base);
1200         } else if(resp_buf_type != CIFS_NO_BUFFER) {
1201                 /* return buffer to caller to free */ 
1202                 *buf = iov[0].iov_base;         
1203                 if(resp_buf_type == CIFS_SMALL_BUFFER)
1204                         *pbuf_type = CIFS_SMALL_BUFFER;
1205                 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1206                         *pbuf_type = CIFS_LARGE_BUFFER;
1207         } /* else no valid buffer on return - leave as null */
1208
1209         /* Note: On -EAGAIN error only caller can retry on handle based calls
1210                 since file handle passed in no longer valid */
1211         return rc;
1212 }
1213
1214
1215 int
1216 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1217              const int netfid, const unsigned int count,
1218              const __u64 offset, unsigned int *nbytes, const char *buf,
1219              const char __user * ubuf, const int long_op)
1220 {
1221         int rc = -EACCES;
1222         WRITE_REQ *pSMB = NULL;
1223         WRITE_RSP *pSMBr = NULL;
1224         int bytes_returned, wct;
1225         __u32 bytes_sent;
1226         __u16 byte_count;
1227
1228         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1229         if(tcon->ses == NULL)
1230                 return -ECONNABORTED;
1231
1232         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1233                 wct = 14;
1234         else
1235                 wct = 12;
1236
1237         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1238                       (void **) &pSMBr);
1239         if (rc)
1240                 return rc;
1241         /* tcon and ses pointer are checked in smb_init */
1242         if (tcon->ses->server == NULL)
1243                 return -ECONNABORTED;
1244
1245         pSMB->AndXCommand = 0xFF;       /* none */
1246         pSMB->Fid = netfid;
1247         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1248         if(wct == 14) 
1249                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1250         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1251                 return -EIO;
1252         
1253         pSMB->Reserved = 0xFFFFFFFF;
1254         pSMB->WriteMode = 0;
1255         pSMB->Remaining = 0;
1256
1257         /* Can increase buffer size if buffer is big enough in some cases - ie we 
1258         can send more if LARGE_WRITE_X capability returned by the server and if
1259         our buffer is big enough or if we convert to iovecs on socket writes
1260         and eliminate the copy to the CIFS buffer */
1261         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1262                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1263         } else {
1264                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1265                          & ~0xFF;
1266         }
1267
1268         if (bytes_sent > count)
1269                 bytes_sent = count;
1270         pSMB->DataOffset =
1271                 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1272         if(buf)
1273             memcpy(pSMB->Data,buf,bytes_sent);
1274         else if(ubuf) {
1275                 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1276                         cifs_buf_release(pSMB);
1277                         return -EFAULT;
1278                 }
1279         } else if (count != 0) {
1280                 /* No buffer */
1281                 cifs_buf_release(pSMB);
1282                 return -EINVAL;
1283         } /* else setting file size with write of zero bytes */
1284         if(wct == 14)
1285                 byte_count = bytes_sent + 1; /* pad */
1286         else /* wct == 12 */ {
1287                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1288         }
1289         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1290         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1291         pSMB->hdr.smb_buf_length += byte_count;
1292
1293         if(wct == 14)
1294                 pSMB->ByteCount = cpu_to_le16(byte_count);
1295         else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
1296                 struct smb_com_writex_req * pSMBW = 
1297                         (struct smb_com_writex_req *)pSMB;
1298                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1299         }
1300
1301         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1302                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1303         cifs_stats_inc(&tcon->num_writes);
1304         if (rc) {
1305                 cFYI(1, ("Send error in write = %d", rc));
1306                 *nbytes = 0;
1307         } else {
1308                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1309                 *nbytes = (*nbytes) << 16;
1310                 *nbytes += le16_to_cpu(pSMBr->Count);
1311         }
1312
1313         cifs_buf_release(pSMB);
1314
1315         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1316                 since file handle passed in no longer valid */
1317
1318         return rc;
1319 }
1320
1321 int
1322 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1323              const int netfid, const unsigned int count,
1324              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1325              int n_vec, const int long_op)
1326 {
1327         int rc = -EACCES;
1328         WRITE_REQ *pSMB = NULL;
1329         int wct;
1330         int smb_hdr_len;
1331         int resp_buf_type = 0;
1332
1333         cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1334
1335         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1336                 wct = 14;
1337         else
1338                 wct = 12;
1339         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1340         if (rc)
1341                 return rc;
1342         /* tcon and ses pointer are checked in smb_init */
1343         if (tcon->ses->server == NULL)
1344                 return -ECONNABORTED;
1345
1346         pSMB->AndXCommand = 0xFF;       /* none */
1347         pSMB->Fid = netfid;
1348         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1349         if(wct == 14)
1350                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1351         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1352                 return -EIO;
1353         pSMB->Reserved = 0xFFFFFFFF;
1354         pSMB->WriteMode = 0;
1355         pSMB->Remaining = 0;
1356
1357         pSMB->DataOffset =
1358             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1359
1360         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1361         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1362         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1363         if(wct == 14)
1364                 pSMB->hdr.smb_buf_length += count+1;
1365         else /* wct == 12 */
1366                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
1367         if(wct == 14)
1368                 pSMB->ByteCount = cpu_to_le16(count + 1);
1369         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1370                 struct smb_com_writex_req * pSMBW =
1371                                 (struct smb_com_writex_req *)pSMB;
1372                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1373         }
1374         iov[0].iov_base = pSMB;
1375         if(wct == 14)
1376                 iov[0].iov_len = smb_hdr_len + 4;
1377         else /* wct == 12 pad bigger by four bytes */
1378                 iov[0].iov_len = smb_hdr_len + 8;
1379         
1380
1381         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1382                           long_op);
1383         cifs_stats_inc(&tcon->num_writes);
1384         if (rc) {
1385                 cFYI(1, ("Send error Write2 = %d", rc));
1386                 *nbytes = 0;
1387         } else if(resp_buf_type == 0) {
1388                 /* presumably this can not happen, but best to be safe */
1389                 rc = -EIO;
1390                 *nbytes = 0;
1391         } else {
1392                 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1393                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1394                 *nbytes = (*nbytes) << 16;
1395                 *nbytes += le16_to_cpu(pSMBr->Count);
1396         } 
1397
1398 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1399         if(resp_buf_type == CIFS_SMALL_BUFFER)
1400                 cifs_small_buf_release(iov[0].iov_base);
1401         else if(resp_buf_type == CIFS_LARGE_BUFFER)
1402                 cifs_buf_release(iov[0].iov_base);
1403
1404         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1405                 since file handle passed in no longer valid */
1406
1407         return rc;
1408 }
1409
1410
1411 int
1412 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1413             const __u16 smb_file_id, const __u64 len,
1414             const __u64 offset, const __u32 numUnlock,
1415             const __u32 numLock, const __u8 lockType, const int waitFlag)
1416 {
1417         int rc = 0;
1418         LOCK_REQ *pSMB = NULL;
1419         LOCK_RSP *pSMBr = NULL;
1420         int bytes_returned;
1421         int timeout = 0;
1422         __u16 count;
1423
1424         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1425         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1426
1427         if (rc)
1428                 return rc;
1429
1430         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1431
1432         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1433                 timeout = -1; /* no response expected */
1434                 pSMB->Timeout = 0;
1435         } else if (waitFlag == TRUE) {
1436                 timeout = 3;  /* blocking operation, no timeout */
1437                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1438         } else {
1439                 pSMB->Timeout = 0;
1440         }
1441
1442         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1443         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1444         pSMB->LockType = lockType;
1445         pSMB->AndXCommand = 0xFF;       /* none */
1446         pSMB->Fid = smb_file_id; /* netfid stays le */
1447
1448         if((numLock != 0) || (numUnlock != 0)) {
1449                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1450                 /* BB where to store pid high? */
1451                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1452                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1453                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1454                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1455                 count = sizeof(LOCKING_ANDX_RANGE);
1456         } else {
1457                 /* oplock break */
1458                 count = 0;
1459         }
1460         pSMB->hdr.smb_buf_length += count;
1461         pSMB->ByteCount = cpu_to_le16(count);
1462
1463         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1464                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1465         cifs_stats_inc(&tcon->num_locks);
1466         if (rc) {
1467                 cFYI(1, ("Send error in Lock = %d", rc));
1468         }
1469         cifs_small_buf_release(pSMB);
1470
1471         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1472         since file handle passed in no longer valid */
1473         return rc;
1474 }
1475
1476 int
1477 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1478                 const __u16 smb_file_id, const int get_flag, const __u64 len,
1479                 struct file_lock *pLockData, const __u16 lock_type, 
1480                 const int waitFlag)
1481 {
1482         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1483         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1484         char *data_offset;
1485         struct cifs_posix_lock *parm_data;
1486         int rc = 0;
1487         int bytes_returned = 0;
1488         __u16 params, param_offset, offset, byte_count, count;
1489
1490         cFYI(1, ("Posix Lock"));
1491
1492         if(pLockData == NULL)
1493                 return EINVAL;
1494
1495         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1496
1497         if (rc)
1498                 return rc;
1499
1500         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1501
1502         params = 6; 
1503         pSMB->MaxSetupCount = 0;
1504         pSMB->Reserved = 0;
1505         pSMB->Flags = 0;
1506         pSMB->Timeout = 0;
1507         pSMB->Reserved2 = 0;
1508         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1509         offset = param_offset + params;
1510
1511         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1512
1513         count = sizeof(struct cifs_posix_lock);
1514         pSMB->MaxParameterCount = cpu_to_le16(2);
1515         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1516         pSMB->SetupCount = 1;
1517         pSMB->Reserved3 = 0;
1518         if(get_flag)
1519                 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1520         else
1521                 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1522         byte_count = 3 /* pad */  + params + count;
1523         pSMB->DataCount = cpu_to_le16(count);
1524         pSMB->ParameterCount = cpu_to_le16(params);
1525         pSMB->TotalDataCount = pSMB->DataCount;
1526         pSMB->TotalParameterCount = pSMB->ParameterCount;
1527         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1528         parm_data = (struct cifs_posix_lock *) 
1529                         (((char *) &pSMB->hdr.Protocol) + offset);
1530
1531         parm_data->lock_type = cpu_to_le16(lock_type);
1532         if(waitFlag)
1533                 parm_data->lock_flags = cpu_to_le16(1);
1534         parm_data->pid = cpu_to_le32(current->tgid);
1535         parm_data->start = cpu_to_le64(pLockData->fl_start);
1536         parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
1537
1538         pSMB->DataOffset = cpu_to_le16(offset);
1539         pSMB->Fid = smb_file_id;
1540         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1541         pSMB->Reserved4 = 0;
1542         pSMB->hdr.smb_buf_length += byte_count;
1543         pSMB->ByteCount = cpu_to_le16(byte_count);
1544         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1545                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1546         if (rc) {
1547                 cFYI(1, ("Send error in Posix Lock = %d", rc));
1548         } else if (get_flag) {
1549                 /* lock structure can be returned on get */
1550                 __u16 data_offset;
1551                 __u16 data_count;
1552                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1553
1554                 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1555                         rc = -EIO;      /* bad smb */
1556                         goto plk_err_exit;
1557                 }
1558                 if(pLockData == NULL) {
1559                         rc = -EINVAL;
1560                         goto plk_err_exit;
1561                 }
1562                 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1563                 data_count  = le16_to_cpu(pSMBr->t2.DataCount);
1564                 if(data_count < sizeof(struct cifs_posix_lock)) {
1565                         rc = -EIO;
1566                         goto plk_err_exit;
1567                 }
1568                 parm_data = (struct cifs_posix_lock *)
1569                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1570                 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1571                         pLockData->fl_type = F_UNLCK;
1572         }
1573  
1574 plk_err_exit:
1575         if (pSMB)
1576                 cifs_small_buf_release(pSMB);
1577
1578         /* Note: On -EAGAIN error only caller can retry on handle based calls
1579            since file handle passed in no longer valid */
1580
1581         return rc;
1582 }
1583
1584
1585 int
1586 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1587 {
1588         int rc = 0;
1589         CLOSE_REQ *pSMB = NULL;
1590         CLOSE_RSP *pSMBr = NULL;
1591         int bytes_returned;
1592         cFYI(1, ("In CIFSSMBClose"));
1593
1594 /* do not retry on dead session on close */
1595         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1596         if(rc == -EAGAIN)
1597                 return 0;
1598         if (rc)
1599                 return rc;
1600
1601         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1602
1603         pSMB->FileID = (__u16) smb_file_id;
1604         pSMB->LastWriteTime = 0;
1605         pSMB->ByteCount = 0;
1606         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1607                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1608         cifs_stats_inc(&tcon->num_closes);
1609         if (rc) {
1610                 if(rc!=-EINTR) {
1611                         /* EINTR is expected when user ctl-c to kill app */
1612                         cERROR(1, ("Send error in Close = %d", rc));
1613                 }
1614         }
1615
1616         cifs_small_buf_release(pSMB);
1617
1618         /* Since session is dead, file will be closed on server already */
1619         if(rc == -EAGAIN)
1620                 rc = 0;
1621
1622         return rc;
1623 }
1624
1625 int
1626 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1627               const char *fromName, const char *toName,
1628               const struct nls_table *nls_codepage, int remap)
1629 {
1630         int rc = 0;
1631         RENAME_REQ *pSMB = NULL;
1632         RENAME_RSP *pSMBr = NULL;
1633         int bytes_returned;
1634         int name_len, name_len2;
1635         __u16 count;
1636
1637         cFYI(1, ("In CIFSSMBRename"));
1638 renameRetry:
1639         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1640                       (void **) &pSMBr);
1641         if (rc)
1642                 return rc;
1643
1644         pSMB->BufferFormat = 0x04;
1645         pSMB->SearchAttributes =
1646             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1647                         ATTR_DIRECTORY);
1648
1649         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1650                 name_len =
1651                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1652                                      PATH_MAX, nls_codepage, remap);
1653                 name_len++;     /* trailing null */
1654                 name_len *= 2;
1655                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1656         /* protocol requires ASCII signature byte on Unicode string */
1657                 pSMB->OldFileName[name_len + 1] = 0x00;
1658                 name_len2 =
1659                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1660                                      toName, PATH_MAX, nls_codepage, remap);
1661                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1662                 name_len2 *= 2; /* convert to bytes */
1663         } else {                /* BB improve the check for buffer overruns BB */
1664                 name_len = strnlen(fromName, PATH_MAX);
1665                 name_len++;     /* trailing null */
1666                 strncpy(pSMB->OldFileName, fromName, name_len);
1667                 name_len2 = strnlen(toName, PATH_MAX);
1668                 name_len2++;    /* trailing null */
1669                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1670                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1671                 name_len2++;    /* trailing null */
1672                 name_len2++;    /* signature byte */
1673         }
1674
1675         count = 1 /* 1st signature byte */  + name_len + name_len2;
1676         pSMB->hdr.smb_buf_length += count;
1677         pSMB->ByteCount = cpu_to_le16(count);
1678
1679         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1680                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1681         cifs_stats_inc(&tcon->num_renames);
1682         if (rc) {
1683                 cFYI(1, ("Send error in rename = %d", rc));
1684         } 
1685
1686         cifs_buf_release(pSMB);
1687
1688         if (rc == -EAGAIN)
1689                 goto renameRetry;
1690
1691         return rc;
1692 }
1693
1694 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1695                 int netfid, char * target_name, 
1696                 const struct nls_table * nls_codepage, int remap)
1697 {
1698         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1699         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1700         struct set_file_rename * rename_info;
1701         char *data_offset;
1702         char dummy_string[30];
1703         int rc = 0;
1704         int bytes_returned = 0;
1705         int len_of_str;
1706         __u16 params, param_offset, offset, count, byte_count;
1707
1708         cFYI(1, ("Rename to File by handle"));
1709         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1710                         (void **) &pSMBr);
1711         if (rc)
1712                 return rc;
1713
1714         params = 6;
1715         pSMB->MaxSetupCount = 0;
1716         pSMB->Reserved = 0;
1717         pSMB->Flags = 0;
1718         pSMB->Timeout = 0;
1719         pSMB->Reserved2 = 0;
1720         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1721         offset = param_offset + params;
1722
1723         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1724         rename_info = (struct set_file_rename *) data_offset;
1725         pSMB->MaxParameterCount = cpu_to_le16(2);
1726         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1727         pSMB->SetupCount = 1;
1728         pSMB->Reserved3 = 0;
1729         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1730         byte_count = 3 /* pad */  + params;
1731         pSMB->ParameterCount = cpu_to_le16(params);
1732         pSMB->TotalParameterCount = pSMB->ParameterCount;
1733         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1734         pSMB->DataOffset = cpu_to_le16(offset);
1735         /* construct random name ".cifs_tmp<inodenum><mid>" */
1736         rename_info->overwrite = cpu_to_le32(1);
1737         rename_info->root_fid  = 0;
1738         /* unicode only call */
1739         if(target_name == NULL) {
1740                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1741                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1742                                         dummy_string, 24, nls_codepage, remap);
1743         } else {
1744                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1745                                         target_name, PATH_MAX, nls_codepage, remap);
1746         }
1747         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1748         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1749         byte_count += count;
1750         pSMB->DataCount = cpu_to_le16(count);
1751         pSMB->TotalDataCount = pSMB->DataCount;
1752         pSMB->Fid = netfid;
1753         pSMB->InformationLevel =
1754                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1755         pSMB->Reserved4 = 0;
1756         pSMB->hdr.smb_buf_length += byte_count;
1757         pSMB->ByteCount = cpu_to_le16(byte_count);
1758         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1759                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1760         cifs_stats_inc(&pTcon->num_t2renames);
1761         if (rc) {
1762                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1763         }
1764
1765         cifs_buf_release(pSMB);
1766
1767         /* Note: On -EAGAIN error only caller can retry on handle based calls
1768                 since file handle passed in no longer valid */
1769
1770         return rc;
1771 }
1772
1773 int
1774 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1775             const __u16 target_tid, const char *toName, const int flags,
1776             const struct nls_table *nls_codepage, int remap)
1777 {
1778         int rc = 0;
1779         COPY_REQ *pSMB = NULL;
1780         COPY_RSP *pSMBr = NULL;
1781         int bytes_returned;
1782         int name_len, name_len2;
1783         __u16 count;
1784
1785         cFYI(1, ("In CIFSSMBCopy"));
1786 copyRetry:
1787         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1788                         (void **) &pSMBr);
1789         if (rc)
1790                 return rc;
1791
1792         pSMB->BufferFormat = 0x04;
1793         pSMB->Tid2 = target_tid;
1794
1795         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1796
1797         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1798                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1799                                             fromName, PATH_MAX, nls_codepage,
1800                                             remap);
1801                 name_len++;     /* trailing null */
1802                 name_len *= 2;
1803                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1804                 /* protocol requires ASCII signature byte on Unicode string */
1805                 pSMB->OldFileName[name_len + 1] = 0x00;
1806                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1807                                 toName, PATH_MAX, nls_codepage, remap);
1808                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1809                 name_len2 *= 2; /* convert to bytes */
1810         } else {                /* BB improve the check for buffer overruns BB */
1811                 name_len = strnlen(fromName, PATH_MAX);
1812                 name_len++;     /* trailing null */
1813                 strncpy(pSMB->OldFileName, fromName, name_len);
1814                 name_len2 = strnlen(toName, PATH_MAX);
1815                 name_len2++;    /* trailing null */
1816                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1817                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1818                 name_len2++;    /* trailing null */
1819                 name_len2++;    /* signature byte */
1820         }
1821
1822         count = 1 /* 1st signature byte */  + name_len + name_len2;
1823         pSMB->hdr.smb_buf_length += count;
1824         pSMB->ByteCount = cpu_to_le16(count);
1825
1826         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1827                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1828         if (rc) {
1829                 cFYI(1, ("Send error in copy = %d with %d files copied",
1830                         rc, le16_to_cpu(pSMBr->CopyCount)));
1831         }
1832         if (pSMB)
1833                 cifs_buf_release(pSMB);
1834
1835         if (rc == -EAGAIN)
1836                 goto copyRetry;
1837
1838         return rc;
1839 }
1840
1841 int
1842 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1843                       const char *fromName, const char *toName,
1844                       const struct nls_table *nls_codepage)
1845 {
1846         TRANSACTION2_SPI_REQ *pSMB = NULL;
1847         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1848         char *data_offset;
1849         int name_len;
1850         int name_len_target;
1851         int rc = 0;
1852         int bytes_returned = 0;
1853         __u16 params, param_offset, offset, byte_count;
1854
1855         cFYI(1, ("In Symlink Unix style"));
1856 createSymLinkRetry:
1857         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1858                       (void **) &pSMBr);
1859         if (rc)
1860                 return rc;
1861
1862         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1863                 name_len =
1864                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1865                                   /* find define for this maxpathcomponent */
1866                                   , nls_codepage);
1867                 name_len++;     /* trailing null */
1868                 name_len *= 2;
1869
1870         } else {                /* BB improve the check for buffer overruns BB */
1871                 name_len = strnlen(fromName, PATH_MAX);
1872                 name_len++;     /* trailing null */
1873                 strncpy(pSMB->FileName, fromName, name_len);
1874         }
1875         params = 6 + name_len;
1876         pSMB->MaxSetupCount = 0;
1877         pSMB->Reserved = 0;
1878         pSMB->Flags = 0;
1879         pSMB->Timeout = 0;
1880         pSMB->Reserved2 = 0;
1881         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1882                                      InformationLevel) - 4;
1883         offset = param_offset + params;
1884
1885         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1886         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1887                 name_len_target =
1888                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1889                                   /* find define for this maxpathcomponent */
1890                                   , nls_codepage);
1891                 name_len_target++;      /* trailing null */
1892                 name_len_target *= 2;
1893         } else {                /* BB improve the check for buffer overruns BB */
1894                 name_len_target = strnlen(toName, PATH_MAX);
1895                 name_len_target++;      /* trailing null */
1896                 strncpy(data_offset, toName, name_len_target);
1897         }
1898
1899         pSMB->MaxParameterCount = cpu_to_le16(2);
1900         /* BB find exact max on data count below from sess */
1901         pSMB->MaxDataCount = cpu_to_le16(1000);
1902         pSMB->SetupCount = 1;
1903         pSMB->Reserved3 = 0;
1904         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1905         byte_count = 3 /* pad */  + params + name_len_target;
1906         pSMB->DataCount = cpu_to_le16(name_len_target);
1907         pSMB->ParameterCount = cpu_to_le16(params);
1908         pSMB->TotalDataCount = pSMB->DataCount;
1909         pSMB->TotalParameterCount = pSMB->ParameterCount;
1910         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1911         pSMB->DataOffset = cpu_to_le16(offset);
1912         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1913         pSMB->Reserved4 = 0;
1914         pSMB->hdr.smb_buf_length += byte_count;
1915         pSMB->ByteCount = cpu_to_le16(byte_count);
1916         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1917                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1918         cifs_stats_inc(&tcon->num_symlinks);
1919         if (rc) {
1920                 cFYI(1,
1921                      ("Send error in SetPathInfo (create symlink) = %d",
1922                       rc));
1923         }
1924
1925         if (pSMB)
1926                 cifs_buf_release(pSMB);
1927
1928         if (rc == -EAGAIN)
1929                 goto createSymLinkRetry;
1930
1931         return rc;
1932 }
1933
1934 int
1935 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1936                        const char *fromName, const char *toName,
1937                        const struct nls_table *nls_codepage, int remap)
1938 {
1939         TRANSACTION2_SPI_REQ *pSMB = NULL;
1940         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1941         char *data_offset;
1942         int name_len;
1943         int name_len_target;
1944         int rc = 0;
1945         int bytes_returned = 0;
1946         __u16 params, param_offset, offset, byte_count;
1947
1948         cFYI(1, ("In Create Hard link Unix style"));
1949 createHardLinkRetry:
1950         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1951                       (void **) &pSMBr);
1952         if (rc)
1953                 return rc;
1954
1955         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1956                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1957                                             PATH_MAX, nls_codepage, remap);
1958                 name_len++;     /* trailing null */
1959                 name_len *= 2;
1960
1961         } else {                /* BB improve the check for buffer overruns BB */
1962                 name_len = strnlen(toName, PATH_MAX);
1963                 name_len++;     /* trailing null */
1964                 strncpy(pSMB->FileName, toName, name_len);
1965         }
1966         params = 6 + name_len;
1967         pSMB->MaxSetupCount = 0;
1968         pSMB->Reserved = 0;
1969         pSMB->Flags = 0;
1970         pSMB->Timeout = 0;
1971         pSMB->Reserved2 = 0;
1972         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1973                                      InformationLevel) - 4;
1974         offset = param_offset + params;
1975
1976         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1977         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1978                 name_len_target =
1979                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1980                                      nls_codepage, remap);
1981                 name_len_target++;      /* trailing null */
1982                 name_len_target *= 2;
1983         } else {                /* BB improve the check for buffer overruns BB */
1984                 name_len_target = strnlen(fromName, PATH_MAX);
1985                 name_len_target++;      /* trailing null */
1986                 strncpy(data_offset, fromName, name_len_target);
1987         }
1988
1989         pSMB->MaxParameterCount = cpu_to_le16(2);
1990         /* BB find exact max on data count below from sess*/
1991         pSMB->MaxDataCount = cpu_to_le16(1000);
1992         pSMB->SetupCount = 1;
1993         pSMB->Reserved3 = 0;
1994         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1995         byte_count = 3 /* pad */  + params + name_len_target;
1996         pSMB->ParameterCount = cpu_to_le16(params);
1997         pSMB->TotalParameterCount = pSMB->ParameterCount;
1998         pSMB->DataCount = cpu_to_le16(name_len_target);
1999         pSMB->TotalDataCount = pSMB->DataCount;
2000         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2001         pSMB->DataOffset = cpu_to_le16(offset);
2002         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2003         pSMB->Reserved4 = 0;
2004         pSMB->hdr.smb_buf_length += byte_count;
2005         pSMB->ByteCount = cpu_to_le16(byte_count);
2006         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2007                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2008         cifs_stats_inc(&tcon->num_hardlinks);
2009         if (rc) {
2010                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2011         }
2012
2013         cifs_buf_release(pSMB);
2014         if (rc == -EAGAIN)
2015                 goto createHardLinkRetry;
2016
2017         return rc;
2018 }
2019
2020 int
2021 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2022                    const char *fromName, const char *toName,
2023                    const struct nls_table *nls_codepage, int remap)
2024 {
2025         int rc = 0;
2026         NT_RENAME_REQ *pSMB = NULL;
2027         RENAME_RSP *pSMBr = NULL;
2028         int bytes_returned;
2029         int name_len, name_len2;
2030         __u16 count;
2031
2032         cFYI(1, ("In CIFSCreateHardLink"));
2033 winCreateHardLinkRetry:
2034
2035         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2036                       (void **) &pSMBr);
2037         if (rc)
2038                 return rc;
2039
2040         pSMB->SearchAttributes =
2041             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2042                         ATTR_DIRECTORY);
2043         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2044         pSMB->ClusterCount = 0;
2045
2046         pSMB->BufferFormat = 0x04;
2047
2048         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2049                 name_len =
2050                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2051                                      PATH_MAX, nls_codepage, remap);
2052                 name_len++;     /* trailing null */
2053                 name_len *= 2;
2054                 pSMB->OldFileName[name_len] = 0;        /* pad */
2055                 pSMB->OldFileName[name_len + 1] = 0x04; 
2056                 name_len2 =
2057                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
2058                                      toName, PATH_MAX, nls_codepage, remap);
2059                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2060                 name_len2 *= 2; /* convert to bytes */
2061         } else {                /* BB improve the check for buffer overruns BB */
2062                 name_len = strnlen(fromName, PATH_MAX);
2063                 name_len++;     /* trailing null */
2064                 strncpy(pSMB->OldFileName, fromName, name_len);
2065                 name_len2 = strnlen(toName, PATH_MAX);
2066                 name_len2++;    /* trailing null */
2067                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
2068                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2069                 name_len2++;    /* trailing null */
2070                 name_len2++;    /* signature byte */
2071         }
2072
2073         count = 1 /* string type byte */  + name_len + name_len2;
2074         pSMB->hdr.smb_buf_length += count;
2075         pSMB->ByteCount = cpu_to_le16(count);
2076
2077         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2078                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2079         cifs_stats_inc(&tcon->num_hardlinks);
2080         if (rc) {
2081                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2082         }
2083         cifs_buf_release(pSMB);
2084         if (rc == -EAGAIN)
2085                 goto winCreateHardLinkRetry;
2086
2087         return rc;
2088 }
2089
2090 int
2091 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2092                         const unsigned char *searchName,
2093                         char *symlinkinfo, const int buflen,
2094                         const struct nls_table *nls_codepage)
2095 {
2096 /* SMB_QUERY_FILE_UNIX_LINK */
2097         TRANSACTION2_QPI_REQ *pSMB = NULL;
2098         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2099         int rc = 0;
2100         int bytes_returned;
2101         int name_len;
2102         __u16 params, byte_count;
2103
2104         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2105
2106 querySymLinkRetry:
2107         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2108                       (void **) &pSMBr);
2109         if (rc)
2110                 return rc;
2111
2112         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2113                 name_len =
2114                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2115                                   /* find define for this maxpathcomponent */
2116                                   , nls_codepage);
2117                 name_len++;     /* trailing null */
2118                 name_len *= 2;
2119         } else {                /* BB improve the check for buffer overruns BB */
2120                 name_len = strnlen(searchName, PATH_MAX);
2121                 name_len++;     /* trailing null */
2122                 strncpy(pSMB->FileName, searchName, name_len);
2123         }
2124
2125         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2126         pSMB->TotalDataCount = 0;
2127         pSMB->MaxParameterCount = cpu_to_le16(2);
2128         /* BB find exact max data count below from sess structure BB */
2129         pSMB->MaxDataCount = cpu_to_le16(4000);
2130         pSMB->MaxSetupCount = 0;
2131         pSMB->Reserved = 0;
2132         pSMB->Flags = 0;
2133         pSMB->Timeout = 0;
2134         pSMB->Reserved2 = 0;
2135         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2136         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2137         pSMB->DataCount = 0;
2138         pSMB->DataOffset = 0;
2139         pSMB->SetupCount = 1;
2140         pSMB->Reserved3 = 0;
2141         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2142         byte_count = params + 1 /* pad */ ;
2143         pSMB->TotalParameterCount = cpu_to_le16(params);
2144         pSMB->ParameterCount = pSMB->TotalParameterCount;
2145         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2146         pSMB->Reserved4 = 0;
2147         pSMB->hdr.smb_buf_length += byte_count;
2148         pSMB->ByteCount = cpu_to_le16(byte_count);
2149
2150         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2151                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2152         if (rc) {
2153                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2154         } else {
2155                 /* decode response */
2156
2157                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2158                 if (rc || (pSMBr->ByteCount < 2))
2159                 /* BB also check enough total bytes returned */
2160                         rc = -EIO;      /* bad smb */
2161                 else {
2162                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2163                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2164
2165                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2166                                 name_len = UniStrnlen((wchar_t *) ((char *)
2167                                         &pSMBr->hdr.Protocol +data_offset),
2168                                         min_t(const int, buflen,count) / 2);
2169                         /* BB FIXME investigate remapping reserved chars here */
2170                                 cifs_strfromUCS_le(symlinkinfo,
2171                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol +
2172                                                 data_offset),
2173                                         name_len, nls_codepage);
2174                         } else {
2175                                 strncpy(symlinkinfo,
2176                                         (char *) &pSMBr->hdr.Protocol + 
2177                                                 data_offset,
2178                                         min_t(const int, buflen, count));
2179                         }
2180                         symlinkinfo[buflen] = 0;
2181         /* just in case so calling code does not go off the end of buffer */
2182                 }
2183         }
2184         cifs_buf_release(pSMB);
2185         if (rc == -EAGAIN)
2186                 goto querySymLinkRetry;
2187         return rc;
2188 }
2189
2190 /* Initialize NT TRANSACT SMB into small smb request buffer.
2191    This assumes that all NT TRANSACTS that we init here have
2192    total parm and data under about 400 bytes (to fit in small cifs
2193    buffer size), which is the case so far, it easily fits. NB:
2194         Setup words themselves and ByteCount
2195         MaxSetupCount (size of returned setup area) and
2196         MaxParameterCount (returned parms size) must be set by caller */
2197 static int 
2198 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2199                    const int parm_len, struct cifsTconInfo *tcon,
2200                    void ** ret_buf)
2201 {
2202         int rc;
2203         __u32 temp_offset;
2204         struct smb_com_ntransact_req * pSMB;
2205
2206         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2207                                 (void **)&pSMB);
2208         if (rc)
2209                 return rc;
2210         *ret_buf = (void *)pSMB;
2211         pSMB->Reserved = 0;
2212         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2213         pSMB->TotalDataCount  = 0;
2214         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2215                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2216         pSMB->ParameterCount = pSMB->TotalParameterCount;
2217         pSMB->DataCount  = pSMB->TotalDataCount;
2218         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2219                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
2220         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2221         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2222         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2223         pSMB->SubCommand = cpu_to_le16(sub_command);
2224         return 0;
2225 }
2226
2227 static int
2228 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2229                    int * pdatalen, int * pparmlen)
2230 {
2231         char * end_of_smb;
2232         __u32 data_count, data_offset, parm_count, parm_offset;
2233         struct smb_com_ntransact_rsp * pSMBr;
2234
2235         if(buf == NULL)
2236                 return -EINVAL;
2237
2238         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2239
2240         /* ByteCount was converted from little endian in SendReceive */
2241         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + 
2242                         (char *)&pSMBr->ByteCount;
2243
2244                 
2245         data_offset = le32_to_cpu(pSMBr->DataOffset);
2246         data_count = le32_to_cpu(pSMBr->DataCount);
2247         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2248         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2249
2250         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2251         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2252
2253         /* should we also check that parm and data areas do not overlap? */
2254         if(*ppparm > end_of_smb) {
2255                 cFYI(1,("parms start after end of smb"));
2256                 return -EINVAL;
2257         } else if(parm_count + *ppparm > end_of_smb) {
2258                 cFYI(1,("parm end after end of smb"));
2259                 return -EINVAL;
2260         } else if(*ppdata > end_of_smb) {
2261                 cFYI(1,("data starts after end of smb"));
2262                 return -EINVAL;
2263         } else if(data_count + *ppdata > end_of_smb) {
2264                 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2265                         *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr));  /* BB FIXME */
2266                 return -EINVAL;
2267         } else if(parm_count + data_count > pSMBr->ByteCount) {
2268                 cFYI(1,("parm count and data count larger than SMB"));
2269                 return -EINVAL;
2270         }
2271         return 0;
2272 }
2273
2274 int
2275 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2276                         const unsigned char *searchName,
2277                         char *symlinkinfo, const int buflen,__u16 fid,
2278                         const struct nls_table *nls_codepage)
2279 {
2280         int rc = 0;
2281         int bytes_returned;
2282         int name_len;
2283         struct smb_com_transaction_ioctl_req * pSMB;
2284         struct smb_com_transaction_ioctl_rsp * pSMBr;
2285
2286         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2287         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2288                       (void **) &pSMBr);
2289         if (rc)
2290                 return rc;
2291
2292         pSMB->TotalParameterCount = 0 ;
2293         pSMB->TotalDataCount = 0;
2294         pSMB->MaxParameterCount = cpu_to_le32(2);
2295         /* BB find exact data count max from sess structure BB */
2296         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2297                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2298         pSMB->MaxSetupCount = 4;
2299         pSMB->Reserved = 0;
2300         pSMB->ParameterOffset = 0;
2301         pSMB->DataCount = 0;
2302         pSMB->DataOffset = 0;
2303         pSMB->SetupCount = 4;
2304         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2305         pSMB->ParameterCount = pSMB->TotalParameterCount;
2306         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2307         pSMB->IsFsctl = 1; /* FSCTL */
2308         pSMB->IsRootFlag = 0;
2309         pSMB->Fid = fid; /* file handle always le */
2310         pSMB->ByteCount = 0;
2311
2312         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2313                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2314         if (rc) {
2315                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2316         } else {                /* decode response */
2317                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2318                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2319                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2320                 /* BB also check enough total bytes returned */
2321                         rc = -EIO;      /* bad smb */
2322                 else {
2323                         if(data_count && (data_count < 2048)) {
2324                                 char * end_of_smb = 2 /* sizeof byte count */ +
2325                                                 pSMBr->ByteCount +
2326                                                 (char *)&pSMBr->ByteCount;
2327
2328                                 struct reparse_data * reparse_buf = (struct reparse_data *)
2329                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
2330                                 if((char*)reparse_buf >= end_of_smb) {
2331                                         rc = -EIO;
2332                                         goto qreparse_out;
2333                                 }
2334                                 if((reparse_buf->LinkNamesBuf + 
2335                                         reparse_buf->TargetNameOffset +
2336                                         reparse_buf->TargetNameLen) >
2337                                                 end_of_smb) {
2338                                         cFYI(1,("reparse buf extended beyond SMB"));
2339                                         rc = -EIO;
2340                                         goto qreparse_out;
2341                                 }
2342                                 
2343                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2344                                         name_len = UniStrnlen((wchar_t *)
2345                                                         (reparse_buf->LinkNamesBuf + 
2346                                                         reparse_buf->TargetNameOffset),
2347                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
2348                                         cifs_strfromUCS_le(symlinkinfo,
2349                                                 (__le16 *) (reparse_buf->LinkNamesBuf + 
2350                                                 reparse_buf->TargetNameOffset),
2351                                                 name_len, nls_codepage);
2352                                 } else { /* ASCII names */
2353                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
2354                                                 reparse_buf->TargetNameOffset, 
2355                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
2356                                 }
2357                         } else {
2358                                 rc = -EIO;
2359                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2360                         }
2361                         symlinkinfo[buflen] = 0; /* just in case so the caller
2362                                         does not go off the end of the buffer */
2363                         cFYI(1,("readlink result - %s",symlinkinfo));
2364                 }
2365         }
2366 qreparse_out:
2367         cifs_buf_release(pSMB);
2368
2369         /* Note: On -EAGAIN error only caller can retry on handle based calls
2370                 since file handle passed in no longer valid */
2371
2372         return rc;
2373 }
2374
2375 #ifdef CONFIG_CIFS_POSIX
2376
2377 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2378 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2379 {
2380         /* u8 cifs fields do not need le conversion */
2381         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2382         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2383         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2384         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2385
2386         return;
2387 }
2388
2389 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2390 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2391                                 const int acl_type,const int size_of_data_area)
2392 {
2393         int size =  0;
2394         int i;
2395         __u16 count;
2396         struct cifs_posix_ace * pACE;
2397         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2398         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2399
2400         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2401                 return -EOPNOTSUPP;
2402
2403         if(acl_type & ACL_TYPE_ACCESS) {
2404                 count = le16_to_cpu(cifs_acl->access_entry_count);
2405                 pACE = &cifs_acl->ace_array[0];
2406                 size = sizeof(struct cifs_posix_acl);
2407                 size += sizeof(struct cifs_posix_ace) * count;
2408                 /* check if we would go beyond end of SMB */
2409                 if(size_of_data_area < size) {
2410                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2411                         return -EINVAL;
2412                 }
2413         } else if(acl_type & ACL_TYPE_DEFAULT) {
2414                 count = le16_to_cpu(cifs_acl->access_entry_count);
2415                 size = sizeof(struct cifs_posix_acl);
2416                 size += sizeof(struct cifs_posix_ace) * count;
2417 /* skip past access ACEs to get to default ACEs */
2418                 pACE = &cifs_acl->ace_array[count];
2419                 count = le16_to_cpu(cifs_acl->default_entry_count);
2420                 size += sizeof(struct cifs_posix_ace) * count;
2421                 /* check if we would go beyond end of SMB */
2422                 if(size_of_data_area < size)
2423                         return -EINVAL;
2424         } else {
2425                 /* illegal type */
2426                 return -EINVAL;
2427         }
2428
2429         size = posix_acl_xattr_size(count);
2430         if((buflen == 0) || (local_acl == NULL)) {
2431                 /* used to query ACL EA size */                         
2432         } else if(size > buflen) {
2433                 return -ERANGE;
2434         } else /* buffer big enough */ {
2435                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2436                 for(i = 0;i < count ;i++) {
2437                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2438                         pACE ++;
2439                 }
2440         }
2441         return size;
2442 }
2443
2444 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2445                         const posix_acl_xattr_entry * local_ace)
2446 {
2447         __u16 rc = 0; /* 0 = ACL converted ok */
2448
2449         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2450         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2451         /* BB is there a better way to handle the large uid? */
2452         if(local_ace->e_id == cpu_to_le32(-1)) {
2453         /* Probably no need to le convert -1 on any arch but can not hurt */
2454                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2455         } else 
2456                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2457         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2458         return rc;
2459 }
2460
2461 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2462 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2463                 const int acl_type)
2464 {
2465         __u16 rc = 0;
2466         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2467         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2468         int count;
2469         int i;
2470
2471         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2472                 return 0;
2473
2474         count = posix_acl_xattr_count((size_t)buflen);
2475         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2476                 count, buflen, le32_to_cpu(local_acl->a_version)));
2477         if(le32_to_cpu(local_acl->a_version) != 2) {
2478                 cFYI(1,("unknown POSIX ACL version %d",
2479                      le32_to_cpu(local_acl->a_version)));
2480                 return 0;
2481         }
2482         cifs_acl->version = cpu_to_le16(1);
2483         if(acl_type == ACL_TYPE_ACCESS) 
2484                 cifs_acl->access_entry_count = cpu_to_le16(count);
2485         else if(acl_type == ACL_TYPE_DEFAULT)
2486                 cifs_acl->default_entry_count = cpu_to_le16(count);
2487         else {
2488                 cFYI(1,("unknown ACL type %d",acl_type));
2489                 return 0;
2490         }
2491         for(i=0;i<count;i++) {
2492                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2493                                         &local_acl->a_entries[i]);
2494                 if(rc != 0) {
2495                         /* ACE not converted */
2496                         break;
2497                 }
2498         }
2499         if(rc == 0) {
2500                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2501                 rc += sizeof(struct cifs_posix_acl);
2502                 /* BB add check to make sure ACL does not overflow SMB */
2503         }
2504         return rc;
2505 }
2506
2507 int
2508 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2509                         const unsigned char *searchName,
2510                         char *acl_inf, const int buflen, const int acl_type,
2511                         const struct nls_table *nls_codepage, int remap)
2512 {
2513 /* SMB_QUERY_POSIX_ACL */
2514         TRANSACTION2_QPI_REQ *pSMB = NULL;
2515         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2516         int rc = 0;
2517         int bytes_returned;
2518         int name_len;
2519         __u16 params, byte_count;
2520                                                                                                                                              
2521         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2522
2523 queryAclRetry:
2524         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2525                 (void **) &pSMBr);
2526         if (rc)
2527                 return rc;
2528                                                                                                                                              
2529         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2530                 name_len =
2531                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2532                                          PATH_MAX, nls_codepage, remap);
2533                 name_len++;     /* trailing null */
2534                 name_len *= 2;
2535                 pSMB->FileName[name_len] = 0;
2536                 pSMB->FileName[name_len+1] = 0;
2537         } else {                /* BB improve the check for buffer overruns BB */
2538                 name_len = strnlen(searchName, PATH_MAX);
2539                 name_len++;     /* trailing null */
2540                 strncpy(pSMB->FileName, searchName, name_len);
2541         }
2542
2543         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2544         pSMB->TotalDataCount = 0;
2545         pSMB->MaxParameterCount = cpu_to_le16(2);
2546         /* BB find exact max data count below from sess structure BB */
2547         pSMB->MaxDataCount = cpu_to_le16(4000);
2548         pSMB->MaxSetupCount = 0;
2549         pSMB->Reserved = 0;
2550         pSMB->Flags = 0;
2551         pSMB->Timeout = 0;
2552         pSMB->Reserved2 = 0;
2553         pSMB->ParameterOffset = cpu_to_le16(
2554                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2555         pSMB->DataCount = 0;
2556         pSMB->DataOffset = 0;
2557         pSMB->SetupCount = 1;
2558         pSMB->Reserved3 = 0;
2559         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2560         byte_count = params + 1 /* pad */ ;
2561         pSMB->TotalParameterCount = cpu_to_le16(params);
2562         pSMB->ParameterCount = pSMB->TotalParameterCount;
2563         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2564         pSMB->Reserved4 = 0;
2565         pSMB->hdr.smb_buf_length += byte_count;
2566         pSMB->ByteCount = cpu_to_le16(byte_count);
2567
2568         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2569                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2570         cifs_stats_inc(&tcon->num_acl_get);
2571         if (rc) {
2572                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2573         } else {
2574                 /* decode response */
2575  
2576                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2577                 if (rc || (pSMBr->ByteCount < 2))
2578                 /* BB also check enough total bytes returned */
2579                         rc = -EIO;      /* bad smb */
2580                 else {
2581                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2582                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2583                         rc = cifs_copy_posix_acl(acl_inf,
2584                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2585                                 buflen,acl_type,count);
2586                 }
2587         }
2588         cifs_buf_release(pSMB);
2589         if (rc == -EAGAIN)
2590                 goto queryAclRetry;
2591         return rc;
2592 }
2593
2594 int
2595 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2596                         const unsigned char *fileName,
2597                         const char *local_acl, const int buflen, 
2598                         const int acl_type,
2599                         const struct nls_table *nls_codepage, int remap)
2600 {
2601         struct smb_com_transaction2_spi_req *pSMB = NULL;
2602         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2603         char *parm_data;
2604         int name_len;
2605         int rc = 0;
2606         int bytes_returned = 0;
2607         __u16 params, byte_count, data_count, param_offset, offset;
2608
2609         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2610 setAclRetry:
2611         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2612                       (void **) &pSMBr);
2613         if (rc)
2614                 return rc;
2615         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2616                 name_len =
2617                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2618                                       PATH_MAX, nls_codepage, remap);
2619                 name_len++;     /* trailing null */
2620                 name_len *= 2;
2621         } else {                /* BB improve the check for buffer overruns BB */
2622                 name_len = strnlen(fileName, PATH_MAX);
2623                 name_len++;     /* trailing null */
2624                 strncpy(pSMB->FileName, fileName, name_len);
2625         }
2626         params = 6 + name_len;
2627         pSMB->MaxParameterCount = cpu_to_le16(2);
2628         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2629         pSMB->MaxSetupCount = 0;
2630         pSMB->Reserved = 0;
2631         pSMB->Flags = 0;
2632         pSMB->Timeout = 0;
2633         pSMB->Reserved2 = 0;
2634         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2635                                      InformationLevel) - 4;
2636         offset = param_offset + params;
2637         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2638         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2639
2640         /* convert to on the wire format for POSIX ACL */
2641         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2642
2643         if(data_count == 0) {
2644                 rc = -EOPNOTSUPP;
2645                 goto setACLerrorExit;
2646         }
2647         pSMB->DataOffset = cpu_to_le16(offset);
2648         pSMB->SetupCount = 1;
2649         pSMB->Reserved3 = 0;
2650         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2651         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2652         byte_count = 3 /* pad */  + params + data_count;
2653         pSMB->DataCount = cpu_to_le16(data_count);
2654         pSMB->TotalDataCount = pSMB->DataCount;
2655         pSMB->ParameterCount = cpu_to_le16(params);
2656         pSMB->TotalParameterCount = pSMB->ParameterCount;
2657         pSMB->Reserved4 = 0;
2658         pSMB->hdr.smb_buf_length += byte_count;
2659         pSMB->ByteCount = cpu_to_le16(byte_count);
2660         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2661                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2662         if (rc) {
2663                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2664         }
2665
2666 setACLerrorExit:
2667         cifs_buf_release(pSMB);
2668         if (rc == -EAGAIN)
2669                 goto setAclRetry;
2670         return rc;
2671 }
2672
2673 /* BB fix tabs in this function FIXME BB */
2674 int
2675 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2676                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2677 {
2678         int rc = 0;
2679         struct smb_t2_qfi_req *pSMB = NULL;
2680         struct smb_t2_qfi_rsp *pSMBr = NULL;
2681         int bytes_returned;
2682         __u16 params, byte_count;
2683
2684         cFYI(1,("In GetExtAttr"));
2685         if(tcon == NULL)
2686                 return -ENODEV;
2687
2688 GetExtAttrRetry:
2689         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2690                       (void **) &pSMBr);
2691         if (rc)
2692                 return rc;
2693
2694         params = 2 /* level */ +2 /* fid */;
2695         pSMB->t2.TotalDataCount = 0;
2696         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2697         /* BB find exact max data count below from sess structure BB */
2698         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2699         pSMB->t2.MaxSetupCount = 0;
2700         pSMB->t2.Reserved = 0;
2701         pSMB->t2.Flags = 0;
2702         pSMB->t2.Timeout = 0;
2703         pSMB->t2.Reserved2 = 0;
2704         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2705                         Fid) - 4);
2706         pSMB->t2.DataCount = 0;
2707         pSMB->t2.DataOffset = 0;
2708         pSMB->t2.SetupCount = 1;
2709         pSMB->t2.Reserved3 = 0;
2710         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2711         byte_count = params + 1 /* pad */ ;
2712         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2713         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2714         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2715         pSMB->Pad = 0;
2716         pSMB->Fid = netfid;
2717         pSMB->hdr.smb_buf_length += byte_count;
2718         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2719
2720         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2721                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2722         if (rc) {
2723                 cFYI(1, ("error %d in GetExtAttr", rc));
2724         } else {
2725                 /* decode response */
2726                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2727                 if (rc || (pSMBr->ByteCount < 2))
2728                 /* BB also check enough total bytes returned */
2729                         /* If rc should we check for EOPNOSUPP and
2730                         disable the srvino flag? or in caller? */
2731                         rc = -EIO;      /* bad smb */
2732                 else {
2733                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2734                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2735                         struct file_chattr_info * pfinfo;
2736                         /* BB Do we need a cast or hash here ? */
2737                         if(count != 16) {
2738                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2739                                 rc = -EIO;
2740                                 goto GetExtAttrOut;
2741                         }
2742                         pfinfo = (struct file_chattr_info *)
2743                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2744                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2745                         *pMask = le64_to_cpu(pfinfo->mask);
2746                 }
2747         }
2748 GetExtAttrOut:
2749         cifs_buf_release(pSMB);
2750         if (rc == -EAGAIN)
2751                 goto GetExtAttrRetry;
2752         return rc;
2753 }
2754
2755
2756 #endif /* CONFIG_POSIX */
2757
2758
2759 /* security id for everyone */
2760 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2761 /* group users */
2762 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2763
2764 /* Convert CIFS ACL to POSIX form */
2765 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2766 {
2767         return 0;
2768 }
2769
2770 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2771 int
2772 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2773          /*  BB fix up return info */ char *acl_inf, const int buflen, 
2774                   const int acl_type /* ACCESS/DEFAULT not sure implication */)
2775 {
2776         int rc = 0;
2777         int buf_type = 0;
2778         QUERY_SEC_DESC_REQ * pSMB;
2779         struct kvec iov[1];
2780
2781         cFYI(1, ("GetCifsACL"));
2782
2783         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
2784                         8 /* parm len */, tcon, (void **) &pSMB);
2785         if (rc)
2786                 return rc;
2787
2788         pSMB->MaxParameterCount = cpu_to_le32(4);
2789         /* BB TEST with big acls that might need to be e.g. larger than 16K */
2790         pSMB->MaxSetupCount = 0;
2791         pSMB->Fid = fid; /* file handle always le */
2792         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2793                                      CIFS_ACL_DACL);
2794         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2795         pSMB->hdr.smb_buf_length += 11;
2796         iov[0].iov_base = (char *)pSMB;
2797         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2798
2799         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2800         cifs_stats_inc(&tcon->num_acl_get);
2801         if (rc) {
2802                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2803         } else {                /* decode response */
2804                 struct cifs_sid * psec_desc;
2805                 __le32 * parm;
2806                 int parm_len;
2807                 int data_len;
2808                 int acl_len;
2809                 struct smb_com_ntransact_rsp * pSMBr;
2810
2811 /* validate_nttransact */
2812                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
2813                                         (char **)&psec_desc,
2814                                         &parm_len, &data_len);
2815                 
2816                 if(rc)
2817                         goto qsec_out;
2818                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2819
2820                 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
2821
2822                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2823                         rc = -EIO;      /* bad smb */
2824                         goto qsec_out;
2825                 }
2826
2827 /* BB check that data area is minimum length and as big as acl_len */
2828
2829                 acl_len = le32_to_cpu(*(__le32 *)parm);
2830                 /* BB check if(acl_len > bufsize) */
2831
2832                 parse_sec_desc(psec_desc, acl_len);
2833         }
2834 qsec_out:
2835         if(buf_type == CIFS_SMALL_BUFFER)
2836                 cifs_small_buf_release(iov[0].iov_base);
2837         else if(buf_type == CIFS_LARGE_BUFFER)
2838                 cifs_buf_release(iov[0].iov_base);
2839 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2840         return rc;
2841 }
2842
2843
2844 /* Legacy Query Path Information call for lookup to old servers such
2845    as Win9x/WinME */
2846 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2847                  const unsigned char *searchName,
2848                  FILE_ALL_INFO * pFinfo,
2849                  const struct nls_table *nls_codepage, int remap)
2850 {
2851         QUERY_INFORMATION_REQ * pSMB;
2852         QUERY_INFORMATION_RSP * pSMBr;
2853         int rc = 0;
2854         int bytes_returned;
2855         int name_len;
2856
2857         cFYI(1, ("In SMBQPath path %s", searchName)); 
2858 QInfRetry:
2859         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2860                       (void **) &pSMBr);
2861         if (rc)
2862                 return rc;
2863
2864         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2865                 name_len =
2866                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2867                                      PATH_MAX, nls_codepage, remap);
2868                 name_len++;     /* trailing null */
2869                 name_len *= 2;
2870         } else {               
2871                 name_len = strnlen(searchName, PATH_MAX);
2872                 name_len++;     /* trailing null */
2873                 strncpy(pSMB->FileName, searchName, name_len);
2874         }
2875         pSMB->BufferFormat = 0x04;
2876         name_len++; /* account for buffer type byte */  
2877         pSMB->hdr.smb_buf_length += (__u16) name_len;
2878         pSMB->ByteCount = cpu_to_le16(name_len);
2879
2880         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2881                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2882         if (rc) {
2883                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2884         } else if (pFinfo) {            /* decode response */
2885                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2886                 pFinfo->AllocationSize =
2887                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2888                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2889                 pFinfo->Attributes =
2890                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2891         } else
2892                 rc = -EIO; /* bad buffer passed in */
2893
2894         cifs_buf_release(pSMB);
2895
2896         if (rc == -EAGAIN)
2897                 goto QInfRetry;
2898
2899         return rc;
2900 }
2901
2902
2903
2904
2905 int
2906 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2907                  const unsigned char *searchName,
2908                  FILE_ALL_INFO * pFindData,
2909                  const struct nls_table *nls_codepage, int remap)
2910 {
2911 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2912         TRANSACTION2_QPI_REQ *pSMB = NULL;
2913         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2914         int rc = 0;
2915         int bytes_returned;
2916         int name_len;
2917         __u16 params, byte_count;
2918
2919 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2920 QPathInfoRetry:
2921         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2922                       (void **) &pSMBr);
2923         if (rc)
2924                 return rc;
2925
2926         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2927                 name_len =
2928                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2929                                      PATH_MAX, nls_codepage, remap);
2930                 name_len++;     /* trailing null */
2931                 name_len *= 2;
2932         } else {                /* BB improve the check for buffer overruns BB */
2933                 name_len = strnlen(searchName, PATH_MAX);
2934                 name_len++;     /* trailing null */
2935                 strncpy(pSMB->FileName, searchName, name_len);
2936         }
2937
2938         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2939         pSMB->TotalDataCount = 0;
2940         pSMB->MaxParameterCount = cpu_to_le16(2);
2941         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2942         pSMB->MaxSetupCount = 0;
2943         pSMB->Reserved = 0;
2944         pSMB->Flags = 0;
2945         pSMB->Timeout = 0;
2946         pSMB->Reserved2 = 0;
2947         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2948         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2949         pSMB->DataCount = 0;
2950         pSMB->DataOffset = 0;
2951         pSMB->SetupCount = 1;
2952         pSMB->Reserved3 = 0;
2953         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2954         byte_count = params + 1 /* pad */ ;
2955         pSMB->TotalParameterCount = cpu_to_le16(params);
2956         pSMB->ParameterCount = pSMB->TotalParameterCount;
2957         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2958         pSMB->Reserved4 = 0;
2959         pSMB->hdr.smb_buf_length += byte_count;
2960         pSMB->ByteCount = cpu_to_le16(byte_count);
2961
2962         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2963                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2964         if (rc) {
2965                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2966         } else {                /* decode response */
2967                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2968
2969                 if (rc || (pSMBr->ByteCount < 40)) 
2970                         rc = -EIO;      /* bad smb */
2971                 else if (pFindData){
2972                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2973                         memcpy((char *) pFindData,
2974                                (char *) &pSMBr->hdr.Protocol +
2975                                data_offset, sizeof (FILE_ALL_INFO));
2976                 } else
2977                     rc = -ENOMEM;
2978         }
2979         cifs_buf_release(pSMB);
2980         if (rc == -EAGAIN)
2981                 goto QPathInfoRetry;
2982
2983         return rc;
2984 }
2985
2986 int
2987 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2988                      const unsigned char *searchName,
2989                      FILE_UNIX_BASIC_INFO * pFindData,
2990                      const struct nls_table *nls_codepage, int remap)
2991 {
2992 /* SMB_QUERY_FILE_UNIX_BASIC */
2993         TRANSACTION2_QPI_REQ *pSMB = NULL;
2994         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2995         int rc = 0;
2996         int bytes_returned = 0;
2997         int name_len;
2998         __u16 params, byte_count;
2999
3000         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3001 UnixQPathInfoRetry:
3002         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3003                       (void **) &pSMBr);
3004         if (rc)
3005                 return rc;
3006
3007         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3008                 name_len =
3009                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3010                                   PATH_MAX, nls_codepage, remap);
3011                 name_len++;     /* trailing null */
3012                 name_len *= 2;
3013         } else {                /* BB improve the check for buffer overruns BB */
3014                 name_len = strnlen(searchName, PATH_MAX);
3015                 name_len++;     /* trailing null */
3016                 strncpy(pSMB->FileName, searchName, name_len);
3017         }
3018
3019         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3020         pSMB->TotalDataCount = 0;
3021         pSMB->MaxParameterCount = cpu_to_le16(2);
3022         /* BB find exact max SMB PDU from sess structure BB */
3023         pSMB->MaxDataCount = cpu_to_le16(4000); 
3024         pSMB->MaxSetupCount = 0;
3025         pSMB->Reserved = 0;
3026         pSMB->Flags = 0;
3027         pSMB->Timeout = 0;
3028         pSMB->Reserved2 = 0;
3029         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3030         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3031         pSMB->DataCount = 0;
3032         pSMB->DataOffset = 0;
3033         pSMB->SetupCount = 1;
3034         pSMB->Reserved3 = 0;
3035         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3036         byte_count = params + 1 /* pad */ ;
3037         pSMB->TotalParameterCount = cpu_to_le16(params);
3038         pSMB->ParameterCount = pSMB->TotalParameterCount;
3039         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3040         pSMB->Reserved4 = 0;
3041         pSMB->hdr.smb_buf_length += byte_count;
3042         pSMB->ByteCount = cpu_to_le16(byte_count);
3043
3044         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3045                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3046         if (rc) {
3047                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3048         } else {                /* decode response */
3049                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3050
3051                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3052                         rc = -EIO;      /* bad smb */
3053                 } else {
3054                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3055                         memcpy((char *) pFindData,
3056                                (char *) &pSMBr->hdr.Protocol +
3057                                data_offset,
3058                                sizeof (FILE_UNIX_BASIC_INFO));
3059                 }
3060         }
3061         cifs_buf_release(pSMB);
3062         if (rc == -EAGAIN)
3063                 goto UnixQPathInfoRetry;
3064
3065         return rc;
3066 }
3067
3068 #if 0  /* function unused at present */
3069 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3070                const char *searchName, FILE_ALL_INFO * findData,
3071                const struct nls_table *nls_codepage)
3072 {
3073 /* level 257 SMB_ */
3074         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3075         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3076         int rc = 0;
3077         int bytes_returned;
3078         int name_len;
3079         __u16 params, byte_count;
3080
3081         cFYI(1, ("In FindUnique"));
3082 findUniqueRetry:
3083         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3084                       (void **) &pSMBr);
3085         if (rc)
3086                 return rc;
3087
3088         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3089                 name_len =
3090                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
3091                                   /* find define for this maxpathcomponent */
3092                                   , nls_codepage);
3093                 name_len++;     /* trailing null */
3094                 name_len *= 2;
3095         } else {                /* BB improve the check for buffer overruns BB */
3096                 name_len = strnlen(searchName, PATH_MAX);
3097                 name_len++;     /* trailing null */
3098                 strncpy(pSMB->FileName, searchName, name_len);
3099         }
3100
3101         params = 12 + name_len /* includes null */ ;
3102         pSMB->TotalDataCount = 0;       /* no EAs */
3103         pSMB->MaxParameterCount = cpu_to_le16(2);
3104         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3105         pSMB->MaxSetupCount = 0;
3106         pSMB->Reserved = 0;
3107         pSMB->Flags = 0;
3108         pSMB->Timeout = 0;
3109         pSMB->Reserved2 = 0;
3110         pSMB->ParameterOffset = cpu_to_le16(
3111          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3112         pSMB->DataCount = 0;
3113         pSMB->DataOffset = 0;
3114         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
3115         pSMB->Reserved3 = 0;
3116         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3117         byte_count = params + 1 /* pad */ ;
3118         pSMB->TotalParameterCount = cpu_to_le16(params);
3119         pSMB->ParameterCount = pSMB->TotalParameterCount;
3120         pSMB->SearchAttributes =
3121             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3122                         ATTR_DIRECTORY);
3123         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
3124         pSMB->SearchFlags = cpu_to_le16(1);
3125         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3126         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
3127         pSMB->hdr.smb_buf_length += byte_count;
3128         pSMB->ByteCount = cpu_to_le16(byte_count);
3129
3130         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3131                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3132
3133         if (rc) {
3134                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3135         } else {                /* decode response */
3136                 cifs_stats_inc(&tcon->num_ffirst);
3137                 /* BB fill in */
3138         }
3139
3140         cifs_buf_release(pSMB);
3141         if (rc == -EAGAIN)
3142                 goto findUniqueRetry;
3143
3144         return rc;
3145 }
3146 #endif /* end unused (temporarily) function */
3147
3148 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3149 int
3150 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3151               const char *searchName, 
3152               const struct nls_table *nls_codepage,
3153               __u16 *   pnetfid,
3154               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3155 {
3156 /* level 257 SMB_ */
3157         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3158         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3159         T2_FFIRST_RSP_PARMS * parms;
3160         int rc = 0;
3161         int bytes_returned = 0;
3162         int name_len;
3163         __u16 params, byte_count;
3164
3165         cFYI(1, ("In FindFirst for %s",searchName));
3166
3167 findFirstRetry:
3168         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3169                       (void **) &pSMBr);
3170         if (rc)
3171                 return rc;
3172
3173         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3174                 name_len =
3175                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3176                                  PATH_MAX, nls_codepage, remap);
3177                 /* We can not add the asterik earlier in case
3178                 it got remapped to 0xF03A as if it were part of the
3179                 directory name instead of a wildcard */
3180                 name_len *= 2;
3181                 pSMB->FileName[name_len] = dirsep;
3182                 pSMB->FileName[name_len+1] = 0;
3183                 pSMB->FileName[name_len+2] = '*';
3184                 pSMB->FileName[name_len+3] = 0;
3185                 name_len += 4; /* now the trailing null */
3186                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3187                 pSMB->FileName[name_len+1] = 0;
3188                 name_len += 2;
3189         } else {        /* BB add check for overrun of SMB buf BB */
3190                 name_len = strnlen(searchName, PATH_MAX);
3191 /* BB fix here and in unicode clause above ie
3192                 if(name_len > buffersize-header)
3193                         free buffer exit; BB */
3194                 strncpy(pSMB->FileName, searchName, name_len);
3195                 pSMB->FileName[name_len] = dirsep;
3196                 pSMB->FileName[name_len+1] = '*';
3197                 pSMB->FileName[name_len+2] = 0;
3198                 name_len += 3;
3199         }
3200
3201         params = 12 + name_len /* includes null */ ;
3202         pSMB->TotalDataCount = 0;       /* no EAs */
3203         pSMB->MaxParameterCount = cpu_to_le16(10);
3204         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3205                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3206         pSMB->MaxSetupCount = 0;
3207         pSMB->Reserved = 0;
3208         pSMB->Flags = 0;
3209         pSMB->Timeout = 0;
3210         pSMB->Reserved2 = 0;
3211         byte_count = params + 1 /* pad */ ;
3212         pSMB->TotalParameterCount = cpu_to_le16(params);
3213         pSMB->ParameterCount = pSMB->TotalParameterCount;
3214         pSMB->ParameterOffset = cpu_to_le16(
3215               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3216                 - 4);
3217         pSMB->DataCount = 0;
3218         pSMB->DataOffset = 0;
3219         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3220         pSMB->Reserved3 = 0;
3221         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3222         pSMB->SearchAttributes =
3223             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3224                         ATTR_DIRECTORY);
3225         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3226         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
3227                 CIFS_SEARCH_RETURN_RESUME);
3228         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3229
3230         /* BB what should we set StorageType to? Does it matter? BB */
3231         pSMB->SearchStorageType = 0;
3232         pSMB->hdr.smb_buf_length += byte_count;
3233         pSMB->ByteCount = cpu_to_le16(byte_count);
3234
3235         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3236                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3237         cifs_stats_inc(&tcon->num_ffirst);
3238
3239         if (rc) {/* BB add logic to retry regular search if Unix search
3240                         rejected unexpectedly by server */
3241                 /* BB Add code to handle unsupported level rc */
3242                 cFYI(1, ("Error in FindFirst = %d", rc));
3243
3244                 cifs_buf_release(pSMB);
3245
3246                 /* BB eventually could optimize out free and realloc of buf */
3247                 /*    for this case */
3248                 if (rc == -EAGAIN)
3249                         goto findFirstRetry;
3250         } else { /* decode response */
3251                 /* BB remember to free buffer if error BB */
3252                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3253                 if(rc == 0) {
3254                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3255                                 psrch_inf->unicode = TRUE;
3256                         else
3257                                 psrch_inf->unicode = FALSE;
3258
3259                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3260                         psrch_inf->smallBuf = 0;
3261                         psrch_inf->srch_entries_start = 
3262                                 (char *) &pSMBr->hdr.Protocol + 
3263                                         le16_to_cpu(pSMBr->t2.DataOffset);
3264                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3265                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3266
3267                         if(parms->EndofSearch)
3268                                 psrch_inf->endOfSearch = TRUE;
3269                         else
3270                                 psrch_inf->endOfSearch = FALSE;
3271
3272                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3273                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3274                                 psrch_inf->entries_in_buffer;
3275                         *pnetfid = parms->SearchHandle;
3276                 } else {
3277                         cifs_buf_release(pSMB);
3278                 }
3279         }
3280
3281         return rc;
3282 }
3283
3284 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3285             __u16 searchHandle, struct cifs_search_info * psrch_inf)
3286 {
3287         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3288         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3289         T2_FNEXT_RSP_PARMS * parms;
3290         char *response_data;
3291         int rc = 0;
3292         int bytes_returned, name_len;
3293         __u16 params, byte_count;
3294
3295         cFYI(1, ("In FindNext"));
3296
3297         if(psrch_inf->endOfSearch == TRUE)
3298                 return -ENOENT;
3299
3300         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3301                 (void **) &pSMBr);
3302         if (rc)
3303                 return rc;
3304
3305         params = 14;    /* includes 2 bytes of null string, converted to LE below */
3306         byte_count = 0;
3307         pSMB->TotalDataCount = 0;       /* no EAs */
3308         pSMB->MaxParameterCount = cpu_to_le16(8);
3309         pSMB->MaxDataCount =
3310             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3311         pSMB->MaxSetupCount = 0;
3312         pSMB->Reserved = 0;
3313         pSMB->Flags = 0;
3314         pSMB->Timeout = 0;
3315         pSMB->Reserved2 = 0;
3316         pSMB->ParameterOffset =  cpu_to_le16(
3317               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3318         pSMB->DataCount = 0;
3319         pSMB->DataOffset = 0;
3320         pSMB->SetupCount = 1;
3321         pSMB->Reserved3 = 0;
3322         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3323         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3324         pSMB->SearchCount =
3325                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3326         /* test for Unix extensions */
3327 /*      if (tcon->ses->capabilities & CAP_UNIX) {
3328                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3329                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3330         } else {
3331                 pSMB->InformationLevel =
3332                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3333                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3334         } */
3335         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3336         pSMB->ResumeKey = psrch_inf->resume_key;
3337         pSMB->SearchFlags =
3338               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3339
3340         name_len = psrch_inf->resume_name_len;
3341         params += name_len;
3342         if(name_len < PATH_MAX) {
3343                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3344                 byte_count += name_len;
3345                 /* 14 byte parm len above enough for 2 byte null terminator */
3346                 pSMB->ResumeFileName[name_len] = 0;
3347                 pSMB->ResumeFileName[name_len+1] = 0;
3348         } else {
3349                 rc = -EINVAL;
3350                 goto FNext2_err_exit;
3351         }
3352         byte_count = params + 1 /* pad */ ;
3353         pSMB->TotalParameterCount = cpu_to_le16(params);
3354         pSMB->ParameterCount = pSMB->TotalParameterCount;
3355         pSMB->hdr.smb_buf_length += byte_count;
3356         pSMB->ByteCount = cpu_to_le16(byte_count);
3357                                                                                               
3358         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3359                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3360         cifs_stats_inc(&tcon->num_fnext);
3361         if (rc) {
3362                 if (rc == -EBADF) {
3363                         psrch_inf->endOfSearch = TRUE;
3364                         rc = 0; /* search probably was closed at end of search above */
3365                 } else
3366                         cFYI(1, ("FindNext returned = %d", rc));
3367         } else {                /* decode response */
3368                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3369                 
3370                 if(rc == 0) {
3371                         /* BB fixme add lock for file (srch_info) struct here */
3372                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3373                                 psrch_inf->unicode = TRUE;
3374                         else
3375                                 psrch_inf->unicode = FALSE;
3376                         response_data = (char *) &pSMBr->hdr.Protocol +
3377                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3378                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3379                         response_data = (char *)&pSMBr->hdr.Protocol +
3380                                 le16_to_cpu(pSMBr->t2.DataOffset);
3381                         if(psrch_inf->smallBuf)
3382                                 cifs_small_buf_release(
3383                                         psrch_inf->ntwrk_buf_start);
3384                         else
3385                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3386                         psrch_inf->srch_entries_start = response_data;
3387                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3388                         psrch_inf->smallBuf = 0;
3389                         if(parms->EndofSearch)
3390                                 psrch_inf->endOfSearch = TRUE;
3391                         else
3392                                 psrch_inf->endOfSearch = FALSE;
3393                                                                                               
3394                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3395                         psrch_inf->index_of_last_entry +=
3396                                 psrch_inf->entries_in_buffer;
3397 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3398
3399                         /* BB fixme add unlock here */
3400                 }
3401
3402         }
3403
3404         /* BB On error, should we leave previous search buf (and count and
3405         last entry fields) intact or free the previous one? */
3406
3407         /* Note: On -EAGAIN error only caller can retry on handle based calls
3408         since file handle passed in no longer valid */
3409 FNext2_err_exit:
3410         if (rc != 0)
3411                 cifs_buf_release(pSMB);
3412                                                                                               
3413         return rc;
3414 }
3415
3416 int
3417 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3418 {
3419         int rc = 0;
3420         FINDCLOSE_REQ *pSMB = NULL;
3421         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3422         int bytes_returned;
3423
3424         cFYI(1, ("In CIFSSMBFindClose"));
3425         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3426
3427         /* no sense returning error if session restarted
3428                 as file handle has been closed */
3429         if(rc == -EAGAIN)
3430                 return 0;
3431         if (rc)
3432                 return rc;
3433
3434         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3435         pSMB->FileID = searchHandle;
3436         pSMB->ByteCount = 0;
3437         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3438                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3439         if (rc) {
3440                 cERROR(1, ("Send error in FindClose = %d", rc));
3441         }
3442         cifs_stats_inc(&tcon->num_fclose);
3443         cifs_small_buf_release(pSMB);
3444
3445         /* Since session is dead, search handle closed on server already */
3446         if (rc == -EAGAIN)
3447                 rc = 0;
3448
3449         return rc;
3450 }
3451
3452 int
3453 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3454                 const unsigned char *searchName,
3455                 __u64 * inode_number,
3456                 const struct nls_table *nls_codepage, int remap)
3457 {
3458         int rc = 0;
3459         TRANSACTION2_QPI_REQ *pSMB = NULL;
3460         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3461         int name_len, bytes_returned;
3462         __u16 params, byte_count;
3463
3464         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3465         if(tcon == NULL)
3466                 return -ENODEV; 
3467
3468 GetInodeNumberRetry:
3469         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3470                       (void **) &pSMBr);
3471         if (rc)
3472                 return rc;
3473
3474
3475         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3476                 name_len =
3477                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3478                                 PATH_MAX,nls_codepage, remap);
3479                 name_len++;     /* trailing null */
3480                 name_len *= 2;
3481         } else {                /* BB improve the check for buffer overruns BB */
3482                 name_len = strnlen(searchName, PATH_MAX);
3483                 name_len++;     /* trailing null */
3484                 strncpy(pSMB->FileName, searchName, name_len);
3485         }
3486
3487         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3488         pSMB->TotalDataCount = 0;
3489         pSMB->MaxParameterCount = cpu_to_le16(2);
3490         /* BB find exact max data count below from sess structure BB */
3491         pSMB->MaxDataCount = cpu_to_le16(4000);
3492         pSMB->MaxSetupCount = 0;
3493         pSMB->Reserved = 0;
3494         pSMB->Flags = 0;
3495         pSMB->Timeout = 0;
3496         pSMB->Reserved2 = 0;
3497         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3498                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3499         pSMB->DataCount = 0;
3500         pSMB->DataOffset = 0;
3501         pSMB->SetupCount = 1;
3502         pSMB->Reserved3 = 0;
3503         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3504         byte_count = params + 1 /* pad */ ;
3505         pSMB->TotalParameterCount = cpu_to_le16(params);
3506         pSMB->ParameterCount = pSMB->TotalParameterCount;
3507         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3508         pSMB->Reserved4 = 0;
3509         pSMB->hdr.smb_buf_length += byte_count;
3510         pSMB->ByteCount = cpu_to_le16(byte_count);
3511
3512         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3513                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3514         if (rc) {
3515                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3516         } else {
3517                 /* decode response */
3518                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3519                 if (rc || (pSMBr->ByteCount < 2))
3520                 /* BB also check enough total bytes returned */
3521                         /* If rc should we check for EOPNOSUPP and
3522                         disable the srvino flag? or in caller? */
3523                         rc = -EIO;      /* bad smb */
3524                 else {
3525                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3526                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3527                         struct file_internal_info * pfinfo;
3528                         /* BB Do we need a cast or hash here ? */
3529                         if(count < 8) {
3530                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3531                                 rc = -EIO;
3532                                 goto GetInodeNumOut;
3533                         }
3534                         pfinfo = (struct file_internal_info *)
3535                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3536                         *inode_number = pfinfo->UniqueId;
3537                 }
3538         }
3539 GetInodeNumOut:
3540         cifs_buf_release(pSMB);
3541         if (rc == -EAGAIN)
3542                 goto GetInodeNumberRetry;
3543         return rc;
3544 }
3545
3546 int
3547 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3548                 const unsigned char *searchName,
3549                 unsigned char **targetUNCs,
3550                 unsigned int *number_of_UNC_in_array,
3551                 const struct nls_table *nls_codepage, int remap)
3552 {
3553 /* TRANS2_GET_DFS_REFERRAL */
3554         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3555         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3556         struct dfs_referral_level_3 * referrals = NULL;
3557         int rc = 0;
3558         int bytes_returned;
3559         int name_len;
3560         unsigned int i;
3561         char * temp;
3562         __u16 params, byte_count;
3563         *number_of_UNC_in_array = 0;
3564         *targetUNCs = NULL;
3565
3566         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3567         if (ses == NULL)
3568                 return -ENODEV;
3569 getDFSRetry:
3570         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3571                       (void **) &pSMBr);
3572         if (rc)
3573                 return rc;
3574         
3575         /* server pointer checked in called function, 
3576         but should never be null here anyway */
3577         pSMB->hdr.Mid = GetNextMid(ses->server);
3578         pSMB->hdr.Tid = ses->ipc_tid;
3579         pSMB->hdr.Uid = ses->Suid;
3580         if (ses->capabilities & CAP_STATUS32) {
3581                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3582         }
3583         if (ses->capabilities & CAP_DFS) {
3584                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3585         }
3586
3587         if (ses->capabilities & CAP_UNICODE) {
3588                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3589                 name_len =
3590                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3591                                      searchName, PATH_MAX, nls_codepage, remap);
3592                 name_len++;     /* trailing null */
3593                 name_len *= 2;
3594         } else {                /* BB improve the check for buffer overruns BB */
3595                 name_len = strnlen(searchName, PATH_MAX);
3596                 name_len++;     /* trailing null */
3597                 strncpy(pSMB->RequestFileName, searchName, name_len);
3598         }
3599
3600         params = 2 /* level */  + name_len /*includes null */ ;
3601         pSMB->TotalDataCount = 0;
3602         pSMB->DataCount = 0;
3603         pSMB->DataOffset = 0;
3604         pSMB->MaxParameterCount = 0;
3605         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3606         pSMB->MaxSetupCount = 0;
3607         pSMB->Reserved = 0;
3608         pSMB->Flags = 0;
3609         pSMB->Timeout = 0;
3610         pSMB->Reserved2 = 0;
3611         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3612         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3613         pSMB->SetupCount = 1;
3614         pSMB->Reserved3 = 0;
3615         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3616         byte_count = params + 3 /* pad */ ;
3617         pSMB->ParameterCount = cpu_to_le16(params);
3618         pSMB->TotalParameterCount = pSMB->ParameterCount;
3619         pSMB->MaxReferralLevel = cpu_to_le16(3);
3620         pSMB->hdr.smb_buf_length += byte_count;
3621         pSMB->ByteCount = cpu_to_le16(byte_count);
3622
3623         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3624                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3625         if (rc) {
3626                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3627         } else {                /* decode response */
3628 /* BB Add logic to parse referrals here */
3629                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3630
3631                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3632                         rc = -EIO;      /* bad smb */
3633                 else {
3634                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3635                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3636
3637                         cFYI(1,
3638                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3639                               pSMBr->ByteCount, data_offset));
3640                         referrals = 
3641                             (struct dfs_referral_level_3 *) 
3642                                         (8 /* sizeof start of data block */ +
3643                                         data_offset +
3644                                         (char *) &pSMBr->hdr.Protocol); 
3645                         cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
3646                                 le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
3647                         /* BB This field is actually two bytes in from start of
3648                            data block so we could do safety check that DataBlock
3649                            begins at address of pSMBr->NumberOfReferrals */
3650                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3651
3652                         /* BB Fix below so can return more than one referral */
3653                         if(*number_of_UNC_in_array > 1)
3654                                 *number_of_UNC_in_array = 1;
3655
3656                         /* get the length of the strings describing refs */
3657                         name_len = 0;
3658                         for(i=0;i<*number_of_UNC_in_array;i++) {
3659                                 /* make sure that DfsPathOffset not past end */
3660                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3661                                 if (offset > data_count) {
3662                                         /* if invalid referral, stop here and do 
3663                                         not try to copy any more */
3664                                         *number_of_UNC_in_array = i;
3665                                         break;
3666                                 } 
3667                                 temp = ((char *)referrals) + offset;
3668
3669                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3670                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3671                                 } else {
3672                                         name_len += strnlen(temp,data_count);
3673                                 }
3674                                 referrals++;
3675                                 /* BB add check that referral pointer does not fall off end PDU */
3676                                 
3677                         }
3678                         /* BB add check for name_len bigger than bcc */
3679                         *targetUNCs = 
3680                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3681                         if(*targetUNCs == NULL) {
3682                                 rc = -ENOMEM;
3683                                 goto GetDFSRefExit;
3684                         }
3685                         /* copy the ref strings */
3686                         referrals =  
3687                             (struct dfs_referral_level_3 *) 
3688                                         (8 /* sizeof data hdr */ +
3689                                         data_offset + 
3690                                         (char *) &pSMBr->hdr.Protocol);
3691
3692                         for(i=0;i<*number_of_UNC_in_array;i++) {
3693                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3694                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3695                                         cifs_strfromUCS_le(*targetUNCs,
3696                                                 (__le16 *) temp, name_len, nls_codepage);
3697                                 } else {
3698                                         strncpy(*targetUNCs,temp,name_len);
3699                                 }
3700                                 /*  BB update target_uncs pointers */
3701                                 referrals++;
3702                         }
3703                         temp = *targetUNCs;
3704                         temp[name_len] = 0;
3705                 }
3706
3707         }
3708 GetDFSRefExit:
3709         if (pSMB)
3710                 cifs_buf_release(pSMB);
3711
3712         if (rc == -EAGAIN)
3713                 goto getDFSRetry;
3714
3715         return rc;
3716 }
3717
3718 /* Query File System Info such as free space to old servers such as Win 9x */
3719 int
3720 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3721 {
3722 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3723         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3724         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3725         FILE_SYSTEM_ALLOC_INFO *response_data;
3726         int rc = 0;
3727         int bytes_returned = 0;
3728         __u16 params, byte_count;
3729
3730         cFYI(1, ("OldQFSInfo"));
3731 oldQFSInfoRetry:
3732         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3733                 (void **) &pSMBr);
3734         if (rc)
3735                 return rc;
3736         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3737                       (void **) &pSMBr);
3738         if (rc)
3739                 return rc;
3740
3741         params = 2;     /* level */
3742         pSMB->TotalDataCount = 0;
3743         pSMB->MaxParameterCount = cpu_to_le16(2);
3744         pSMB->MaxDataCount = cpu_to_le16(1000);
3745         pSMB->MaxSetupCount = 0;
3746         pSMB->Reserved = 0;
3747         pSMB->Flags = 0;
3748         pSMB->Timeout = 0;
3749         pSMB->Reserved2 = 0;
3750         byte_count = params + 1 /* pad */ ;
3751         pSMB->TotalParameterCount = cpu_to_le16(params);
3752         pSMB->ParameterCount = pSMB->TotalParameterCount;
3753         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3754         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3755         pSMB->DataCount = 0;
3756         pSMB->DataOffset = 0;
3757         pSMB->SetupCount = 1;
3758         pSMB->Reserved3 = 0;
3759         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3760         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3761         pSMB->hdr.smb_buf_length += byte_count;
3762         pSMB->ByteCount = cpu_to_le16(byte_count);
3763
3764         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3765                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3766         if (rc) {
3767                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3768         } else {                /* decode response */
3769                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3770
3771                 if (rc || (pSMBr->ByteCount < 18))
3772                         rc = -EIO;      /* bad smb */
3773                 else {
3774                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3775                         cFYI(1,("qfsinf resp BCC: %d  Offset %d",
3776                                  pSMBr->ByteCount, data_offset));
3777
3778                         response_data =
3779                                 (FILE_SYSTEM_ALLOC_INFO *) 
3780                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3781                         FSData->f_bsize =
3782                                 le16_to_cpu(response_data->BytesPerSector) *
3783                                 le32_to_cpu(response_data->
3784                                         SectorsPerAllocationUnit);
3785                         FSData->f_blocks =
3786                                 le32_to_cpu(response_data->TotalAllocationUnits);
3787                         FSData->f_bfree = FSData->f_bavail =
3788                                 le32_to_cpu(response_data->FreeAllocationUnits);
3789                         cFYI(1,
3790                              ("Blocks: %lld  Free: %lld Block size %ld",
3791                               (unsigned long long)FSData->f_blocks,
3792                               (unsigned long long)FSData->f_bfree,
3793                               FSData->f_bsize));
3794                 }
3795         }
3796         cifs_buf_release(pSMB);
3797
3798         if (rc == -EAGAIN)
3799                 goto oldQFSInfoRetry;
3800
3801         return rc;
3802 }
3803
3804 int
3805 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3806 {
3807 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3808         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3809         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3810         FILE_SYSTEM_INFO *response_data;
3811         int rc = 0;
3812         int bytes_returned = 0;
3813         __u16 params, byte_count;
3814
3815         cFYI(1, ("In QFSInfo"));
3816 QFSInfoRetry:
3817         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3818                       (void **) &pSMBr);
3819         if (rc)
3820                 return rc;
3821
3822         params = 2;     /* level */
3823         pSMB->TotalDataCount = 0;
3824         pSMB->MaxParameterCount = cpu_to_le16(2);
3825         pSMB->MaxDataCount = cpu_to_le16(1000);
3826         pSMB->MaxSetupCount = 0;
3827         pSMB->Reserved = 0;
3828         pSMB->Flags = 0;
3829         pSMB->Timeout = 0;
3830         pSMB->Reserved2 = 0;
3831         byte_count = params + 1 /* pad */ ;
3832         pSMB->TotalParameterCount = cpu_to_le16(params);
3833         pSMB->ParameterCount = pSMB->TotalParameterCount;
3834         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3835         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3836         pSMB->DataCount = 0;
3837         pSMB->DataOffset = 0;
3838         pSMB->SetupCount = 1;
3839         pSMB->Reserved3 = 0;
3840         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3841         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3842         pSMB->hdr.smb_buf_length += byte_count;
3843         pSMB->ByteCount = cpu_to_le16(byte_count);
3844
3845         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3846                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3847         if (rc) {
3848                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3849         } else {                /* decode response */
3850                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3851
3852                 if (rc || (pSMBr->ByteCount < 24))
3853                         rc = -EIO;      /* bad smb */
3854                 else {
3855                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3856
3857                         response_data =
3858                             (FILE_SYSTEM_INFO
3859                              *) (((char *) &pSMBr->hdr.Protocol) +
3860                                  data_offset);
3861                         FSData->f_bsize =
3862                             le32_to_cpu(response_data->BytesPerSector) *
3863                             le32_to_cpu(response_data->
3864                                         SectorsPerAllocationUnit);
3865                         FSData->f_blocks =
3866                             le64_to_cpu(response_data->TotalAllocationUnits);
3867                         FSData->f_bfree = FSData->f_bavail =
3868                             le64_to_cpu(response_data->FreeAllocationUnits);
3869                         cFYI(1,
3870                              ("Blocks: %lld  Free: %lld Block size %ld",
3871                               (unsigned long long)FSData->f_blocks,
3872                               (unsigned long long)FSData->f_bfree,
3873                               FSData->f_bsize));
3874                 }
3875         }
3876         cifs_buf_release(pSMB);
3877
3878         if (rc == -EAGAIN)
3879                 goto QFSInfoRetry;
3880
3881         return rc;
3882 }
3883
3884 int
3885 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3886 {
3887 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3888         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3889         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3890         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3891         int rc = 0;
3892         int bytes_returned = 0;
3893         __u16 params, byte_count;
3894
3895         cFYI(1, ("In QFSAttributeInfo"));
3896 QFSAttributeRetry:
3897         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3898                       (void **) &pSMBr);
3899         if (rc)
3900                 return rc;
3901
3902         params = 2;     /* level */
3903         pSMB->TotalDataCount = 0;
3904         pSMB->MaxParameterCount = cpu_to_le16(2);
3905         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3906         pSMB->MaxSetupCount = 0;
3907         pSMB->Reserved = 0;
3908         pSMB->Flags = 0;
3909         pSMB->Timeout = 0;
3910         pSMB->Reserved2 = 0;
3911         byte_count = params + 1 /* pad */ ;
3912         pSMB->TotalParameterCount = cpu_to_le16(params);
3913         pSMB->ParameterCount = pSMB->TotalParameterCount;
3914         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3915         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3916         pSMB->DataCount = 0;
3917         pSMB->DataOffset = 0;
3918         pSMB->SetupCount = 1;
3919         pSMB->Reserved3 = 0;
3920         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3921         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3922         pSMB->hdr.smb_buf_length += byte_count;
3923         pSMB->ByteCount = cpu_to_le16(byte_count);
3924
3925         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3926                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3927         if (rc) {
3928                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3929         } else {                /* decode response */
3930                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3931
3932                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3933                         rc = -EIO;      /* bad smb */
3934                 } else {
3935                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3936                         response_data =
3937                             (FILE_SYSTEM_ATTRIBUTE_INFO
3938                              *) (((char *) &pSMBr->hdr.Protocol) +
3939                                  data_offset);
3940                         memcpy(&tcon->fsAttrInfo, response_data,
3941                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3942                 }
3943         }
3944         cifs_buf_release(pSMB);
3945
3946         if (rc == -EAGAIN)
3947                 goto QFSAttributeRetry;
3948
3949         return rc;
3950 }
3951
3952 int
3953 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3954 {
3955 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3956         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3957         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3958         FILE_SYSTEM_DEVICE_INFO *response_data;
3959         int rc = 0;
3960         int bytes_returned = 0;
3961         __u16 params, byte_count;
3962
3963         cFYI(1, ("In QFSDeviceInfo"));
3964 QFSDeviceRetry:
3965         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3966                       (void **) &pSMBr);
3967         if (rc)
3968                 return rc;
3969
3970         params = 2;     /* level */
3971         pSMB->TotalDataCount = 0;
3972         pSMB->MaxParameterCount = cpu_to_le16(2);
3973         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3974         pSMB->MaxSetupCount = 0;
3975         pSMB->Reserved = 0;
3976         pSMB->Flags = 0;
3977         pSMB->Timeout = 0;
3978         pSMB->Reserved2 = 0;
3979         byte_count = params + 1 /* pad */ ;
3980         pSMB->TotalParameterCount = cpu_to_le16(params);
3981         pSMB->ParameterCount = pSMB->TotalParameterCount;
3982         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3983         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3984
3985         pSMB->DataCount = 0;
3986         pSMB->DataOffset = 0;
3987         pSMB->SetupCount = 1;
3988         pSMB->Reserved3 = 0;
3989         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3990         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3991         pSMB->hdr.smb_buf_length += byte_count;
3992         pSMB->ByteCount = cpu_to_le16(byte_count);
3993
3994         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3995                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3996         if (rc) {
3997                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3998         } else {                /* decode response */
3999                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4000
4001                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4002                         rc = -EIO;      /* bad smb */
4003                 else {
4004                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4005                         response_data =
4006                             (FILE_SYSTEM_DEVICE_INFO *)
4007                                 (((char *) &pSMBr->hdr.Protocol) +
4008                                  data_offset);
4009                         memcpy(&tcon->fsDevInfo, response_data,
4010                                sizeof (FILE_SYSTEM_DEVICE_INFO));
4011                 }
4012         }
4013         cifs_buf_release(pSMB);
4014
4015         if (rc == -EAGAIN)
4016                 goto QFSDeviceRetry;
4017
4018         return rc;
4019 }
4020
4021 int
4022 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4023 {
4024 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
4025         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4026         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4027         FILE_SYSTEM_UNIX_INFO *response_data;
4028         int rc = 0;
4029         int bytes_returned = 0;
4030         __u16 params, byte_count;
4031
4032         cFYI(1, ("In QFSUnixInfo"));
4033 QFSUnixRetry:
4034         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4035                       (void **) &pSMBr);
4036         if (rc)
4037                 return rc;
4038
4039         params = 2;     /* level */
4040         pSMB->TotalDataCount = 0;
4041         pSMB->DataCount = 0;
4042         pSMB->DataOffset = 0;
4043         pSMB->MaxParameterCount = cpu_to_le16(2);
4044         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4045         pSMB->MaxSetupCount = 0;
4046         pSMB->Reserved = 0;
4047         pSMB->Flags = 0;
4048         pSMB->Timeout = 0;
4049         pSMB->Reserved2 = 0;
4050         byte_count = params + 1 /* pad */ ;
4051         pSMB->ParameterCount = cpu_to_le16(params);
4052         pSMB->TotalParameterCount = pSMB->ParameterCount;
4053         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
4054         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4055         pSMB->SetupCount = 1;
4056         pSMB->Reserved3 = 0;
4057         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4058         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4059         pSMB->hdr.smb_buf_length += byte_count;
4060         pSMB->ByteCount = cpu_to_le16(byte_count);
4061
4062         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4063                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4064         if (rc) {
4065                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4066         } else {                /* decode response */
4067                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4068
4069                 if (rc || (pSMBr->ByteCount < 13)) {
4070                         rc = -EIO;      /* bad smb */
4071                 } else {
4072                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4073                         response_data =
4074                             (FILE_SYSTEM_UNIX_INFO
4075                              *) (((char *) &pSMBr->hdr.Protocol) +
4076                                  data_offset);
4077                         memcpy(&tcon->fsUnixInfo, response_data,
4078                                sizeof (FILE_SYSTEM_UNIX_INFO));
4079                 }
4080         }
4081         cifs_buf_release(pSMB);
4082
4083         if (rc == -EAGAIN)
4084                 goto QFSUnixRetry;
4085
4086
4087         return rc;
4088 }
4089
4090 int
4091 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4092 {
4093 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
4094         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4095         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4096         int rc = 0;
4097         int bytes_returned = 0;
4098         __u16 params, param_offset, offset, byte_count;
4099
4100         cFYI(1, ("In SETFSUnixInfo"));
4101 SETFSUnixRetry:
4102         /* BB switch to small buf init to save memory */
4103         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4104                       (void **) &pSMBr);
4105         if (rc)
4106                 return rc;
4107
4108         params = 4;     /* 2 bytes zero followed by info level. */
4109         pSMB->MaxSetupCount = 0;
4110         pSMB->Reserved = 0;
4111         pSMB->Flags = 0;
4112         pSMB->Timeout = 0;
4113         pSMB->Reserved2 = 0;
4114         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4115         offset = param_offset + params;
4116
4117         pSMB->MaxParameterCount = cpu_to_le16(4);
4118         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4119         pSMB->SetupCount = 1;
4120         pSMB->Reserved3 = 0;
4121         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4122         byte_count = 1 /* pad */ + params + 12;
4123
4124         pSMB->DataCount = cpu_to_le16(12);
4125         pSMB->ParameterCount = cpu_to_le16(params);
4126         pSMB->TotalDataCount = pSMB->DataCount;
4127         pSMB->TotalParameterCount = pSMB->ParameterCount;
4128         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4129         pSMB->DataOffset = cpu_to_le16(offset);
4130
4131         /* Params. */
4132         pSMB->FileNum = 0;
4133         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4134
4135         /* Data. */
4136         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4137         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4138         pSMB->ClientUnixCap = cpu_to_le64(cap);
4139
4140         pSMB->hdr.smb_buf_length += byte_count;
4141         pSMB->ByteCount = cpu_to_le16(byte_count);
4142
4143         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4144                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4145         if (rc) {
4146                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4147         } else {                /* decode response */
4148                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4149                 if (rc) {
4150                         rc = -EIO;      /* bad smb */
4151                 }
4152         }
4153         cifs_buf_release(pSMB);
4154
4155         if (rc == -EAGAIN)
4156                 goto SETFSUnixRetry;
4157
4158         return rc;
4159 }
4160
4161
4162
4163 int
4164 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4165                    struct kstatfs *FSData)
4166 {
4167 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4168         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4169         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4170         FILE_SYSTEM_POSIX_INFO *response_data;
4171         int rc = 0;
4172         int bytes_returned = 0;
4173         __u16 params, byte_count;
4174
4175         cFYI(1, ("In QFSPosixInfo"));
4176 QFSPosixRetry:
4177         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4178                       (void **) &pSMBr);
4179         if (rc)
4180                 return rc;
4181
4182         params = 2;     /* level */
4183         pSMB->TotalDataCount = 0;
4184         pSMB->DataCount = 0;
4185         pSMB->DataOffset = 0;
4186         pSMB->MaxParameterCount = cpu_to_le16(2);
4187         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4188         pSMB->MaxSetupCount = 0;
4189         pSMB->Reserved = 0;
4190         pSMB->Flags = 0;
4191         pSMB->Timeout = 0;
4192         pSMB->Reserved2 = 0;
4193         byte_count = params + 1 /* pad */ ;
4194         pSMB->ParameterCount = cpu_to_le16(params);
4195         pSMB->TotalParameterCount = pSMB->ParameterCount;
4196         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
4197         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4198         pSMB->SetupCount = 1;
4199         pSMB->Reserved3 = 0;
4200         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4201         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4202         pSMB->hdr.smb_buf_length += byte_count;
4203         pSMB->ByteCount = cpu_to_le16(byte_count);
4204
4205         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4206                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4207         if (rc) {
4208                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4209         } else {                /* decode response */
4210                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4211
4212                 if (rc || (pSMBr->ByteCount < 13)) {
4213                         rc = -EIO;      /* bad smb */
4214                 } else {
4215                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4216                         response_data =
4217                             (FILE_SYSTEM_POSIX_INFO
4218                              *) (((char *) &pSMBr->hdr.Protocol) +
4219                                  data_offset);
4220                         FSData->f_bsize =
4221                                         le32_to_cpu(response_data->BlockSize);
4222                         FSData->f_blocks =
4223                                         le64_to_cpu(response_data->TotalBlocks);
4224                         FSData->f_bfree =
4225                             le64_to_cpu(response_data->BlocksAvail);
4226                         if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4227                                 FSData->f_bavail = FSData->f_bfree;
4228                         } else {
4229                                 FSData->f_bavail =
4230                                         le64_to_cpu(response_data->UserBlocksAvail);
4231                         }
4232                         if(response_data->TotalFileNodes != cpu_to_le64(-1))
4233                                 FSData->f_files =
4234                                         le64_to_cpu(response_data->TotalFileNodes);
4235                         if(response_data->FreeFileNodes != cpu_to_le64(-1))
4236                                 FSData->f_ffree =
4237                                         le64_to_cpu(response_data->FreeFileNodes);
4238                 }
4239         }
4240         cifs_buf_release(pSMB);
4241
4242         if (rc == -EAGAIN)
4243                 goto QFSPosixRetry;
4244
4245         return rc;
4246 }
4247
4248
4249 /* We can not use write of zero bytes trick to 
4250    set file size due to need for large file support.  Also note that 
4251    this SetPathInfo is preferred to SetFileInfo based method in next 
4252    routine which is only needed to work around a sharing violation bug
4253    in Samba which this routine can run into */
4254
4255 int
4256 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4257               __u64 size, int SetAllocation, 
4258               const struct nls_table *nls_codepage, int remap)
4259 {
4260         struct smb_com_transaction2_spi_req *pSMB = NULL;
4261         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4262         struct file_end_of_file_info *parm_data;
4263         int name_len;
4264         int rc = 0;
4265         int bytes_returned = 0;
4266         __u16 params, byte_count, data_count, param_offset, offset;
4267
4268         cFYI(1, ("In SetEOF"));
4269 SetEOFRetry:
4270         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4271                       (void **) &pSMBr);
4272         if (rc)
4273                 return rc;
4274
4275         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4276                 name_len =
4277                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4278                                      PATH_MAX, nls_codepage, remap);
4279                 name_len++;     /* trailing null */
4280                 name_len *= 2;
4281         } else {        /* BB improve the check for buffer overruns BB */
4282                 name_len = strnlen(fileName, PATH_MAX);
4283                 name_len++;     /* trailing null */
4284                 strncpy(pSMB->FileName, fileName, name_len);
4285         }
4286         params = 6 + name_len;
4287         data_count = sizeof (struct file_end_of_file_info);
4288         pSMB->MaxParameterCount = cpu_to_le16(2);
4289         pSMB->MaxDataCount = cpu_to_le16(4100);
4290         pSMB->MaxSetupCount = 0;
4291         pSMB->Reserved = 0;
4292         pSMB->Flags = 0;
4293         pSMB->Timeout = 0;
4294         pSMB->Reserved2 = 0;
4295         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4296                                      InformationLevel) - 4;
4297         offset = param_offset + params;
4298         if(SetAllocation) {
4299                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4300                     pSMB->InformationLevel =
4301                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4302                 else
4303                     pSMB->InformationLevel =
4304                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4305         } else /* Set File Size */  {    
4306             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4307                     pSMB->InformationLevel =
4308                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4309             else
4310                     pSMB->InformationLevel =
4311                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4312         }
4313
4314         parm_data =
4315             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4316                                        offset);
4317         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4318         pSMB->DataOffset = cpu_to_le16(offset);
4319         pSMB->SetupCount = 1;
4320         pSMB->Reserved3 = 0;
4321         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4322         byte_count = 3 /* pad */  + params + data_count;
4323         pSMB->DataCount = cpu_to_le16(data_count);
4324         pSMB->TotalDataCount = pSMB->DataCount;
4325         pSMB->ParameterCount = cpu_to_le16(params);
4326         pSMB->TotalParameterCount = pSMB->ParameterCount;
4327         pSMB->Reserved4 = 0;
4328         pSMB->hdr.smb_buf_length += byte_count;
4329         parm_data->FileSize = cpu_to_le64(size);
4330         pSMB->ByteCount = cpu_to_le16(byte_count);
4331         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4332                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4333         if (rc) {
4334                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4335         }
4336
4337         cifs_buf_release(pSMB);
4338
4339         if (rc == -EAGAIN)
4340                 goto SetEOFRetry;
4341
4342         return rc;
4343 }
4344
4345 int
4346 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
4347                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4348 {
4349         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4350         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4351         char *data_offset;
4352         struct file_end_of_file_info *parm_data;
4353         int rc = 0;
4354         int bytes_returned = 0;
4355         __u16 params, param_offset, offset, byte_count, count;
4356
4357         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4358                         (long long)size));
4359         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4360
4361         if (rc)
4362                 return rc;
4363
4364         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4365
4366         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4367         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4368     
4369         params = 6;
4370         pSMB->MaxSetupCount = 0;
4371         pSMB->Reserved = 0;
4372         pSMB->Flags = 0;
4373         pSMB->Timeout = 0;
4374         pSMB->Reserved2 = 0;
4375         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4376         offset = param_offset + params;
4377
4378         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
4379
4380         count = sizeof(struct file_end_of_file_info);
4381         pSMB->MaxParameterCount = cpu_to_le16(2);
4382         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4383         pSMB->SetupCount = 1;
4384         pSMB->Reserved3 = 0;
4385         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4386         byte_count = 3 /* pad */  + params + count;
4387         pSMB->DataCount = cpu_to_le16(count);
4388         pSMB->ParameterCount = cpu_to_le16(params);
4389         pSMB->TotalDataCount = pSMB->DataCount;
4390         pSMB->TotalParameterCount = pSMB->ParameterCount;
4391         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4392         parm_data =
4393                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4394                         offset);
4395         pSMB->DataOffset = cpu_to_le16(offset);
4396         parm_data->FileSize = cpu_to_le64(size);
4397         pSMB->Fid = fid;
4398         if(SetAllocation) {
4399                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4400                         pSMB->InformationLevel =
4401                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4402                 else
4403                         pSMB->InformationLevel =
4404                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4405         } else /* Set File Size */  {    
4406             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4407                     pSMB->InformationLevel =
4408                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4409             else
4410                     pSMB->InformationLevel =
4411                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4412         }
4413         pSMB->Reserved4 = 0;
4414         pSMB->hdr.smb_buf_length += byte_count;
4415         pSMB->ByteCount = cpu_to_le16(byte_count);
4416         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4417                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4418         if (rc) {
4419                 cFYI(1,
4420                      ("Send error in SetFileInfo (SetFileSize) = %d",
4421                       rc));
4422         }
4423
4424         if (pSMB)
4425                 cifs_small_buf_release(pSMB);
4426
4427         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4428                 since file handle passed in no longer valid */
4429
4430         return rc;
4431 }
4432
4433 /* Some legacy servers such as NT4 require that the file times be set on 
4434    an open handle, rather than by pathname - this is awkward due to
4435    potential access conflicts on the open, but it is unavoidable for these
4436    old servers since the only other choice is to go from 100 nanosecond DCE
4437    time and resort to the original setpathinfo level which takes the ancient
4438    DOS time format with 2 second granularity */
4439 int
4440 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
4441                    __u16 fid)
4442 {
4443         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4444         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4445         char *data_offset;
4446         int rc = 0;
4447         int bytes_returned = 0;
4448         __u16 params, param_offset, offset, byte_count, count;
4449
4450         cFYI(1, ("Set Times (via SetFileInfo)"));
4451         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4452
4453         if (rc)
4454                 return rc;
4455
4456         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4457
4458         /* At this point there is no need to override the current pid
4459         with the pid of the opener, but that could change if we someday
4460         use an existing handle (rather than opening one on the fly) */
4461         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4462         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4463     
4464         params = 6;
4465         pSMB->MaxSetupCount = 0;
4466         pSMB->Reserved = 0;
4467         pSMB->Flags = 0;
4468         pSMB->Timeout = 0;
4469         pSMB->Reserved2 = 0;
4470         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4471         offset = param_offset + params;
4472
4473         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
4474
4475         count = sizeof (FILE_BASIC_INFO);
4476         pSMB->MaxParameterCount = cpu_to_le16(2);
4477         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4478         pSMB->SetupCount = 1;
4479         pSMB->Reserved3 = 0;
4480         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4481         byte_count = 3 /* pad */  + params + count;
4482         pSMB->DataCount = cpu_to_le16(count);
4483         pSMB->ParameterCount = cpu_to_le16(params);
4484         pSMB->TotalDataCount = pSMB->DataCount;
4485         pSMB->TotalParameterCount = pSMB->ParameterCount;
4486         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4487         pSMB->DataOffset = cpu_to_le16(offset);
4488         pSMB->Fid = fid;
4489         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4490                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4491         else
4492                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4493         pSMB->Reserved4 = 0;
4494         pSMB->hdr.smb_buf_length += byte_count;
4495         pSMB->ByteCount = cpu_to_le16(byte_count);
4496         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4497         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4498                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4499         if (rc) {
4500                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4501         }
4502
4503         cifs_small_buf_release(pSMB);
4504
4505         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4506                 since file handle passed in no longer valid */
4507
4508         return rc;
4509 }
4510
4511
4512 int
4513 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4514                 const FILE_BASIC_INFO * data, 
4515                 const struct nls_table *nls_codepage, int remap)
4516 {
4517         TRANSACTION2_SPI_REQ *pSMB = NULL;
4518         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4519         int name_len;
4520         int rc = 0;
4521         int bytes_returned = 0;
4522         char *data_offset;
4523         __u16 params, param_offset, offset, byte_count, count;
4524
4525         cFYI(1, ("In SetTimes"));
4526
4527 SetTimesRetry:
4528         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4529                       (void **) &pSMBr);
4530         if (rc)
4531                 return rc;
4532
4533         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4534                 name_len =
4535                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4536                                      PATH_MAX, nls_codepage, remap);
4537                 name_len++;     /* trailing null */
4538                 name_len *= 2;
4539         } else {                /* BB improve the check for buffer overruns BB */
4540                 name_len = strnlen(fileName, PATH_MAX);
4541                 name_len++;     /* trailing null */
4542                 strncpy(pSMB->FileName, fileName, name_len);
4543         }
4544
4545         params = 6 + name_len;
4546         count = sizeof (FILE_BASIC_INFO);
4547         pSMB->MaxParameterCount = cpu_to_le16(2);
4548         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4549         pSMB->MaxSetupCount = 0;
4550         pSMB->Reserved = 0;
4551         pSMB->Flags = 0;
4552         pSMB->Timeout = 0;
4553         pSMB->Reserved2 = 0;
4554         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4555                                      InformationLevel) - 4;
4556         offset = param_offset + params;
4557         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4558         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4559         pSMB->DataOffset = cpu_to_le16(offset);
4560         pSMB->SetupCount = 1;
4561         pSMB->Reserved3 = 0;
4562         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4563         byte_count = 3 /* pad */  + params + count;
4564
4565         pSMB->DataCount = cpu_to_le16(count);
4566         pSMB->ParameterCount = cpu_to_le16(params);
4567         pSMB->TotalDataCount = pSMB->DataCount;
4568         pSMB->TotalParameterCount = pSMB->ParameterCount;
4569         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4570                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4571         else
4572                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4573         pSMB->Reserved4 = 0;
4574         pSMB->hdr.smb_buf_length += byte_count;
4575         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4576         pSMB->ByteCount = cpu_to_le16(byte_count);
4577         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4578                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4579         if (rc) {
4580                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4581         }
4582
4583         cifs_buf_release(pSMB);
4584
4585         if (rc == -EAGAIN)
4586                 goto SetTimesRetry;
4587
4588         return rc;
4589 }
4590
4591 /* Can not be used to set time stamps yet (due to old DOS time format) */
4592 /* Can be used to set attributes */
4593 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4594           handling it anyway and NT4 was what we thought it would be needed for
4595           Do not delete it until we prove whether needed for Win9x though */
4596 int
4597 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4598                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4599 {
4600         SETATTR_REQ *pSMB = NULL;
4601         SETATTR_RSP *pSMBr = NULL;
4602         int rc = 0;
4603         int bytes_returned;
4604         int name_len;
4605
4606         cFYI(1, ("In SetAttrLegacy"));
4607
4608 SetAttrLgcyRetry:
4609         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4610                       (void **) &pSMBr);
4611         if (rc)
4612                 return rc;
4613
4614         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4615                 name_len =
4616                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4617                                 PATH_MAX, nls_codepage);
4618                 name_len++;     /* trailing null */
4619                 name_len *= 2;
4620         } else {                /* BB improve the check for buffer overruns BB */
4621                 name_len = strnlen(fileName, PATH_MAX);
4622                 name_len++;     /* trailing null */
4623                 strncpy(pSMB->fileName, fileName, name_len);
4624         }
4625         pSMB->attr = cpu_to_le16(dos_attrs);
4626         pSMB->BufferFormat = 0x04;
4627         pSMB->hdr.smb_buf_length += name_len + 1;
4628         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4629         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4630                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4631         if (rc) {
4632                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4633         }
4634
4635         cifs_buf_release(pSMB);
4636
4637         if (rc == -EAGAIN)
4638                 goto SetAttrLgcyRetry;
4639
4640         return rc;
4641 }
4642 #endif /* temporarily unneeded SetAttr legacy function */
4643
4644 int
4645 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4646                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4647                     dev_t device, const struct nls_table *nls_codepage, 
4648                     int remap)
4649 {
4650         TRANSACTION2_SPI_REQ *pSMB = NULL;
4651         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4652         int name_len;
4653         int rc = 0;
4654         int bytes_returned = 0;
4655         FILE_UNIX_BASIC_INFO *data_offset;
4656         __u16 params, param_offset, offset, count, byte_count;
4657
4658         cFYI(1, ("In SetUID/GID/Mode"));
4659 setPermsRetry:
4660         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4661                       (void **) &pSMBr);
4662         if (rc)
4663                 return rc;
4664
4665         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4666                 name_len =
4667                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4668                                      PATH_MAX, nls_codepage, remap);
4669                 name_len++;     /* trailing null */
4670                 name_len *= 2;
4671         } else {        /* BB improve the check for buffer overruns BB */
4672                 name_len = strnlen(fileName, PATH_MAX);
4673                 name_len++;     /* trailing null */
4674                 strncpy(pSMB->FileName, fileName, name_len);
4675         }
4676
4677         params = 6 + name_len;
4678         count = sizeof (FILE_UNIX_BASIC_INFO);
4679         pSMB->MaxParameterCount = cpu_to_le16(2);
4680         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4681         pSMB->MaxSetupCount = 0;
4682         pSMB->Reserved = 0;
4683         pSMB->Flags = 0;
4684         pSMB->Timeout = 0;
4685         pSMB->Reserved2 = 0;
4686         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4687                                      InformationLevel) - 4;
4688         offset = param_offset + params;
4689         data_offset =
4690             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4691                                       offset);
4692         memset(data_offset, 0, count);
4693         pSMB->DataOffset = cpu_to_le16(offset);
4694         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4695         pSMB->SetupCount = 1;
4696         pSMB->Reserved3 = 0;
4697         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4698         byte_count = 3 /* pad */  + params + count;
4699         pSMB->ParameterCount = cpu_to_le16(params);
4700         pSMB->DataCount = cpu_to_le16(count);
4701         pSMB->TotalParameterCount = pSMB->ParameterCount;
4702         pSMB->TotalDataCount = pSMB->DataCount;
4703         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4704         pSMB->Reserved4 = 0;
4705         pSMB->hdr.smb_buf_length += byte_count;
4706         data_offset->Uid = cpu_to_le64(uid);
4707         data_offset->Gid = cpu_to_le64(gid);
4708         /* better to leave device as zero when it is  */
4709         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4710         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4711         data_offset->Permissions = cpu_to_le64(mode);
4712     
4713         if(S_ISREG(mode))
4714                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4715         else if(S_ISDIR(mode))
4716                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4717         else if(S_ISLNK(mode))
4718                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4719         else if(S_ISCHR(mode))
4720                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4721         else if(S_ISBLK(mode))
4722                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4723         else if(S_ISFIFO(mode))
4724                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4725         else if(S_ISSOCK(mode))
4726                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4727
4728
4729         pSMB->ByteCount = cpu_to_le16(byte_count);
4730         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4731                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4732         if (rc) {
4733                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4734         }
4735
4736         if (pSMB)
4737                 cifs_buf_release(pSMB);
4738         if (rc == -EAGAIN)
4739                 goto setPermsRetry;
4740         return rc;
4741 }
4742
4743 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4744                   const int notify_subdirs, const __u16 netfid,
4745                   __u32 filter, struct file * pfile, int multishot, 
4746                   const struct nls_table *nls_codepage)
4747 {
4748         int rc = 0;
4749         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4750         struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4751         struct dir_notify_req *dnotify_req;
4752         int bytes_returned;
4753
4754         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4755         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4756                       (void **) &pSMBr);
4757         if (rc)
4758                 return rc;
4759
4760         pSMB->TotalParameterCount = 0 ;
4761         pSMB->TotalDataCount = 0;
4762         pSMB->MaxParameterCount = cpu_to_le32(2);
4763         /* BB find exact data count max from sess structure BB */
4764         pSMB->MaxDataCount = 0; /* same in little endian or be */
4765 /* BB VERIFY verify which is correct for above BB */
4766         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4767                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4768
4769         pSMB->MaxSetupCount = 4;
4770         pSMB->Reserved = 0;
4771         pSMB->ParameterOffset = 0;
4772         pSMB->DataCount = 0;
4773         pSMB->DataOffset = 0;
4774         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4775         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4776         pSMB->ParameterCount = pSMB->TotalParameterCount;
4777         if(notify_subdirs)
4778                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4779         pSMB->Reserved2 = 0;
4780         pSMB->CompletionFilter = cpu_to_le32(filter);
4781         pSMB->Fid = netfid; /* file handle always le */
4782         pSMB->ByteCount = 0;
4783
4784         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4785                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4786         if (rc) {
4787                 cFYI(1, ("Error in Notify = %d", rc));
4788         } else {
4789                 /* Add file to outstanding requests */
4790                 /* BB change to kmem cache alloc */     
4791                 dnotify_req = (struct dir_notify_req *) kmalloc(
4792                                                 sizeof(struct dir_notify_req),
4793                                                  GFP_KERNEL);
4794                 if(dnotify_req) {
4795                         dnotify_req->Pid = pSMB->hdr.Pid;
4796                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4797                         dnotify_req->Mid = pSMB->hdr.Mid;
4798                         dnotify_req->Tid = pSMB->hdr.Tid;
4799                         dnotify_req->Uid = pSMB->hdr.Uid;
4800                         dnotify_req->netfid = netfid;
4801                         dnotify_req->pfile = pfile;
4802                         dnotify_req->filter = filter;
4803                         dnotify_req->multishot = multishot;
4804                         spin_lock(&GlobalMid_Lock);
4805                         list_add_tail(&dnotify_req->lhead, 
4806                                         &GlobalDnotifyReqList);
4807                         spin_unlock(&GlobalMid_Lock);
4808                 } else 
4809                         rc = -ENOMEM;
4810         }
4811         cifs_buf_release(pSMB);
4812         return rc;      
4813 }
4814 #ifdef CONFIG_CIFS_XATTR
4815 ssize_t
4816 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4817                  const unsigned char *searchName,
4818                  char * EAData, size_t buf_size,
4819                  const struct nls_table *nls_codepage, int remap)
4820 {
4821                 /* BB assumes one setup word */
4822         TRANSACTION2_QPI_REQ *pSMB = NULL;
4823         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4824         int rc = 0;
4825         int bytes_returned;
4826         int name_len;
4827         struct fea * temp_fea;
4828         char * temp_ptr;
4829         __u16 params, byte_count;
4830
4831         cFYI(1, ("In Query All EAs path %s", searchName));
4832 QAllEAsRetry:
4833         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4834                       (void **) &pSMBr);
4835         if (rc)
4836                 return rc;
4837
4838         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4839                 name_len =
4840                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4841                                      PATH_MAX, nls_codepage, remap);
4842                 name_len++;     /* trailing null */
4843                 name_len *= 2;
4844         } else {        /* BB improve the check for buffer overruns BB */
4845                 name_len = strnlen(searchName, PATH_MAX);
4846                 name_len++;     /* trailing null */
4847                 strncpy(pSMB->FileName, searchName, name_len);
4848         }
4849
4850         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4851         pSMB->TotalDataCount = 0;
4852         pSMB->MaxParameterCount = cpu_to_le16(2);
4853         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4854         pSMB->MaxSetupCount = 0;
4855         pSMB->Reserved = 0;
4856         pSMB->Flags = 0;
4857         pSMB->Timeout = 0;
4858         pSMB->Reserved2 = 0;
4859         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4860         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4861         pSMB->DataCount = 0;
4862         pSMB->DataOffset = 0;
4863         pSMB->SetupCount = 1;
4864         pSMB->Reserved3 = 0;
4865         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4866         byte_count = params + 1 /* pad */ ;
4867         pSMB->TotalParameterCount = cpu_to_le16(params);
4868         pSMB->ParameterCount = pSMB->TotalParameterCount;
4869         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4870         pSMB->Reserved4 = 0;
4871         pSMB->hdr.smb_buf_length += byte_count;
4872         pSMB->ByteCount = cpu_to_le16(byte_count);
4873
4874         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4875                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4876         if (rc) {
4877                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4878         } else {                /* decode response */
4879                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4880
4881                 /* BB also check enough total bytes returned */
4882                 /* BB we need to improve the validity checking
4883                 of these trans2 responses */
4884                 if (rc || (pSMBr->ByteCount < 4)) 
4885                         rc = -EIO;      /* bad smb */
4886            /* else if (pFindData){
4887                         memcpy((char *) pFindData,
4888                                (char *) &pSMBr->hdr.Protocol +
4889                                data_offset, kl);
4890                 }*/ else {
4891                         /* check that length of list is not more than bcc */
4892                         /* check that each entry does not go beyond length
4893                            of list */
4894                         /* check that each element of each entry does not
4895                            go beyond end of list */
4896                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4897                         struct fealist * ea_response_data;
4898                         rc = 0;
4899                         /* validate_trans2_offsets() */
4900                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4901                         ea_response_data = (struct fealist *)
4902                                 (((char *) &pSMBr->hdr.Protocol) +
4903                                 data_offset);
4904                         name_len = le32_to_cpu(ea_response_data->list_len);
4905                         cFYI(1,("ea length %d", name_len));
4906                         if(name_len <= 8) {
4907                         /* returned EA size zeroed at top of function */
4908                                 cFYI(1,("empty EA list returned from server"));
4909                         } else {
4910                                 /* account for ea list len */
4911                                 name_len -= 4;
4912                                 temp_fea = ea_response_data->list;
4913                                 temp_ptr = (char *)temp_fea;
4914                                 while(name_len > 0) {
4915                                         __u16 value_len;
4916                                         name_len -= 4;
4917                                         temp_ptr += 4;
4918                                         rc += temp_fea->name_len;
4919                                 /* account for prefix user. and trailing null */
4920                                         rc = rc + 5 + 1; 
4921                                         if(rc<(int)buf_size) {
4922                                                 memcpy(EAData,"user.",5);
4923                                                 EAData+=5;
4924                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4925                                                 EAData+=temp_fea->name_len;
4926                                                 /* null terminate name */
4927                                                 *EAData = 0;
4928                                                 EAData = EAData + 1;
4929                                         } else if(buf_size == 0) {
4930                                                 /* skip copy - calc size only */
4931                                         } else {
4932                                                 /* stop before overrun buffer */
4933                                                 rc = -ERANGE;
4934                                                 break;
4935                                         }
4936                                         name_len -= temp_fea->name_len;
4937                                         temp_ptr += temp_fea->name_len;
4938                                         /* account for trailing null */
4939                                         name_len--;
4940                                         temp_ptr++;
4941                                         value_len = le16_to_cpu(temp_fea->value_len);
4942                                         name_len -= value_len;
4943                                         temp_ptr += value_len;
4944                                         /* BB check that temp_ptr is still within smb BB*/
4945                                 /* no trailing null to account for in value len */
4946                                         /* go on to next EA */
4947                                         temp_fea = (struct fea *)temp_ptr;
4948                                 }
4949                         }
4950                 }
4951         }
4952         if (pSMB)
4953                 cifs_buf_release(pSMB);
4954         if (rc == -EAGAIN)
4955                 goto QAllEAsRetry;
4956
4957         return (ssize_t)rc;
4958 }
4959
4960 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4961                 const unsigned char * searchName,const unsigned char * ea_name,
4962                 unsigned char * ea_value, size_t buf_size, 
4963                 const struct nls_table *nls_codepage, int remap)
4964 {
4965         TRANSACTION2_QPI_REQ *pSMB = NULL;
4966         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4967         int rc = 0;
4968         int bytes_returned;
4969         int name_len;
4970         struct fea * temp_fea;
4971         char * temp_ptr;
4972         __u16 params, byte_count;
4973
4974         cFYI(1, ("In Query EA path %s", searchName));
4975 QEARetry:
4976         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4977                       (void **) &pSMBr);
4978         if (rc)
4979                 return rc;
4980
4981         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4982                 name_len =
4983                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4984                                      PATH_MAX, nls_codepage, remap);
4985                 name_len++;     /* trailing null */
4986                 name_len *= 2;
4987         } else {        /* BB improve the check for buffer overruns BB */
4988                 name_len = strnlen(searchName, PATH_MAX);
4989                 name_len++;     /* trailing null */
4990                 strncpy(pSMB->FileName, searchName, name_len);
4991         }
4992
4993         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4994         pSMB->TotalDataCount = 0;
4995         pSMB->MaxParameterCount = cpu_to_le16(2);
4996         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4997         pSMB->MaxSetupCount = 0;
4998         pSMB->Reserved = 0;
4999         pSMB->Flags = 0;
5000         pSMB->Timeout = 0;
5001         pSMB->Reserved2 = 0;
5002         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5003         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5004         pSMB->DataCount = 0;
5005         pSMB->DataOffset = 0;
5006         pSMB->SetupCount = 1;
5007         pSMB->Reserved3 = 0;
5008         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5009         byte_count = params + 1 /* pad */ ;
5010         pSMB->TotalParameterCount = cpu_to_le16(params);
5011         pSMB->ParameterCount = pSMB->TotalParameterCount;
5012         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5013         pSMB->Reserved4 = 0;
5014         pSMB->hdr.smb_buf_length += byte_count;
5015         pSMB->ByteCount = cpu_to_le16(byte_count);
5016
5017         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5018                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5019         if (rc) {
5020                 cFYI(1, ("Send error in Query EA = %d", rc));
5021         } else {                /* decode response */
5022                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5023
5024                 /* BB also check enough total bytes returned */
5025                 /* BB we need to improve the validity checking
5026                 of these trans2 responses */
5027                 if (rc || (pSMBr->ByteCount < 4)) 
5028                         rc = -EIO;      /* bad smb */
5029            /* else if (pFindData){
5030                         memcpy((char *) pFindData,
5031                                (char *) &pSMBr->hdr.Protocol +
5032                                data_offset, kl);
5033                 }*/ else {
5034                         /* check that length of list is not more than bcc */
5035                         /* check that each entry does not go beyond length
5036                            of list */
5037                         /* check that each element of each entry does not
5038                            go beyond end of list */
5039                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5040                         struct fealist * ea_response_data;
5041                         rc = -ENODATA;
5042                         /* validate_trans2_offsets() */
5043                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5044                         ea_response_data = (struct fealist *)
5045                                 (((char *) &pSMBr->hdr.Protocol) +
5046                                 data_offset);
5047                         name_len = le32_to_cpu(ea_response_data->list_len);
5048                         cFYI(1,("ea length %d", name_len));
5049                         if(name_len <= 8) {
5050                         /* returned EA size zeroed at top of function */
5051                                 cFYI(1,("empty EA list returned from server"));
5052                         } else {
5053                                 /* account for ea list len */
5054                                 name_len -= 4;
5055                                 temp_fea = ea_response_data->list;
5056                                 temp_ptr = (char *)temp_fea;
5057                                 /* loop through checking if we have a matching
5058                                 name and then return the associated value */
5059                                 while(name_len > 0) {
5060                                         __u16 value_len;
5061                                         name_len -= 4;
5062                                         temp_ptr += 4;
5063                                         value_len = le16_to_cpu(temp_fea->value_len);
5064                                 /* BB validate that value_len falls within SMB, 
5065                                 even though maximum for name_len is 255 */ 
5066                                         if(memcmp(temp_fea->name,ea_name,
5067                                                   temp_fea->name_len) == 0) {
5068                                                 /* found a match */
5069                                                 rc = value_len;
5070                                 /* account for prefix user. and trailing null */
5071                                                 if(rc<=(int)buf_size) {
5072                                                         memcpy(ea_value,
5073                                                                 temp_fea->name+temp_fea->name_len+1,
5074                                                                 rc);
5075                                                         /* ea values, unlike ea names,
5076                                                         are not null terminated */
5077                                                 } else if(buf_size == 0) {
5078                                                 /* skip copy - calc size only */
5079                                                 } else {
5080                                                         /* stop before overrun buffer */
5081                                                         rc = -ERANGE;
5082                                                 }
5083                                                 break;
5084                                         }
5085                                         name_len -= temp_fea->name_len;
5086                                         temp_ptr += temp_fea->name_len;
5087                                         /* account for trailing null */
5088                                         name_len--;
5089                                         temp_ptr++;
5090                                         name_len -= value_len;
5091                                         temp_ptr += value_len;
5092                                 /* no trailing null to account for in value len */
5093                                         /* go on to next EA */
5094                                         temp_fea = (struct fea *)temp_ptr;
5095                                 }
5096                         } 
5097                 }
5098         }
5099         if (pSMB)
5100                 cifs_buf_release(pSMB);
5101         if (rc == -EAGAIN)
5102                 goto QEARetry;
5103
5104         return (ssize_t)rc;
5105 }
5106
5107 int
5108 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5109                 const char * ea_name, const void * ea_value, 
5110                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5111                 int remap)
5112 {
5113         struct smb_com_transaction2_spi_req *pSMB = NULL;
5114         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5115         struct fealist *parm_data;
5116         int name_len;
5117         int rc = 0;
5118         int bytes_returned = 0;
5119         __u16 params, param_offset, byte_count, offset, count;
5120
5121         cFYI(1, ("In SetEA"));
5122 SetEARetry:
5123         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5124                       (void **) &pSMBr);
5125         if (rc)
5126                 return rc;
5127
5128         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5129                 name_len =
5130                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
5131                                      PATH_MAX, nls_codepage, remap);
5132                 name_len++;     /* trailing null */
5133                 name_len *= 2;
5134         } else {                /* BB improve the check for buffer overruns BB */
5135                 name_len = strnlen(fileName, PATH_MAX);
5136                 name_len++;     /* trailing null */
5137                 strncpy(pSMB->FileName, fileName, name_len);
5138         }
5139
5140         params = 6 + name_len;
5141
5142         /* done calculating parms using name_len of file name,
5143         now use name_len to calculate length of ea name
5144         we are going to create in the inode xattrs */
5145         if(ea_name == NULL)
5146                 name_len = 0;
5147         else
5148                 name_len = strnlen(ea_name,255);
5149
5150         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5151         pSMB->MaxParameterCount = cpu_to_le16(2);
5152         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5153         pSMB->MaxSetupCount = 0;
5154         pSMB->Reserved = 0;
5155         pSMB->Flags = 0;
5156         pSMB->Timeout = 0;
5157         pSMB->Reserved2 = 0;
5158         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5159                                      InformationLevel) - 4;
5160         offset = param_offset + params;
5161         pSMB->InformationLevel =
5162                 cpu_to_le16(SMB_SET_FILE_EA);
5163
5164         parm_data =
5165                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5166                                        offset);
5167         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5168         pSMB->DataOffset = cpu_to_le16(offset);
5169         pSMB->SetupCount = 1;
5170         pSMB->Reserved3 = 0;
5171         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5172         byte_count = 3 /* pad */  + params + count;
5173         pSMB->DataCount = cpu_to_le16(count);
5174         parm_data->list_len = cpu_to_le32(count);
5175         parm_data->list[0].EA_flags = 0;
5176         /* we checked above that name len is less than 255 */
5177         parm_data->list[0].name_len = (__u8)name_len;
5178         /* EA names are always ASCII */
5179         if(ea_name)
5180                 strncpy(parm_data->list[0].name,ea_name,name_len);
5181         parm_data->list[0].name[name_len] = 0;
5182         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5183         /* caller ensures that ea_value_len is less than 64K but
5184         we need to ensure that it fits within the smb */
5185
5186         /*BB add length check that it would fit in negotiated SMB buffer size BB */
5187         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5188         if(ea_value_len)
5189                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5190
5191         pSMB->TotalDataCount = pSMB->DataCount;
5192         pSMB->ParameterCount = cpu_to_le16(params);
5193         pSMB->TotalParameterCount = pSMB->ParameterCount;
5194         pSMB->Reserved4 = 0;
5195         pSMB->hdr.smb_buf_length += byte_count;
5196         pSMB->ByteCount = cpu_to_le16(byte_count);
5197         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5198                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5199         if (rc) {
5200                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5201         }
5202
5203         cifs_buf_release(pSMB);
5204
5205         if (rc == -EAGAIN)
5206                 goto SetEARetry;
5207
5208         return rc;
5209 }
5210
5211 #endif