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