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