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