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