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