[CIFS] Finishup DFS code
[firefly-linux-kernel-4.4.55.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2008
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly differently for reconnection purposes since we never     */
28  /* want to reuse a stale file handle and only the caller knows the file info */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsacl.h"
38 #include "cifsproto.h"
39 #include "cifs_unicode.h"
40 #include "cifs_debug.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44         int index;
45         char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48         {LANMAN_PROT, "\2LM1.2X002"},
49         {LANMAN2_PROT, "\2LANMAN2.1"},
50 #endif /* weak password hashing for legacy clients */
51         {CIFS_PROT, "\2NT LM 0.12"},
52         {POSIX_PROT, "\2POSIX 2"},
53         {BAD_PROT, "\2"}
54 };
55 #else
56 static struct {
57         int index;
58         char *name;
59 } protocols[] = {
60 #ifdef CONFIG_CIFS_WEAK_PW_HASH
61         {LANMAN_PROT, "\2LM1.2X002"},
62         {LANMAN2_PROT, "\2LANMAN2.1"},
63 #endif /* weak password hashing for legacy clients */
64         {CIFS_PROT, "\2NT LM 0.12"},
65         {BAD_PROT, "\2"}
66 };
67 #endif
68
69 /* define the number of elements in the cifs dialect array */
70 #ifdef CONFIG_CIFS_POSIX
71 #ifdef CONFIG_CIFS_WEAK_PW_HASH
72 #define CIFS_NUM_PROT 4
73 #else
74 #define CIFS_NUM_PROT 2
75 #endif /* CIFS_WEAK_PW_HASH */
76 #else /* not posix */
77 #ifdef CONFIG_CIFS_WEAK_PW_HASH
78 #define CIFS_NUM_PROT 3
79 #else
80 #define CIFS_NUM_PROT 1
81 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
82 #endif /* CIFS_POSIX */
83
84
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 static int
1170 access_flags_to_smbopen_mode(const int access_flags)
1171 {
1172         int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1173
1174         if (masked_flags == GENERIC_READ)
1175                 return SMBOPEN_READ;
1176         else if (masked_flags == GENERIC_WRITE)
1177                 return SMBOPEN_WRITE;
1178
1179         /* just go for read/write */
1180         return SMBOPEN_READWRITE;
1181 }
1182
1183 int
1184 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1185             const char *fileName, const int openDisposition,
1186             const int access_flags, const int create_options, __u16 *netfid,
1187             int *pOplock, FILE_ALL_INFO *pfile_info,
1188             const struct nls_table *nls_codepage, int remap)
1189 {
1190         int rc = -EACCES;
1191         OPENX_REQ *pSMB = NULL;
1192         OPENX_RSP *pSMBr = NULL;
1193         int bytes_returned;
1194         int name_len;
1195         __u16 count;
1196
1197 OldOpenRetry:
1198         rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199                       (void **) &pSMBr);
1200         if (rc)
1201                 return rc;
1202
1203         pSMB->AndXCommand = 0xFF;       /* none */
1204
1205         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206                 count = 1;      /* account for one byte pad to word boundary */
1207                 name_len =
1208                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1209                                     fileName, PATH_MAX, nls_codepage, remap);
1210                 name_len++;     /* trailing null */
1211                 name_len *= 2;
1212         } else {                /* BB improve check for buffer overruns BB */
1213                 count = 0;      /* no pad */
1214                 name_len = strnlen(fileName, PATH_MAX);
1215                 name_len++;     /* trailing null */
1216                 strncpy(pSMB->fileName, fileName, name_len);
1217         }
1218         if (*pOplock & REQ_OPLOCK)
1219                 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1220         else if (*pOplock & REQ_BATCHOPLOCK)
1221                 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1222
1223         pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1224         pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1225         pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226         /* set file as system file if special file such
1227            as fifo and server expecting SFU style and
1228            no Unix extensions */
1229
1230         if (create_options & CREATE_OPTION_SPECIAL)
1231                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1232         else /* BB FIXME BB */
1233                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1234
1235         if (create_options & CREATE_OPTION_READONLY)
1236                 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1237
1238         /* BB FIXME BB */
1239 /*      pSMB->CreateOptions = cpu_to_le32(create_options &
1240                                                  CREATE_OPTIONS_MASK); */
1241         /* BB FIXME END BB */
1242
1243         pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1244         pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1245         count += name_len;
1246         pSMB->hdr.smb_buf_length += count;
1247
1248         pSMB->ByteCount = cpu_to_le16(count);
1249         /* long_op set to 1 to allow for oplock break timeouts */
1250         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1251                         (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1252         cifs_stats_inc(&tcon->num_opens);
1253         if (rc) {
1254                 cFYI(1, ("Error in Open = %d", rc));
1255         } else {
1256         /* BB verify if wct == 15 */
1257
1258 /*              *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1259
1260                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1261                 /* Let caller know file was created so we can set the mode. */
1262                 /* Do we care about the CreateAction in any other cases? */
1263         /* BB FIXME BB */
1264 /*              if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1265                         *pOplock |= CIFS_CREATE_ACTION; */
1266         /* BB FIXME END */
1267
1268                 if (pfile_info) {
1269                         pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270                         pfile_info->LastAccessTime = 0; /* BB fixme */
1271                         pfile_info->LastWriteTime = 0; /* BB fixme */
1272                         pfile_info->ChangeTime = 0;  /* BB fixme */
1273                         pfile_info->Attributes =
1274                                 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1275                         /* the file_info buf is endian converted by caller */
1276                         pfile_info->AllocationSize =
1277                                 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278                         pfile_info->EndOfFile = pfile_info->AllocationSize;
1279                         pfile_info->NumberOfLinks = cpu_to_le32(1);
1280                 }
1281         }
1282
1283         cifs_buf_release(pSMB);
1284         if (rc == -EAGAIN)
1285                 goto OldOpenRetry;
1286         return rc;
1287 }
1288
1289 int
1290 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1291             const char *fileName, const int openDisposition,
1292             const int access_flags, const int create_options, __u16 *netfid,
1293             int *pOplock, FILE_ALL_INFO *pfile_info,
1294             const struct nls_table *nls_codepage, int remap)
1295 {
1296         int rc = -EACCES;
1297         OPEN_REQ *pSMB = NULL;
1298         OPEN_RSP *pSMBr = NULL;
1299         int bytes_returned;
1300         int name_len;
1301         __u16 count;
1302
1303 openRetry:
1304         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1305                       (void **) &pSMBr);
1306         if (rc)
1307                 return rc;
1308
1309         pSMB->AndXCommand = 0xFF;       /* none */
1310
1311         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1312                 count = 1;      /* account for one byte pad to word boundary */
1313                 name_len =
1314                     cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1315                                      fileName, PATH_MAX, nls_codepage, remap);
1316                 name_len++;     /* trailing null */
1317                 name_len *= 2;
1318                 pSMB->NameLength = cpu_to_le16(name_len);
1319         } else {                /* BB improve check for buffer overruns BB */
1320                 count = 0;      /* no pad */
1321                 name_len = strnlen(fileName, PATH_MAX);
1322                 name_len++;     /* trailing null */
1323                 pSMB->NameLength = cpu_to_le16(name_len);
1324                 strncpy(pSMB->fileName, fileName, name_len);
1325         }
1326         if (*pOplock & REQ_OPLOCK)
1327                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1328         else if (*pOplock & REQ_BATCHOPLOCK)
1329                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1330         pSMB->DesiredAccess = cpu_to_le32(access_flags);
1331         pSMB->AllocationSize = 0;
1332         /* set file as system file if special file such
1333            as fifo and server expecting SFU style and
1334            no Unix extensions */
1335         if (create_options & CREATE_OPTION_SPECIAL)
1336                 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1337         else
1338                 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1339
1340         /* XP does not handle ATTR_POSIX_SEMANTICS */
1341         /* but it helps speed up case sensitive checks for other
1342         servers such as Samba */
1343         if (tcon->ses->capabilities & CAP_UNIX)
1344                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1345
1346         if (create_options & CREATE_OPTION_READONLY)
1347                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1348
1349         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1350         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1351         pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1352         /* BB Expirement with various impersonation levels and verify */
1353         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1354         pSMB->SecurityFlags =
1355             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1356
1357         count += name_len;
1358         pSMB->hdr.smb_buf_length += count;
1359
1360         pSMB->ByteCount = cpu_to_le16(count);
1361         /* long_op set to 1 to allow for oplock break timeouts */
1362         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1363                         (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1364         cifs_stats_inc(&tcon->num_opens);
1365         if (rc) {
1366                 cFYI(1, ("Error in Open = %d", rc));
1367         } else {
1368                 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1369                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1370                 /* Let caller know file was created so we can set the mode. */
1371                 /* Do we care about the CreateAction in any other cases? */
1372                 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1373                         *pOplock |= CIFS_CREATE_ACTION;
1374                 if (pfile_info) {
1375                     memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1376                         36 /* CreationTime to Attributes */);
1377                     /* the file_info buf is endian converted by caller */
1378                     pfile_info->AllocationSize = pSMBr->AllocationSize;
1379                     pfile_info->EndOfFile = pSMBr->EndOfFile;
1380                     pfile_info->NumberOfLinks = cpu_to_le32(1);
1381                 }
1382         }
1383
1384         cifs_buf_release(pSMB);
1385         if (rc == -EAGAIN)
1386                 goto openRetry;
1387         return rc;
1388 }
1389
1390 int
1391 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1392             const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1393             char **buf, int *pbuf_type)
1394 {
1395         int rc = -EACCES;
1396         READ_REQ *pSMB = NULL;
1397         READ_RSP *pSMBr = NULL;
1398         char *pReadData = NULL;
1399         int wct;
1400         int resp_buf_type = 0;
1401         struct kvec iov[1];
1402
1403         cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1404         if (tcon->ses->capabilities & CAP_LARGE_FILES)
1405                 wct = 12;
1406         else
1407                 wct = 10; /* old style read */
1408
1409         *nbytes = 0;
1410         rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1411         if (rc)
1412                 return rc;
1413
1414         /* tcon and ses pointer are checked in smb_init */
1415         if (tcon->ses->server == NULL)
1416                 return -ECONNABORTED;
1417
1418         pSMB->AndXCommand = 0xFF;       /* none */
1419         pSMB->Fid = netfid;
1420         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1421         if (wct == 12)
1422                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1423         else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
1424                 return -EIO;
1425
1426         pSMB->Remaining = 0;
1427         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1428         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1429         if (wct == 12)
1430                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1431         else {
1432                 /* old style read */
1433                 struct smb_com_readx_req *pSMBW =
1434                         (struct smb_com_readx_req *)pSMB;
1435                 pSMBW->ByteCount = 0;
1436         }
1437
1438         iov[0].iov_base = (char *)pSMB;
1439         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1440         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1441                          &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1442         cifs_stats_inc(&tcon->num_reads);
1443         pSMBr = (READ_RSP *)iov[0].iov_base;
1444         if (rc) {
1445                 cERROR(1, ("Send error in read = %d", rc));
1446         } else {
1447                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1448                 data_length = data_length << 16;
1449                 data_length += le16_to_cpu(pSMBr->DataLength);
1450                 *nbytes = data_length;
1451
1452                 /*check that DataLength would not go beyond end of SMB */
1453                 if ((data_length > CIFSMaxBufSize)
1454                                 || (data_length > count)) {
1455                         cFYI(1, ("bad length %d for count %d",
1456                                  data_length, count));
1457                         rc = -EIO;
1458                         *nbytes = 0;
1459                 } else {
1460                         pReadData = (char *) (&pSMBr->hdr.Protocol) +
1461                                         le16_to_cpu(pSMBr->DataOffset);
1462 /*                      if (rc = copy_to_user(buf, pReadData, data_length)) {
1463                                 cERROR(1,("Faulting on read rc = %d",rc));
1464                                 rc = -EFAULT;
1465                         }*/ /* can not use copy_to_user when using page cache*/
1466                         if (*buf)
1467                                 memcpy(*buf, pReadData, data_length);
1468                 }
1469         }
1470
1471 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1472         if (*buf) {
1473                 if (resp_buf_type == CIFS_SMALL_BUFFER)
1474                         cifs_small_buf_release(iov[0].iov_base);
1475                 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1476                         cifs_buf_release(iov[0].iov_base);
1477         } else if (resp_buf_type != CIFS_NO_BUFFER) {
1478                 /* return buffer to caller to free */
1479                 *buf = iov[0].iov_base;
1480                 if (resp_buf_type == CIFS_SMALL_BUFFER)
1481                         *pbuf_type = CIFS_SMALL_BUFFER;
1482                 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1483                         *pbuf_type = CIFS_LARGE_BUFFER;
1484         } /* else no valid buffer on return - leave as null */
1485
1486         /* Note: On -EAGAIN error only caller can retry on handle based calls
1487                 since file handle passed in no longer valid */
1488         return rc;
1489 }
1490
1491
1492 int
1493 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1494              const int netfid, const unsigned int count,
1495              const __u64 offset, unsigned int *nbytes, const char *buf,
1496              const char __user *ubuf, const int long_op)
1497 {
1498         int rc = -EACCES;
1499         WRITE_REQ *pSMB = NULL;
1500         WRITE_RSP *pSMBr = NULL;
1501         int bytes_returned, wct;
1502         __u32 bytes_sent;
1503         __u16 byte_count;
1504
1505         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1506         if (tcon->ses == NULL)
1507                 return -ECONNABORTED;
1508
1509         if (tcon->ses->capabilities & CAP_LARGE_FILES)
1510                 wct = 14;
1511         else
1512                 wct = 12;
1513
1514         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1515                       (void **) &pSMBr);
1516         if (rc)
1517                 return rc;
1518         /* tcon and ses pointer are checked in smb_init */
1519         if (tcon->ses->server == NULL)
1520                 return -ECONNABORTED;
1521
1522         pSMB->AndXCommand = 0xFF;       /* none */
1523         pSMB->Fid = netfid;
1524         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1525         if (wct == 14)
1526                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1527         else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1528                 return -EIO;
1529
1530         pSMB->Reserved = 0xFFFFFFFF;
1531         pSMB->WriteMode = 0;
1532         pSMB->Remaining = 0;
1533
1534         /* Can increase buffer size if buffer is big enough in some cases ie we
1535         can send more if LARGE_WRITE_X capability returned by the server and if
1536         our buffer is big enough or if we convert to iovecs on socket writes
1537         and eliminate the copy to the CIFS buffer */
1538         if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1539                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1540         } else {
1541                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1542                          & ~0xFF;
1543         }
1544
1545         if (bytes_sent > count)
1546                 bytes_sent = count;
1547         pSMB->DataOffset =
1548                 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1549         if (buf)
1550             memcpy(pSMB->Data, buf, bytes_sent);
1551         else if (ubuf) {
1552                 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1553                         cifs_buf_release(pSMB);
1554                         return -EFAULT;
1555                 }
1556         } else if (count != 0) {
1557                 /* No buffer */
1558                 cifs_buf_release(pSMB);
1559                 return -EINVAL;
1560         } /* else setting file size with write of zero bytes */
1561         if (wct == 14)
1562                 byte_count = bytes_sent + 1; /* pad */
1563         else /* wct == 12 */
1564                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1565
1566         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1567         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1568         pSMB->hdr.smb_buf_length += byte_count;
1569
1570         if (wct == 14)
1571                 pSMB->ByteCount = cpu_to_le16(byte_count);
1572         else { /* old style write has byte count 4 bytes earlier
1573                   so 4 bytes pad  */
1574                 struct smb_com_writex_req *pSMBW =
1575                         (struct smb_com_writex_req *)pSMB;
1576                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1577         }
1578
1579         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1580                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1581         cifs_stats_inc(&tcon->num_writes);
1582         if (rc) {
1583                 cFYI(1, ("Send error in write = %d", rc));
1584                 *nbytes = 0;
1585         } else {
1586                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1587                 *nbytes = (*nbytes) << 16;
1588                 *nbytes += le16_to_cpu(pSMBr->Count);
1589         }
1590
1591         cifs_buf_release(pSMB);
1592
1593         /* Note: On -EAGAIN error only caller can retry on handle based calls
1594                 since file handle passed in no longer valid */
1595
1596         return rc;
1597 }
1598
1599 int
1600 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1601              const int netfid, const unsigned int count,
1602              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1603              int n_vec, const int long_op)
1604 {
1605         int rc = -EACCES;
1606         WRITE_REQ *pSMB = NULL;
1607         int wct;
1608         int smb_hdr_len;
1609         int resp_buf_type = 0;
1610
1611         cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1612
1613         if (tcon->ses->capabilities & CAP_LARGE_FILES)
1614                 wct = 14;
1615         else
1616                 wct = 12;
1617         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1618         if (rc)
1619                 return rc;
1620         /* tcon and ses pointer are checked in smb_init */
1621         if (tcon->ses->server == NULL)
1622                 return -ECONNABORTED;
1623
1624         pSMB->AndXCommand = 0xFF;       /* none */
1625         pSMB->Fid = netfid;
1626         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1627         if (wct == 14)
1628                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1629         else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1630                 return -EIO;
1631         pSMB->Reserved = 0xFFFFFFFF;
1632         pSMB->WriteMode = 0;
1633         pSMB->Remaining = 0;
1634
1635         pSMB->DataOffset =
1636             cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1637
1638         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1639         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1640         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1641         if (wct == 14)
1642                 pSMB->hdr.smb_buf_length += count+1;
1643         else /* wct == 12 */
1644                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1645         if (wct == 14)
1646                 pSMB->ByteCount = cpu_to_le16(count + 1);
1647         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1648                 struct smb_com_writex_req *pSMBW =
1649                                 (struct smb_com_writex_req *)pSMB;
1650                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1651         }
1652         iov[0].iov_base = pSMB;
1653         if (wct == 14)
1654                 iov[0].iov_len = smb_hdr_len + 4;
1655         else /* wct == 12 pad bigger by four bytes */
1656                 iov[0].iov_len = smb_hdr_len + 8;
1657
1658
1659         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1660                           long_op);
1661         cifs_stats_inc(&tcon->num_writes);
1662         if (rc) {
1663                 cFYI(1, ("Send error Write2 = %d", rc));
1664                 *nbytes = 0;
1665         } else if (resp_buf_type == 0) {
1666                 /* presumably this can not happen, but best to be safe */
1667                 rc = -EIO;
1668                 *nbytes = 0;
1669         } else {
1670                 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1671                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1672                 *nbytes = (*nbytes) << 16;
1673                 *nbytes += le16_to_cpu(pSMBr->Count);
1674         }
1675
1676 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1677         if (resp_buf_type == CIFS_SMALL_BUFFER)
1678                 cifs_small_buf_release(iov[0].iov_base);
1679         else if (resp_buf_type == CIFS_LARGE_BUFFER)
1680                 cifs_buf_release(iov[0].iov_base);
1681
1682         /* Note: On -EAGAIN error only caller can retry on handle based calls
1683                 since file handle passed in no longer valid */
1684
1685         return rc;
1686 }
1687
1688
1689 int
1690 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1691             const __u16 smb_file_id, const __u64 len,
1692             const __u64 offset, const __u32 numUnlock,
1693             const __u32 numLock, const __u8 lockType, const bool waitFlag)
1694 {
1695         int rc = 0;
1696         LOCK_REQ *pSMB = NULL;
1697         LOCK_RSP *pSMBr = NULL;
1698         int bytes_returned;
1699         int timeout = 0;
1700         __u16 count;
1701
1702         cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1703         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1704
1705         if (rc)
1706                 return rc;
1707
1708         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1709
1710         if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1711                 timeout = CIFS_ASYNC_OP; /* no response expected */
1712                 pSMB->Timeout = 0;
1713         } else if (waitFlag) {
1714                 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1715                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1716         } else {
1717                 pSMB->Timeout = 0;
1718         }
1719
1720         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1721         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1722         pSMB->LockType = lockType;
1723         pSMB->AndXCommand = 0xFF;       /* none */
1724         pSMB->Fid = smb_file_id; /* netfid stays le */
1725
1726         if ((numLock != 0) || (numUnlock != 0)) {
1727                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1728                 /* BB where to store pid high? */
1729                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1730                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1731                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1732                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1733                 count = sizeof(LOCKING_ANDX_RANGE);
1734         } else {
1735                 /* oplock break */
1736                 count = 0;
1737         }
1738         pSMB->hdr.smb_buf_length += count;
1739         pSMB->ByteCount = cpu_to_le16(count);
1740
1741         if (waitFlag) {
1742                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1743                         (struct smb_hdr *) pSMBr, &bytes_returned);
1744                 cifs_small_buf_release(pSMB);
1745         } else {
1746                 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1747                                       timeout);
1748                 /* SMB buffer freed by function above */
1749         }
1750         cifs_stats_inc(&tcon->num_locks);
1751         if (rc)
1752                 cFYI(1, ("Send error in Lock = %d", rc));
1753
1754         /* Note: On -EAGAIN error only caller can retry on handle based calls
1755         since file handle passed in no longer valid */
1756         return rc;
1757 }
1758
1759 int
1760 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1761                 const __u16 smb_file_id, const int get_flag, const __u64 len,
1762                 struct file_lock *pLockData, const __u16 lock_type,
1763                 const bool waitFlag)
1764 {
1765         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1766         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1767         struct cifs_posix_lock *parm_data;
1768         int rc = 0;
1769         int timeout = 0;
1770         int bytes_returned = 0;
1771         int resp_buf_type = 0;
1772         __u16 params, param_offset, offset, byte_count, count;
1773         struct kvec iov[1];
1774
1775         cFYI(1, ("Posix Lock"));
1776
1777         if (pLockData == NULL)
1778                 return -EINVAL;
1779
1780         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1781
1782         if (rc)
1783                 return rc;
1784
1785         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1786
1787         params = 6;
1788         pSMB->MaxSetupCount = 0;
1789         pSMB->Reserved = 0;
1790         pSMB->Flags = 0;
1791         pSMB->Reserved2 = 0;
1792         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1793         offset = param_offset + params;
1794
1795         count = sizeof(struct cifs_posix_lock);
1796         pSMB->MaxParameterCount = cpu_to_le16(2);
1797         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1798         pSMB->SetupCount = 1;
1799         pSMB->Reserved3 = 0;
1800         if (get_flag)
1801                 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1802         else
1803                 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1804         byte_count = 3 /* pad */  + params + count;
1805         pSMB->DataCount = cpu_to_le16(count);
1806         pSMB->ParameterCount = cpu_to_le16(params);
1807         pSMB->TotalDataCount = pSMB->DataCount;
1808         pSMB->TotalParameterCount = pSMB->ParameterCount;
1809         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1810         parm_data = (struct cifs_posix_lock *)
1811                         (((char *) &pSMB->hdr.Protocol) + offset);
1812
1813         parm_data->lock_type = cpu_to_le16(lock_type);
1814         if (waitFlag) {
1815                 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1816                 parm_data->lock_flags = cpu_to_le16(1);
1817                 pSMB->Timeout = cpu_to_le32(-1);
1818         } else
1819                 pSMB->Timeout = 0;
1820
1821         parm_data->pid = cpu_to_le32(current->tgid);
1822         parm_data->start = cpu_to_le64(pLockData->fl_start);
1823         parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
1824
1825         pSMB->DataOffset = cpu_to_le16(offset);
1826         pSMB->Fid = smb_file_id;
1827         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1828         pSMB->Reserved4 = 0;
1829         pSMB->hdr.smb_buf_length += byte_count;
1830         pSMB->ByteCount = cpu_to_le16(byte_count);
1831         if (waitFlag) {
1832                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1833                         (struct smb_hdr *) pSMBr, &bytes_returned);
1834         } else {
1835                 iov[0].iov_base = (char *)pSMB;
1836                 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1837                 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1838                                 &resp_buf_type, timeout);
1839                 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1840                                 not try to free it twice below on exit */
1841                 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1842         }
1843
1844         if (rc) {
1845                 cFYI(1, ("Send error in Posix Lock = %d", rc));
1846         } else if (get_flag) {
1847                 /* lock structure can be returned on get */
1848                 __u16 data_offset;
1849                 __u16 data_count;
1850                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1851
1852                 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1853                         rc = -EIO;      /* bad smb */
1854                         goto plk_err_exit;
1855                 }
1856                 if (pLockData == NULL) {
1857                         rc = -EINVAL;
1858                         goto plk_err_exit;
1859                 }
1860                 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1861                 data_count  = le16_to_cpu(pSMBr->t2.DataCount);
1862                 if (data_count < sizeof(struct cifs_posix_lock)) {
1863                         rc = -EIO;
1864                         goto plk_err_exit;
1865                 }
1866                 parm_data = (struct cifs_posix_lock *)
1867                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1868                 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1869                         pLockData->fl_type = F_UNLCK;
1870         }
1871
1872 plk_err_exit:
1873         if (pSMB)
1874                 cifs_small_buf_release(pSMB);
1875
1876         if (resp_buf_type == CIFS_SMALL_BUFFER)
1877                 cifs_small_buf_release(iov[0].iov_base);
1878         else if (resp_buf_type == CIFS_LARGE_BUFFER)
1879                 cifs_buf_release(iov[0].iov_base);
1880
1881         /* Note: On -EAGAIN error only caller can retry on handle based calls
1882            since file handle passed in no longer valid */
1883
1884         return rc;
1885 }
1886
1887
1888 int
1889 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1890 {
1891         int rc = 0;
1892         CLOSE_REQ *pSMB = NULL;
1893         cFYI(1, ("In CIFSSMBClose"));
1894
1895 /* do not retry on dead session on close */
1896         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1897         if (rc == -EAGAIN)
1898                 return 0;
1899         if (rc)
1900                 return rc;
1901
1902         pSMB->FileID = (__u16) smb_file_id;
1903         pSMB->LastWriteTime = 0xFFFFFFFF;
1904         pSMB->ByteCount = 0;
1905         rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1906         cifs_stats_inc(&tcon->num_closes);
1907         if (rc) {
1908                 if (rc != -EINTR) {
1909                         /* EINTR is expected when user ctl-c to kill app */
1910                         cERROR(1, ("Send error in Close = %d", rc));
1911                 }
1912         }
1913
1914         /* Since session is dead, file will be closed on server already */
1915         if (rc == -EAGAIN)
1916                 rc = 0;
1917
1918         return rc;
1919 }
1920
1921 int
1922 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1923               const char *fromName, const char *toName,
1924               const struct nls_table *nls_codepage, int remap)
1925 {
1926         int rc = 0;
1927         RENAME_REQ *pSMB = NULL;
1928         RENAME_RSP *pSMBr = NULL;
1929         int bytes_returned;
1930         int name_len, name_len2;
1931         __u16 count;
1932
1933         cFYI(1, ("In CIFSSMBRename"));
1934 renameRetry:
1935         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1936                       (void **) &pSMBr);
1937         if (rc)
1938                 return rc;
1939
1940         pSMB->BufferFormat = 0x04;
1941         pSMB->SearchAttributes =
1942             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1943                         ATTR_DIRECTORY);
1944
1945         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1946                 name_len =
1947                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1948                                      PATH_MAX, nls_codepage, remap);
1949                 name_len++;     /* trailing null */
1950                 name_len *= 2;
1951                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1952         /* protocol requires ASCII signature byte on Unicode string */
1953                 pSMB->OldFileName[name_len + 1] = 0x00;
1954                 name_len2 =
1955                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1956                                      toName, PATH_MAX, nls_codepage, remap);
1957                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1958                 name_len2 *= 2; /* convert to bytes */
1959         } else {        /* BB improve the check for buffer overruns BB */
1960                 name_len = strnlen(fromName, PATH_MAX);
1961                 name_len++;     /* trailing null */
1962                 strncpy(pSMB->OldFileName, fromName, name_len);
1963                 name_len2 = strnlen(toName, PATH_MAX);
1964                 name_len2++;    /* trailing null */
1965                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1966                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1967                 name_len2++;    /* trailing null */
1968                 name_len2++;    /* signature byte */
1969         }
1970
1971         count = 1 /* 1st signature byte */  + name_len + name_len2;
1972         pSMB->hdr.smb_buf_length += count;
1973         pSMB->ByteCount = cpu_to_le16(count);
1974
1975         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1976                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1977         cifs_stats_inc(&tcon->num_renames);
1978         if (rc)
1979                 cFYI(1, ("Send error in rename = %d", rc));
1980
1981         cifs_buf_release(pSMB);
1982
1983         if (rc == -EAGAIN)
1984                 goto renameRetry;
1985
1986         return rc;
1987 }
1988
1989 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1990                 int netfid, char *target_name,
1991                 const struct nls_table *nls_codepage, int remap)
1992 {
1993         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1994         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1995         struct set_file_rename *rename_info;
1996         char *data_offset;
1997         char dummy_string[30];
1998         int rc = 0;
1999         int bytes_returned = 0;
2000         int len_of_str;
2001         __u16 params, param_offset, offset, count, byte_count;
2002
2003         cFYI(1, ("Rename to File by handle"));
2004         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2005                         (void **) &pSMBr);
2006         if (rc)
2007                 return rc;
2008
2009         params = 6;
2010         pSMB->MaxSetupCount = 0;
2011         pSMB->Reserved = 0;
2012         pSMB->Flags = 0;
2013         pSMB->Timeout = 0;
2014         pSMB->Reserved2 = 0;
2015         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2016         offset = param_offset + params;
2017
2018         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2019         rename_info = (struct set_file_rename *) data_offset;
2020         pSMB->MaxParameterCount = cpu_to_le16(2);
2021         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2022         pSMB->SetupCount = 1;
2023         pSMB->Reserved3 = 0;
2024         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2025         byte_count = 3 /* pad */  + params;
2026         pSMB->ParameterCount = cpu_to_le16(params);
2027         pSMB->TotalParameterCount = pSMB->ParameterCount;
2028         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2029         pSMB->DataOffset = cpu_to_le16(offset);
2030         /* construct random name ".cifs_tmp<inodenum><mid>" */
2031         rename_info->overwrite = cpu_to_le32(1);
2032         rename_info->root_fid  = 0;
2033         /* unicode only call */
2034         if (target_name == NULL) {
2035                 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2036                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2037                                         dummy_string, 24, nls_codepage, remap);
2038         } else {
2039                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2040                                         target_name, PATH_MAX, nls_codepage,
2041                                         remap);
2042         }
2043         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2044         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2045         byte_count += count;
2046         pSMB->DataCount = cpu_to_le16(count);
2047         pSMB->TotalDataCount = pSMB->DataCount;
2048         pSMB->Fid = netfid;
2049         pSMB->InformationLevel =
2050                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2051         pSMB->Reserved4 = 0;
2052         pSMB->hdr.smb_buf_length += byte_count;
2053         pSMB->ByteCount = cpu_to_le16(byte_count);
2054         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2055                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2056         cifs_stats_inc(&pTcon->num_t2renames);
2057         if (rc)
2058                 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2059
2060         cifs_buf_release(pSMB);
2061
2062         /* Note: On -EAGAIN error only caller can retry on handle based calls
2063                 since file handle passed in no longer valid */
2064
2065         return rc;
2066 }
2067
2068 int
2069 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2070             const __u16 target_tid, const char *toName, const int flags,
2071             const struct nls_table *nls_codepage, int remap)
2072 {
2073         int rc = 0;
2074         COPY_REQ *pSMB = NULL;
2075         COPY_RSP *pSMBr = NULL;
2076         int bytes_returned;
2077         int name_len, name_len2;
2078         __u16 count;
2079
2080         cFYI(1, ("In CIFSSMBCopy"));
2081 copyRetry:
2082         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2083                         (void **) &pSMBr);
2084         if (rc)
2085                 return rc;
2086
2087         pSMB->BufferFormat = 0x04;
2088         pSMB->Tid2 = target_tid;
2089
2090         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2091
2092         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2093                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2094                                             fromName, PATH_MAX, nls_codepage,
2095                                             remap);
2096                 name_len++;     /* trailing null */
2097                 name_len *= 2;
2098                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
2099                 /* protocol requires ASCII signature byte on Unicode string */
2100                 pSMB->OldFileName[name_len + 1] = 0x00;
2101                 name_len2 =
2102                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2103                                 toName, PATH_MAX, nls_codepage, remap);
2104                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2105                 name_len2 *= 2; /* convert to bytes */
2106         } else {        /* BB improve the check for buffer overruns BB */
2107                 name_len = strnlen(fromName, PATH_MAX);
2108                 name_len++;     /* trailing null */
2109                 strncpy(pSMB->OldFileName, fromName, name_len);
2110                 name_len2 = strnlen(toName, PATH_MAX);
2111                 name_len2++;    /* trailing null */
2112                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
2113                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2114                 name_len2++;    /* trailing null */
2115                 name_len2++;    /* signature byte */
2116         }
2117
2118         count = 1 /* 1st signature byte */  + name_len + name_len2;
2119         pSMB->hdr.smb_buf_length += count;
2120         pSMB->ByteCount = cpu_to_le16(count);
2121
2122         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2123                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2124         if (rc) {
2125                 cFYI(1, ("Send error in copy = %d with %d files copied",
2126                         rc, le16_to_cpu(pSMBr->CopyCount)));
2127         }
2128         if (pSMB)
2129                 cifs_buf_release(pSMB);
2130
2131         if (rc == -EAGAIN)
2132                 goto copyRetry;
2133
2134         return rc;
2135 }
2136
2137 int
2138 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2139                       const char *fromName, const char *toName,
2140                       const struct nls_table *nls_codepage)
2141 {
2142         TRANSACTION2_SPI_REQ *pSMB = NULL;
2143         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144         char *data_offset;
2145         int name_len;
2146         int name_len_target;
2147         int rc = 0;
2148         int bytes_returned = 0;
2149         __u16 params, param_offset, offset, byte_count;
2150
2151         cFYI(1, ("In Symlink Unix style"));
2152 createSymLinkRetry:
2153         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154                       (void **) &pSMBr);
2155         if (rc)
2156                 return rc;
2157
2158         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159                 name_len =
2160                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2161                                   /* find define for this maxpathcomponent */
2162                                   , nls_codepage);
2163                 name_len++;     /* trailing null */
2164                 name_len *= 2;
2165
2166         } else {        /* BB improve the check for buffer overruns BB */
2167                 name_len = strnlen(fromName, PATH_MAX);
2168                 name_len++;     /* trailing null */
2169                 strncpy(pSMB->FileName, fromName, name_len);
2170         }
2171         params = 6 + name_len;
2172         pSMB->MaxSetupCount = 0;
2173         pSMB->Reserved = 0;
2174         pSMB->Flags = 0;
2175         pSMB->Timeout = 0;
2176         pSMB->Reserved2 = 0;
2177         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2178                                 InformationLevel) - 4;
2179         offset = param_offset + params;
2180
2181         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2182         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2183                 name_len_target =
2184                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2185                                   /* find define for this maxpathcomponent */
2186                                   , nls_codepage);
2187                 name_len_target++;      /* trailing null */
2188                 name_len_target *= 2;
2189         } else {        /* BB improve the check for buffer overruns BB */
2190                 name_len_target = strnlen(toName, PATH_MAX);
2191                 name_len_target++;      /* trailing null */
2192                 strncpy(data_offset, toName, name_len_target);
2193         }
2194
2195         pSMB->MaxParameterCount = cpu_to_le16(2);
2196         /* BB find exact max on data count below from sess */
2197         pSMB->MaxDataCount = cpu_to_le16(1000);
2198         pSMB->SetupCount = 1;
2199         pSMB->Reserved3 = 0;
2200         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2201         byte_count = 3 /* pad */  + params + name_len_target;
2202         pSMB->DataCount = cpu_to_le16(name_len_target);
2203         pSMB->ParameterCount = cpu_to_le16(params);
2204         pSMB->TotalDataCount = pSMB->DataCount;
2205         pSMB->TotalParameterCount = pSMB->ParameterCount;
2206         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2207         pSMB->DataOffset = cpu_to_le16(offset);
2208         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2209         pSMB->Reserved4 = 0;
2210         pSMB->hdr.smb_buf_length += byte_count;
2211         pSMB->ByteCount = cpu_to_le16(byte_count);
2212         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2213                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2214         cifs_stats_inc(&tcon->num_symlinks);
2215         if (rc)
2216                 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2217
2218         if (pSMB)
2219                 cifs_buf_release(pSMB);
2220
2221         if (rc == -EAGAIN)
2222                 goto createSymLinkRetry;
2223
2224         return rc;
2225 }
2226
2227 int
2228 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2229                        const char *fromName, const char *toName,
2230                        const struct nls_table *nls_codepage, int remap)
2231 {
2232         TRANSACTION2_SPI_REQ *pSMB = NULL;
2233         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2234         char *data_offset;
2235         int name_len;
2236         int name_len_target;
2237         int rc = 0;
2238         int bytes_returned = 0;
2239         __u16 params, param_offset, offset, byte_count;
2240
2241         cFYI(1, ("In Create Hard link Unix style"));
2242 createHardLinkRetry:
2243         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2244                       (void **) &pSMBr);
2245         if (rc)
2246                 return rc;
2247
2248         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2249                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2250                                             PATH_MAX, nls_codepage, remap);
2251                 name_len++;     /* trailing null */
2252                 name_len *= 2;
2253
2254         } else {        /* BB improve the check for buffer overruns BB */
2255                 name_len = strnlen(toName, PATH_MAX);
2256                 name_len++;     /* trailing null */
2257                 strncpy(pSMB->FileName, toName, name_len);
2258         }
2259         params = 6 + name_len;
2260         pSMB->MaxSetupCount = 0;
2261         pSMB->Reserved = 0;
2262         pSMB->Flags = 0;
2263         pSMB->Timeout = 0;
2264         pSMB->Reserved2 = 0;
2265         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2266                                 InformationLevel) - 4;
2267         offset = param_offset + params;
2268
2269         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2270         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271                 name_len_target =
2272                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2273                                      nls_codepage, remap);
2274                 name_len_target++;      /* trailing null */
2275                 name_len_target *= 2;
2276         } else {        /* BB improve the check for buffer overruns BB */
2277                 name_len_target = strnlen(fromName, PATH_MAX);
2278                 name_len_target++;      /* trailing null */
2279                 strncpy(data_offset, fromName, name_len_target);
2280         }
2281
2282         pSMB->MaxParameterCount = cpu_to_le16(2);
2283         /* BB find exact max on data count below from sess*/
2284         pSMB->MaxDataCount = cpu_to_le16(1000);
2285         pSMB->SetupCount = 1;
2286         pSMB->Reserved3 = 0;
2287         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2288         byte_count = 3 /* pad */  + params + name_len_target;
2289         pSMB->ParameterCount = cpu_to_le16(params);
2290         pSMB->TotalParameterCount = pSMB->ParameterCount;
2291         pSMB->DataCount = cpu_to_le16(name_len_target);
2292         pSMB->TotalDataCount = pSMB->DataCount;
2293         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2294         pSMB->DataOffset = cpu_to_le16(offset);
2295         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2296         pSMB->Reserved4 = 0;
2297         pSMB->hdr.smb_buf_length += byte_count;
2298         pSMB->ByteCount = cpu_to_le16(byte_count);
2299         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2300                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2301         cifs_stats_inc(&tcon->num_hardlinks);
2302         if (rc)
2303                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2304
2305         cifs_buf_release(pSMB);
2306         if (rc == -EAGAIN)
2307                 goto createHardLinkRetry;
2308
2309         return rc;
2310 }
2311
2312 int
2313 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2314                    const char *fromName, const char *toName,
2315                    const struct nls_table *nls_codepage, int remap)
2316 {
2317         int rc = 0;
2318         NT_RENAME_REQ *pSMB = NULL;
2319         RENAME_RSP *pSMBr = NULL;
2320         int bytes_returned;
2321         int name_len, name_len2;
2322         __u16 count;
2323
2324         cFYI(1, ("In CIFSCreateHardLink"));
2325 winCreateHardLinkRetry:
2326
2327         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2328                       (void **) &pSMBr);
2329         if (rc)
2330                 return rc;
2331
2332         pSMB->SearchAttributes =
2333             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2334                         ATTR_DIRECTORY);
2335         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2336         pSMB->ClusterCount = 0;
2337
2338         pSMB->BufferFormat = 0x04;
2339
2340         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2341                 name_len =
2342                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2343                                      PATH_MAX, nls_codepage, remap);
2344                 name_len++;     /* trailing null */
2345                 name_len *= 2;
2346                 pSMB->OldFileName[name_len] = 0;        /* pad */
2347                 pSMB->OldFileName[name_len + 1] = 0x04;
2348                 name_len2 =
2349                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2350                                      toName, PATH_MAX, nls_codepage, remap);
2351                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2352                 name_len2 *= 2; /* convert to bytes */
2353         } else {        /* BB improve the check for buffer overruns BB */
2354                 name_len = strnlen(fromName, PATH_MAX);
2355                 name_len++;     /* trailing null */
2356                 strncpy(pSMB->OldFileName, fromName, name_len);
2357                 name_len2 = strnlen(toName, PATH_MAX);
2358                 name_len2++;    /* trailing null */
2359                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
2360                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2361                 name_len2++;    /* trailing null */
2362                 name_len2++;    /* signature byte */
2363         }
2364
2365         count = 1 /* string type byte */  + name_len + name_len2;
2366         pSMB->hdr.smb_buf_length += count;
2367         pSMB->ByteCount = cpu_to_le16(count);
2368
2369         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2370                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2371         cifs_stats_inc(&tcon->num_hardlinks);
2372         if (rc)
2373                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2374
2375         cifs_buf_release(pSMB);
2376         if (rc == -EAGAIN)
2377                 goto winCreateHardLinkRetry;
2378
2379         return rc;
2380 }
2381
2382 int
2383 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2384                         const unsigned char *searchName,
2385                         char *symlinkinfo, const int buflen,
2386                         const struct nls_table *nls_codepage)
2387 {
2388 /* SMB_QUERY_FILE_UNIX_LINK */
2389         TRANSACTION2_QPI_REQ *pSMB = NULL;
2390         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2391         int rc = 0;
2392         int bytes_returned;
2393         int name_len;
2394         __u16 params, byte_count;
2395
2396         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2397
2398 querySymLinkRetry:
2399         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2400                       (void **) &pSMBr);
2401         if (rc)
2402                 return rc;
2403
2404         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2405                 name_len =
2406                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2407                                   PATH_MAX, nls_codepage);
2408                 name_len++;     /* trailing null */
2409                 name_len *= 2;
2410         } else {        /* BB improve the check for buffer overruns BB */
2411                 name_len = strnlen(searchName, PATH_MAX);
2412                 name_len++;     /* trailing null */
2413                 strncpy(pSMB->FileName, searchName, name_len);
2414         }
2415
2416         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2417         pSMB->TotalDataCount = 0;
2418         pSMB->MaxParameterCount = cpu_to_le16(2);
2419         /* BB find exact max data count below from sess structure BB */
2420         pSMB->MaxDataCount = cpu_to_le16(4000);
2421         pSMB->MaxSetupCount = 0;
2422         pSMB->Reserved = 0;
2423         pSMB->Flags = 0;
2424         pSMB->Timeout = 0;
2425         pSMB->Reserved2 = 0;
2426         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2427         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2428         pSMB->DataCount = 0;
2429         pSMB->DataOffset = 0;
2430         pSMB->SetupCount = 1;
2431         pSMB->Reserved3 = 0;
2432         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2433         byte_count = params + 1 /* pad */ ;
2434         pSMB->TotalParameterCount = cpu_to_le16(params);
2435         pSMB->ParameterCount = pSMB->TotalParameterCount;
2436         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2437         pSMB->Reserved4 = 0;
2438         pSMB->hdr.smb_buf_length += byte_count;
2439         pSMB->ByteCount = cpu_to_le16(byte_count);
2440
2441         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2442                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2443         if (rc) {
2444                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2445         } else {
2446                 /* decode response */
2447
2448                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2449                 if (rc || (pSMBr->ByteCount < 2))
2450                 /* BB also check enough total bytes returned */
2451                         rc = -EIO;      /* bad smb */
2452                 else {
2453                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2454                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2455
2456                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2457                                 name_len = UniStrnlen((wchar_t *) ((char *)
2458                                         &pSMBr->hdr.Protocol + data_offset),
2459                                         min_t(const int, buflen, count) / 2);
2460                         /* BB FIXME investigate remapping reserved chars here */
2461                                 cifs_strfromUCS_le(symlinkinfo,
2462                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol
2463                                                         + data_offset),
2464                                         name_len, nls_codepage);
2465                         } else {
2466                                 strncpy(symlinkinfo,
2467                                         (char *) &pSMBr->hdr.Protocol +
2468                                                 data_offset,
2469                                         min_t(const int, buflen, count));
2470                         }
2471                         symlinkinfo[buflen] = 0;
2472         /* just in case so calling code does not go off the end of buffer */
2473                 }
2474         }
2475         cifs_buf_release(pSMB);
2476         if (rc == -EAGAIN)
2477                 goto querySymLinkRetry;
2478         return rc;
2479 }
2480
2481 #ifdef CONFIG_CIFS_EXPERIMENTAL
2482 /* Initialize NT TRANSACT SMB into small smb request buffer.
2483    This assumes that all NT TRANSACTS that we init here have
2484    total parm and data under about 400 bytes (to fit in small cifs
2485    buffer size), which is the case so far, it easily fits. NB:
2486         Setup words themselves and ByteCount
2487         MaxSetupCount (size of returned setup area) and
2488         MaxParameterCount (returned parms size) must be set by caller */
2489 static int
2490 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2491                    const int parm_len, struct cifsTconInfo *tcon,
2492                    void **ret_buf)
2493 {
2494         int rc;
2495         __u32 temp_offset;
2496         struct smb_com_ntransact_req *pSMB;
2497
2498         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2499                                 (void **)&pSMB);
2500         if (rc)
2501                 return rc;
2502         *ret_buf = (void *)pSMB;
2503         pSMB->Reserved = 0;
2504         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2505         pSMB->TotalDataCount  = 0;
2506         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2507                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2508         pSMB->ParameterCount = pSMB->TotalParameterCount;
2509         pSMB->DataCount  = pSMB->TotalDataCount;
2510         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2511                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
2512         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2513         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2514         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2515         pSMB->SubCommand = cpu_to_le16(sub_command);
2516         return 0;
2517 }
2518
2519 static int
2520 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2521                    __u32 *pparmlen, __u32 *pdatalen)
2522 {
2523         char *end_of_smb;
2524         __u32 data_count, data_offset, parm_count, parm_offset;
2525         struct smb_com_ntransact_rsp *pSMBr;
2526
2527         *pdatalen = 0;
2528         *pparmlen = 0;
2529
2530         if (buf == NULL)
2531                 return -EINVAL;
2532
2533         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2534
2535         /* ByteCount was converted from little endian in SendReceive */
2536         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2537                         (char *)&pSMBr->ByteCount;
2538
2539         data_offset = le32_to_cpu(pSMBr->DataOffset);
2540         data_count = le32_to_cpu(pSMBr->DataCount);
2541         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2542         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2543
2544         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2545         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2546
2547         /* should we also check that parm and data areas do not overlap? */
2548         if (*ppparm > end_of_smb) {
2549                 cFYI(1, ("parms start after end of smb"));
2550                 return -EINVAL;
2551         } else if (parm_count + *ppparm > end_of_smb) {
2552                 cFYI(1, ("parm end after end of smb"));
2553                 return -EINVAL;
2554         } else if (*ppdata > end_of_smb) {
2555                 cFYI(1, ("data starts after end of smb"));
2556                 return -EINVAL;
2557         } else if (data_count + *ppdata > end_of_smb) {
2558                 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2559                         *ppdata, data_count, (data_count + *ppdata),
2560                         end_of_smb, pSMBr));
2561                 return -EINVAL;
2562         } else if (parm_count + data_count > pSMBr->ByteCount) {
2563                 cFYI(1, ("parm count and data count larger than SMB"));
2564                 return -EINVAL;
2565         }
2566         *pdatalen = data_count;
2567         *pparmlen = parm_count;
2568         return 0;
2569 }
2570 #endif /* CIFS_EXPERIMENTAL */
2571
2572 int
2573 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2574                         const unsigned char *searchName,
2575                         char *symlinkinfo, const int buflen, __u16 fid,
2576                         const struct nls_table *nls_codepage)
2577 {
2578         int rc = 0;
2579         int bytes_returned;
2580         int name_len;
2581         struct smb_com_transaction_ioctl_req *pSMB;
2582         struct smb_com_transaction_ioctl_rsp *pSMBr;
2583
2584         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2585         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2586                       (void **) &pSMBr);
2587         if (rc)
2588                 return rc;
2589
2590         pSMB->TotalParameterCount = 0 ;
2591         pSMB->TotalDataCount = 0;
2592         pSMB->MaxParameterCount = cpu_to_le32(2);
2593         /* BB find exact data count max from sess structure BB */
2594         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2595                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2596         pSMB->MaxSetupCount = 4;
2597         pSMB->Reserved = 0;
2598         pSMB->ParameterOffset = 0;
2599         pSMB->DataCount = 0;
2600         pSMB->DataOffset = 0;
2601         pSMB->SetupCount = 4;
2602         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2603         pSMB->ParameterCount = pSMB->TotalParameterCount;
2604         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2605         pSMB->IsFsctl = 1; /* FSCTL */
2606         pSMB->IsRootFlag = 0;
2607         pSMB->Fid = fid; /* file handle always le */
2608         pSMB->ByteCount = 0;
2609
2610         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2611                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2612         if (rc) {
2613                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2614         } else {                /* decode response */
2615                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2616                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2617                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2618                 /* BB also check enough total bytes returned */
2619                         rc = -EIO;      /* bad smb */
2620                 else {
2621                         if (data_count && (data_count < 2048)) {
2622                                 char *end_of_smb = 2 /* sizeof byte count */ +
2623                                                 pSMBr->ByteCount +
2624                                                 (char *)&pSMBr->ByteCount;
2625
2626                                 struct reparse_data *reparse_buf =
2627                                                 (struct reparse_data *)
2628                                                 ((char *)&pSMBr->hdr.Protocol
2629                                                                  + data_offset);
2630                                 if ((char *)reparse_buf >= end_of_smb) {
2631                                         rc = -EIO;
2632                                         goto qreparse_out;
2633                                 }
2634                                 if ((reparse_buf->LinkNamesBuf +
2635                                         reparse_buf->TargetNameOffset +
2636                                         reparse_buf->TargetNameLen) >
2637                                                 end_of_smb) {
2638                                         cFYI(1, ("reparse buf beyond SMB"));
2639                                         rc = -EIO;
2640                                         goto qreparse_out;
2641                                 }
2642
2643                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2644                                         name_len = UniStrnlen((wchar_t *)
2645                                                 (reparse_buf->LinkNamesBuf +
2646                                                 reparse_buf->TargetNameOffset),
2647                                                 min(buflen/2,
2648                                                 reparse_buf->TargetNameLen / 2));
2649                                         cifs_strfromUCS_le(symlinkinfo,
2650                                                 (__le16 *) (reparse_buf->LinkNamesBuf +
2651                                                 reparse_buf->TargetNameOffset),
2652                                                 name_len, nls_codepage);
2653                                 } else { /* ASCII names */
2654                                         strncpy(symlinkinfo,
2655                                                 reparse_buf->LinkNamesBuf +
2656                                                 reparse_buf->TargetNameOffset,
2657                                                 min_t(const int, buflen,
2658                                                    reparse_buf->TargetNameLen));
2659                                 }
2660                         } else {
2661                                 rc = -EIO;
2662                                 cFYI(1, ("Invalid return data count on "
2663                                          "get reparse info ioctl"));
2664                         }
2665                         symlinkinfo[buflen] = 0; /* just in case so the caller
2666                                         does not go off the end of the buffer */
2667                         cFYI(1, ("readlink result - %s", symlinkinfo));
2668                 }
2669         }
2670 qreparse_out:
2671         cifs_buf_release(pSMB);
2672
2673         /* Note: On -EAGAIN error only caller can retry on handle based calls
2674                 since file handle passed in no longer valid */
2675
2676         return rc;
2677 }
2678
2679 #ifdef CONFIG_CIFS_POSIX
2680
2681 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2682 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2683                              struct cifs_posix_ace *cifs_ace)
2684 {
2685         /* u8 cifs fields do not need le conversion */
2686         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2687         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2688         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2689         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2690
2691         return;
2692 }
2693
2694 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2695 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2696                                const int acl_type, const int size_of_data_area)
2697 {
2698         int size =  0;
2699         int i;
2700         __u16 count;
2701         struct cifs_posix_ace *pACE;
2702         struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2703         posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2704
2705         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2706                 return -EOPNOTSUPP;
2707
2708         if (acl_type & ACL_TYPE_ACCESS) {
2709                 count = le16_to_cpu(cifs_acl->access_entry_count);
2710                 pACE = &cifs_acl->ace_array[0];
2711                 size = sizeof(struct cifs_posix_acl);
2712                 size += sizeof(struct cifs_posix_ace) * count;
2713                 /* check if we would go beyond end of SMB */
2714                 if (size_of_data_area < size) {
2715                         cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2716                                 size_of_data_area, size));
2717                         return -EINVAL;
2718                 }
2719         } else if (acl_type & ACL_TYPE_DEFAULT) {
2720                 count = le16_to_cpu(cifs_acl->access_entry_count);
2721                 size = sizeof(struct cifs_posix_acl);
2722                 size += sizeof(struct cifs_posix_ace) * count;
2723 /* skip past access ACEs to get to default ACEs */
2724                 pACE = &cifs_acl->ace_array[count];
2725                 count = le16_to_cpu(cifs_acl->default_entry_count);
2726                 size += sizeof(struct cifs_posix_ace) * count;
2727                 /* check if we would go beyond end of SMB */
2728                 if (size_of_data_area < size)
2729                         return -EINVAL;
2730         } else {
2731                 /* illegal type */
2732                 return -EINVAL;
2733         }
2734
2735         size = posix_acl_xattr_size(count);
2736         if ((buflen == 0) || (local_acl == NULL)) {
2737                 /* used to query ACL EA size */
2738         } else if (size > buflen) {
2739                 return -ERANGE;
2740         } else /* buffer big enough */ {
2741                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2742                 for (i = 0; i < count ; i++) {
2743                         cifs_convert_ace(&local_acl->a_entries[i], pACE);
2744                         pACE++;
2745                 }
2746         }
2747         return size;
2748 }
2749
2750 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2751                                      const posix_acl_xattr_entry *local_ace)
2752 {
2753         __u16 rc = 0; /* 0 = ACL converted ok */
2754
2755         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2756         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2757         /* BB is there a better way to handle the large uid? */
2758         if (local_ace->e_id == cpu_to_le32(-1)) {
2759         /* Probably no need to le convert -1 on any arch but can not hurt */
2760                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2761         } else
2762                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2763         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2764         return rc;
2765 }
2766
2767 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2768 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2769                                const int buflen, const int acl_type)
2770 {
2771         __u16 rc = 0;
2772         struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2773         posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2774         int count;
2775         int i;
2776
2777         if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2778                 return 0;
2779
2780         count = posix_acl_xattr_count((size_t)buflen);
2781         cFYI(1, ("setting acl with %d entries from buf of length %d and "
2782                 "version of %d",
2783                 count, buflen, le32_to_cpu(local_acl->a_version)));
2784         if (le32_to_cpu(local_acl->a_version) != 2) {
2785                 cFYI(1, ("unknown POSIX ACL version %d",
2786                      le32_to_cpu(local_acl->a_version)));
2787                 return 0;
2788         }
2789         cifs_acl->version = cpu_to_le16(1);
2790         if (acl_type == ACL_TYPE_ACCESS)
2791                 cifs_acl->access_entry_count = cpu_to_le16(count);
2792         else if (acl_type == ACL_TYPE_DEFAULT)
2793                 cifs_acl->default_entry_count = cpu_to_le16(count);
2794         else {
2795                 cFYI(1, ("unknown ACL type %d", acl_type));
2796                 return 0;
2797         }
2798         for (i = 0; i < count; i++) {
2799                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2800                                         &local_acl->a_entries[i]);
2801                 if (rc != 0) {
2802                         /* ACE not converted */
2803                         break;
2804                 }
2805         }
2806         if (rc == 0) {
2807                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2808                 rc += sizeof(struct cifs_posix_acl);
2809                 /* BB add check to make sure ACL does not overflow SMB */
2810         }
2811         return rc;
2812 }
2813
2814 int
2815 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2816                    const unsigned char *searchName,
2817                    char *acl_inf, const int buflen, const int acl_type,
2818                    const struct nls_table *nls_codepage, int remap)
2819 {
2820 /* SMB_QUERY_POSIX_ACL */
2821         TRANSACTION2_QPI_REQ *pSMB = NULL;
2822         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2823         int rc = 0;
2824         int bytes_returned;
2825         int name_len;
2826         __u16 params, byte_count;
2827
2828         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2829
2830 queryAclRetry:
2831         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2832                 (void **) &pSMBr);
2833         if (rc)
2834                 return rc;
2835
2836         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2837                 name_len =
2838                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2839                                          PATH_MAX, nls_codepage, remap);
2840                 name_len++;     /* trailing null */
2841                 name_len *= 2;
2842                 pSMB->FileName[name_len] = 0;
2843                 pSMB->FileName[name_len+1] = 0;
2844         } else {        /* BB improve the check for buffer overruns BB */
2845                 name_len = strnlen(searchName, PATH_MAX);
2846                 name_len++;     /* trailing null */
2847                 strncpy(pSMB->FileName, searchName, name_len);
2848         }
2849
2850         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2851         pSMB->TotalDataCount = 0;
2852         pSMB->MaxParameterCount = cpu_to_le16(2);
2853         /* BB find exact max data count below from sess structure BB */
2854         pSMB->MaxDataCount = cpu_to_le16(4000);
2855         pSMB->MaxSetupCount = 0;
2856         pSMB->Reserved = 0;
2857         pSMB->Flags = 0;
2858         pSMB->Timeout = 0;
2859         pSMB->Reserved2 = 0;
2860         pSMB->ParameterOffset = cpu_to_le16(
2861                 offsetof(struct smb_com_transaction2_qpi_req,
2862                          InformationLevel) - 4);
2863         pSMB->DataCount = 0;
2864         pSMB->DataOffset = 0;
2865         pSMB->SetupCount = 1;
2866         pSMB->Reserved3 = 0;
2867         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2868         byte_count = params + 1 /* pad */ ;
2869         pSMB->TotalParameterCount = cpu_to_le16(params);
2870         pSMB->ParameterCount = pSMB->TotalParameterCount;
2871         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2872         pSMB->Reserved4 = 0;
2873         pSMB->hdr.smb_buf_length += byte_count;
2874         pSMB->ByteCount = cpu_to_le16(byte_count);
2875
2876         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2878         cifs_stats_inc(&tcon->num_acl_get);
2879         if (rc) {
2880                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2881         } else {
2882                 /* decode response */
2883
2884                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2885                 if (rc || (pSMBr->ByteCount < 2))
2886                 /* BB also check enough total bytes returned */
2887                         rc = -EIO;      /* bad smb */
2888                 else {
2889                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2890                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2891                         rc = cifs_copy_posix_acl(acl_inf,
2892                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2893                                 buflen, acl_type, count);
2894                 }
2895         }
2896         cifs_buf_release(pSMB);
2897         if (rc == -EAGAIN)
2898                 goto queryAclRetry;
2899         return rc;
2900 }
2901
2902 int
2903 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2904                    const unsigned char *fileName,
2905                    const char *local_acl, const int buflen,
2906                    const int acl_type,
2907                    const struct nls_table *nls_codepage, int remap)
2908 {
2909         struct smb_com_transaction2_spi_req *pSMB = NULL;
2910         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2911         char *parm_data;
2912         int name_len;
2913         int rc = 0;
2914         int bytes_returned = 0;
2915         __u16 params, byte_count, data_count, param_offset, offset;
2916
2917         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2918 setAclRetry:
2919         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2920                       (void **) &pSMBr);
2921         if (rc)
2922                 return rc;
2923         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2924                 name_len =
2925                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2926                                       PATH_MAX, nls_codepage, remap);
2927                 name_len++;     /* trailing null */
2928                 name_len *= 2;
2929         } else {        /* BB improve the check for buffer overruns BB */
2930                 name_len = strnlen(fileName, PATH_MAX);
2931                 name_len++;     /* trailing null */
2932                 strncpy(pSMB->FileName, fileName, name_len);
2933         }
2934         params = 6 + name_len;
2935         pSMB->MaxParameterCount = cpu_to_le16(2);
2936         /* BB find max SMB size from sess */
2937         pSMB->MaxDataCount = cpu_to_le16(1000);
2938         pSMB->MaxSetupCount = 0;
2939         pSMB->Reserved = 0;
2940         pSMB->Flags = 0;
2941         pSMB->Timeout = 0;
2942         pSMB->Reserved2 = 0;
2943         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2944                                 InformationLevel) - 4;
2945         offset = param_offset + params;
2946         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2947         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2948
2949         /* convert to on the wire format for POSIX ACL */
2950         data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2951
2952         if (data_count == 0) {
2953                 rc = -EOPNOTSUPP;
2954                 goto setACLerrorExit;
2955         }
2956         pSMB->DataOffset = cpu_to_le16(offset);
2957         pSMB->SetupCount = 1;
2958         pSMB->Reserved3 = 0;
2959         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2960         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2961         byte_count = 3 /* pad */  + params + data_count;
2962         pSMB->DataCount = cpu_to_le16(data_count);
2963         pSMB->TotalDataCount = pSMB->DataCount;
2964         pSMB->ParameterCount = cpu_to_le16(params);
2965         pSMB->TotalParameterCount = pSMB->ParameterCount;
2966         pSMB->Reserved4 = 0;
2967         pSMB->hdr.smb_buf_length += byte_count;
2968         pSMB->ByteCount = cpu_to_le16(byte_count);
2969         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2970                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2971         if (rc)
2972                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2973
2974 setACLerrorExit:
2975         cifs_buf_release(pSMB);
2976         if (rc == -EAGAIN)
2977                 goto setAclRetry;
2978         return rc;
2979 }
2980
2981 /* BB fix tabs in this function FIXME BB */
2982 int
2983 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2984                const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2985 {
2986         int rc = 0;
2987         struct smb_t2_qfi_req *pSMB = NULL;
2988         struct smb_t2_qfi_rsp *pSMBr = NULL;
2989         int bytes_returned;
2990         __u16 params, byte_count;
2991
2992         cFYI(1, ("In GetExtAttr"));
2993         if (tcon == NULL)
2994                 return -ENODEV;
2995
2996 GetExtAttrRetry:
2997         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2998                         (void **) &pSMBr);
2999         if (rc)
3000                 return rc;
3001
3002         params = 2 /* level */ + 2 /* fid */;
3003         pSMB->t2.TotalDataCount = 0;
3004         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3005         /* BB find exact max data count below from sess structure BB */
3006         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3007         pSMB->t2.MaxSetupCount = 0;
3008         pSMB->t2.Reserved = 0;
3009         pSMB->t2.Flags = 0;
3010         pSMB->t2.Timeout = 0;
3011         pSMB->t2.Reserved2 = 0;
3012         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3013                                                Fid) - 4);
3014         pSMB->t2.DataCount = 0;
3015         pSMB->t2.DataOffset = 0;
3016         pSMB->t2.SetupCount = 1;
3017         pSMB->t2.Reserved3 = 0;
3018         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3019         byte_count = params + 1 /* pad */ ;
3020         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3021         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3022         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3023         pSMB->Pad = 0;
3024         pSMB->Fid = netfid;
3025         pSMB->hdr.smb_buf_length += byte_count;
3026         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3027
3028         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3029                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3030         if (rc) {
3031                 cFYI(1, ("error %d in GetExtAttr", rc));
3032         } else {
3033                 /* decode response */
3034                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3035                 if (rc || (pSMBr->ByteCount < 2))
3036                 /* BB also check enough total bytes returned */
3037                         /* If rc should we check for EOPNOSUPP and
3038                            disable the srvino flag? or in caller? */
3039                         rc = -EIO;      /* bad smb */
3040                 else {
3041                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3042                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3043                         struct file_chattr_info *pfinfo;
3044                         /* BB Do we need a cast or hash here ? */
3045                         if (count != 16) {
3046                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
3047                                 rc = -EIO;
3048                                 goto GetExtAttrOut;
3049                         }
3050                         pfinfo = (struct file_chattr_info *)
3051                                  (data_offset + (char *) &pSMBr->hdr.Protocol);
3052                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3053                         *pMask = le64_to_cpu(pfinfo->mask);
3054                 }
3055         }
3056 GetExtAttrOut:
3057         cifs_buf_release(pSMB);
3058         if (rc == -EAGAIN)
3059                 goto GetExtAttrRetry;
3060         return rc;
3061 }
3062
3063 #endif /* CONFIG_POSIX */
3064
3065 #ifdef CONFIG_CIFS_EXPERIMENTAL
3066 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3067 int
3068 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3069                   struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3070 {
3071         int rc = 0;
3072         int buf_type = 0;
3073         QUERY_SEC_DESC_REQ *pSMB;
3074         struct kvec iov[1];
3075
3076         cFYI(1, ("GetCifsACL"));
3077
3078         *pbuflen = 0;
3079         *acl_inf = NULL;
3080
3081         rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3082                         8 /* parm len */, tcon, (void **) &pSMB);
3083         if (rc)
3084                 return rc;
3085
3086         pSMB->MaxParameterCount = cpu_to_le32(4);
3087         /* BB TEST with big acls that might need to be e.g. larger than 16K */
3088         pSMB->MaxSetupCount = 0;
3089         pSMB->Fid = fid; /* file handle always le */
3090         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3091                                      CIFS_ACL_DACL);
3092         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3093         pSMB->hdr.smb_buf_length += 11;
3094         iov[0].iov_base = (char *)pSMB;
3095         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3096
3097         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3098                          CIFS_STD_OP);
3099         cifs_stats_inc(&tcon->num_acl_get);
3100         if (rc) {
3101                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3102         } else {                /* decode response */
3103                 __le32 *parm;
3104                 __u32 parm_len;
3105                 __u32 acl_len;
3106                 struct smb_com_ntransact_rsp *pSMBr;
3107                 char *pdata;
3108
3109 /* validate_nttransact */
3110                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3111                                         &pdata, &parm_len, pbuflen);
3112                 if (rc)
3113                         goto qsec_out;
3114                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3115
3116                 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3117
3118                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3119                         rc = -EIO;      /* bad smb */
3120                         *pbuflen = 0;
3121                         goto qsec_out;
3122                 }
3123
3124 /* BB check that data area is minimum length and as big as acl_len */
3125
3126                 acl_len = le32_to_cpu(*parm);
3127                 if (acl_len != *pbuflen) {
3128                         cERROR(1, ("acl length %d does not match %d",
3129                                    acl_len, *pbuflen));
3130                         if (*pbuflen > acl_len)
3131                                 *pbuflen = acl_len;
3132                 }
3133
3134                 /* check if buffer is big enough for the acl
3135                    header followed by the smallest SID */
3136                 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3137                     (*pbuflen >= 64 * 1024)) {
3138                         cERROR(1, ("bad acl length %d", *pbuflen));
3139                         rc = -EINVAL;
3140                         *pbuflen = 0;
3141                 } else {
3142                         *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3143                         if (*acl_inf == NULL) {
3144                                 *pbuflen = 0;
3145                                 rc = -ENOMEM;
3146                         }
3147                         memcpy(*acl_inf, pdata, *pbuflen);
3148                 }
3149         }
3150 qsec_out:
3151         if (buf_type == CIFS_SMALL_BUFFER)
3152                 cifs_small_buf_release(iov[0].iov_base);
3153         else if (buf_type == CIFS_LARGE_BUFFER)
3154                 cifs_buf_release(iov[0].iov_base);
3155 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3156         return rc;
3157 }
3158
3159 int
3160 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3161                         struct cifs_ntsd *pntsd, __u32 acllen)
3162 {
3163         __u16 byte_count, param_count, data_count, param_offset, data_offset;
3164         int rc = 0;
3165         int bytes_returned = 0;
3166         SET_SEC_DESC_REQ *pSMB = NULL;
3167         NTRANSACT_RSP *pSMBr = NULL;
3168
3169 setCifsAclRetry:
3170         rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3171                         (void **) &pSMBr);
3172         if (rc)
3173                         return (rc);
3174
3175         pSMB->MaxSetupCount = 0;
3176         pSMB->Reserved = 0;
3177
3178         param_count = 8;
3179         param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3180         data_count = acllen;
3181         data_offset = param_offset + param_count;
3182         byte_count = 3 /* pad */  + param_count;
3183
3184         pSMB->DataCount = cpu_to_le32(data_count);
3185         pSMB->TotalDataCount = pSMB->DataCount;
3186         pSMB->MaxParameterCount = cpu_to_le32(4);
3187         pSMB->MaxDataCount = cpu_to_le32(16384);
3188         pSMB->ParameterCount = cpu_to_le32(param_count);
3189         pSMB->ParameterOffset = cpu_to_le32(param_offset);
3190         pSMB->TotalParameterCount = pSMB->ParameterCount;
3191         pSMB->DataOffset = cpu_to_le32(data_offset);
3192         pSMB->SetupCount = 0;
3193         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3194         pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3195
3196         pSMB->Fid = fid; /* file handle always le */
3197         pSMB->Reserved2 = 0;
3198         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3199
3200         if (pntsd && acllen) {
3201                 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3202                         (char *) pntsd,
3203                         acllen);
3204                 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3205
3206         } else
3207                 pSMB->hdr.smb_buf_length += byte_count;
3208
3209         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3210                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3211
3212         cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3213         if (rc)
3214                 cFYI(1, ("Set CIFS ACL returned %d", rc));
3215         cifs_buf_release(pSMB);
3216
3217         if (rc == -EAGAIN)
3218                 goto setCifsAclRetry;
3219
3220         return (rc);
3221 }
3222
3223 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3224
3225 /* Legacy Query Path Information call for lookup to old servers such
3226    as Win9x/WinME */
3227 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3228                         const unsigned char *searchName,
3229                         FILE_ALL_INFO *pFinfo,
3230                         const struct nls_table *nls_codepage, int remap)
3231 {
3232         QUERY_INFORMATION_REQ *pSMB;
3233         QUERY_INFORMATION_RSP *pSMBr;
3234         int rc = 0;
3235         int bytes_returned;
3236         int name_len;
3237
3238         cFYI(1, ("In SMBQPath path %s", searchName));
3239 QInfRetry:
3240         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3241                       (void **) &pSMBr);
3242         if (rc)
3243                 return rc;
3244
3245         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3246                 name_len =
3247                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3248                                         PATH_MAX, nls_codepage, remap);
3249                 name_len++;     /* trailing null */
3250                 name_len *= 2;
3251         } else {
3252                 name_len = strnlen(searchName, PATH_MAX);
3253                 name_len++;     /* trailing null */
3254                 strncpy(pSMB->FileName, searchName, name_len);
3255         }
3256         pSMB->BufferFormat = 0x04;
3257         name_len++; /* account for buffer type byte */
3258         pSMB->hdr.smb_buf_length += (__u16) name_len;
3259         pSMB->ByteCount = cpu_to_le16(name_len);
3260
3261         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3262                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3263         if (rc) {
3264                 cFYI(1, ("Send error in QueryInfo = %d", rc));
3265         } else if (pFinfo) {
3266                 struct timespec ts;
3267                 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3268
3269                 /* decode response */
3270                 /* BB FIXME - add time zone adjustment BB */
3271                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3272                 ts.tv_nsec = 0;
3273                 ts.tv_sec = time;
3274                 /* decode time fields */
3275                 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3276                 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3277                 pFinfo->LastAccessTime = 0;
3278                 pFinfo->AllocationSize =
3279                         cpu_to_le64(le32_to_cpu(pSMBr->size));
3280                 pFinfo->EndOfFile = pFinfo->AllocationSize;
3281                 pFinfo->Attributes =
3282                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
3283         } else
3284                 rc = -EIO; /* bad buffer passed in */
3285
3286         cifs_buf_release(pSMB);
3287
3288         if (rc == -EAGAIN)
3289                 goto QInfRetry;
3290
3291         return rc;
3292 }
3293
3294
3295
3296
3297 int
3298 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3299                  const unsigned char *searchName,
3300                  FILE_ALL_INFO *pFindData,
3301                  int legacy /* old style infolevel */,
3302                  const struct nls_table *nls_codepage, int remap)
3303 {
3304 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3305         TRANSACTION2_QPI_REQ *pSMB = NULL;
3306         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3307         int rc = 0;
3308         int bytes_returned;
3309         int name_len;
3310         __u16 params, byte_count;
3311
3312 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3313 QPathInfoRetry:
3314         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3315                       (void **) &pSMBr);
3316         if (rc)
3317                 return rc;
3318
3319         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3320                 name_len =
3321                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3322                                      PATH_MAX, nls_codepage, remap);
3323                 name_len++;     /* trailing null */
3324                 name_len *= 2;
3325         } else {        /* BB improve the check for buffer overruns BB */
3326                 name_len = strnlen(searchName, PATH_MAX);
3327                 name_len++;     /* trailing null */
3328                 strncpy(pSMB->FileName, searchName, name_len);
3329         }
3330
3331         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3332         pSMB->TotalDataCount = 0;
3333         pSMB->MaxParameterCount = cpu_to_le16(2);
3334         /* BB find exact max SMB PDU from sess structure BB */
3335         pSMB->MaxDataCount = cpu_to_le16(4000);
3336         pSMB->MaxSetupCount = 0;
3337         pSMB->Reserved = 0;
3338         pSMB->Flags = 0;
3339         pSMB->Timeout = 0;
3340         pSMB->Reserved2 = 0;
3341         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3342         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3343         pSMB->DataCount = 0;
3344         pSMB->DataOffset = 0;
3345         pSMB->SetupCount = 1;
3346         pSMB->Reserved3 = 0;
3347         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3348         byte_count = params + 1 /* pad */ ;
3349         pSMB->TotalParameterCount = cpu_to_le16(params);
3350         pSMB->ParameterCount = pSMB->TotalParameterCount;
3351         if (legacy)
3352                 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3353         else
3354                 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3355         pSMB->Reserved4 = 0;
3356         pSMB->hdr.smb_buf_length += byte_count;
3357         pSMB->ByteCount = cpu_to_le16(byte_count);
3358
3359         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3360                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3361         if (rc) {
3362                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3363         } else {                /* decode response */
3364                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365
3366                 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3367                         rc = -EIO;
3368                 else if (!legacy && (pSMBr->ByteCount < 40))
3369                         rc = -EIO;      /* bad smb */
3370                 else if (legacy && (pSMBr->ByteCount < 24))
3371                         rc = -EIO;  /* 24 or 26 expected but we do not read
3372                                         last field */
3373                 else if (pFindData) {
3374                         int size;
3375                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3376
3377                         /* On legacy responses we do not read the last field,
3378                         EAsize, fortunately since it varies by subdialect and
3379                         also note it differs on Set vs. Get, ie two bytes or 4
3380                         bytes depending but we don't care here */
3381                         if (legacy)
3382                                 size = sizeof(FILE_INFO_STANDARD);
3383                         else
3384                                 size = sizeof(FILE_ALL_INFO);
3385                         memcpy((char *) pFindData,
3386                                (char *) &pSMBr->hdr.Protocol +
3387                                data_offset, size);
3388                 } else
3389                     rc = -ENOMEM;
3390         }
3391         cifs_buf_release(pSMB);
3392         if (rc == -EAGAIN)
3393                 goto QPathInfoRetry;
3394
3395         return rc;
3396 }
3397
3398 int
3399 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3400                      const unsigned char *searchName,
3401                      FILE_UNIX_BASIC_INFO *pFindData,
3402                      const struct nls_table *nls_codepage, int remap)
3403 {
3404 /* SMB_QUERY_FILE_UNIX_BASIC */
3405         TRANSACTION2_QPI_REQ *pSMB = NULL;
3406         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3407         int rc = 0;
3408         int bytes_returned = 0;
3409         int name_len;
3410         __u16 params, byte_count;
3411
3412         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3413 UnixQPathInfoRetry:
3414         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3415                       (void **) &pSMBr);
3416         if (rc)
3417                 return rc;
3418
3419         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3420                 name_len =
3421                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3422                                   PATH_MAX, nls_codepage, remap);
3423                 name_len++;     /* trailing null */
3424                 name_len *= 2;
3425         } else {        /* BB improve the check for buffer overruns BB */
3426                 name_len = strnlen(searchName, PATH_MAX);
3427                 name_len++;     /* trailing null */
3428                 strncpy(pSMB->FileName, searchName, name_len);
3429         }
3430
3431         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3432         pSMB->TotalDataCount = 0;
3433         pSMB->MaxParameterCount = cpu_to_le16(2);
3434         /* BB find exact max SMB PDU from sess structure BB */
3435         pSMB->MaxDataCount = cpu_to_le16(4000);
3436         pSMB->MaxSetupCount = 0;
3437         pSMB->Reserved = 0;
3438         pSMB->Flags = 0;
3439         pSMB->Timeout = 0;
3440         pSMB->Reserved2 = 0;
3441         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3442         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3443         pSMB->DataCount = 0;
3444         pSMB->DataOffset = 0;
3445         pSMB->SetupCount = 1;
3446         pSMB->Reserved3 = 0;
3447         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3448         byte_count = params + 1 /* pad */ ;
3449         pSMB->TotalParameterCount = cpu_to_le16(params);
3450         pSMB->ParameterCount = pSMB->TotalParameterCount;
3451         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3452         pSMB->Reserved4 = 0;
3453         pSMB->hdr.smb_buf_length += byte_count;
3454         pSMB->ByteCount = cpu_to_le16(byte_count);
3455
3456         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3457                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3458         if (rc) {
3459                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3460         } else {                /* decode response */
3461                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3462
3463                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3464                         cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3465                                    "Unix Extensions can be disabled on mount "
3466                                    "by specifying the nosfu mount option."));
3467                         rc = -EIO;      /* bad smb */
3468                 } else {
3469                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3470                         memcpy((char *) pFindData,
3471                                (char *) &pSMBr->hdr.Protocol +
3472                                data_offset,
3473                                sizeof(FILE_UNIX_BASIC_INFO));
3474                 }
3475         }
3476         cifs_buf_release(pSMB);
3477         if (rc == -EAGAIN)
3478                 goto UnixQPathInfoRetry;
3479
3480         return rc;
3481 }
3482
3483 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3484 int
3485 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3486               const char *searchName,
3487               const struct nls_table *nls_codepage,
3488               __u16 *pnetfid,
3489               struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3490 {
3491 /* level 257 SMB_ */
3492         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3493         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3494         T2_FFIRST_RSP_PARMS *parms;
3495         int rc = 0;
3496         int bytes_returned = 0;
3497         int name_len;
3498         __u16 params, byte_count;
3499
3500         cFYI(1, ("In FindFirst for %s", searchName));
3501
3502 findFirstRetry:
3503         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3504                       (void **) &pSMBr);
3505         if (rc)
3506                 return rc;
3507
3508         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3509                 name_len =
3510                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3511                                  PATH_MAX, nls_codepage, remap);
3512                 /* We can not add the asterik earlier in case
3513                 it got remapped to 0xF03A as if it were part of the
3514                 directory name instead of a wildcard */
3515                 name_len *= 2;
3516                 pSMB->FileName[name_len] = dirsep;
3517                 pSMB->FileName[name_len+1] = 0;
3518                 pSMB->FileName[name_len+2] = '*';
3519                 pSMB->FileName[name_len+3] = 0;
3520                 name_len += 4; /* now the trailing null */
3521                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3522                 pSMB->FileName[name_len+1] = 0;
3523                 name_len += 2;
3524         } else {        /* BB add check for overrun of SMB buf BB */
3525                 name_len = strnlen(searchName, PATH_MAX);
3526 /* BB fix here and in unicode clause above ie
3527                 if (name_len > buffersize-header)
3528                         free buffer exit; BB */
3529                 strncpy(pSMB->FileName, searchName, name_len);
3530                 pSMB->FileName[name_len] = dirsep;
3531                 pSMB->FileName[name_len+1] = '*';
3532                 pSMB->FileName[name_len+2] = 0;
3533                 name_len += 3;
3534         }
3535
3536         params = 12 + name_len /* includes null */ ;
3537         pSMB->TotalDataCount = 0;       /* no EAs */
3538         pSMB->MaxParameterCount = cpu_to_le16(10);
3539         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3540                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3541         pSMB->MaxSetupCount = 0;
3542         pSMB->Reserved = 0;
3543         pSMB->Flags = 0;
3544         pSMB->Timeout = 0;
3545         pSMB->Reserved2 = 0;
3546         byte_count = params + 1 /* pad */ ;
3547         pSMB->TotalParameterCount = cpu_to_le16(params);
3548         pSMB->ParameterCount = pSMB->TotalParameterCount;
3549         pSMB->ParameterOffset = cpu_to_le16(
3550               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3551                 - 4);
3552         pSMB->DataCount = 0;
3553         pSMB->DataOffset = 0;
3554         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3555         pSMB->Reserved3 = 0;
3556         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3557         pSMB->SearchAttributes =
3558             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3559                         ATTR_DIRECTORY);
3560         pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3561         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3562                 CIFS_SEARCH_RETURN_RESUME);
3563         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3564
3565         /* BB what should we set StorageType to? Does it matter? BB */
3566         pSMB->SearchStorageType = 0;
3567         pSMB->hdr.smb_buf_length += byte_count;
3568         pSMB->ByteCount = cpu_to_le16(byte_count);
3569
3570         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3571                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3572         cifs_stats_inc(&tcon->num_ffirst);
3573
3574         if (rc) {/* BB add logic to retry regular search if Unix search
3575                         rejected unexpectedly by server */
3576                 /* BB Add code to handle unsupported level rc */
3577                 cFYI(1, ("Error in FindFirst = %d", rc));
3578
3579                 cifs_buf_release(pSMB);
3580
3581                 /* BB eventually could optimize out free and realloc of buf */
3582                 /*    for this case */
3583                 if (rc == -EAGAIN)
3584                         goto findFirstRetry;
3585         } else { /* decode response */
3586                 /* BB remember to free buffer if error BB */
3587                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3588                 if (rc == 0) {
3589                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3590                                 psrch_inf->unicode = true;
3591                         else
3592                                 psrch_inf->unicode = false;
3593
3594                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3595                         psrch_inf->smallBuf = 0;
3596                         psrch_inf->srch_entries_start =
3597                                 (char *) &pSMBr->hdr.Protocol +
3598                                         le16_to_cpu(pSMBr->t2.DataOffset);
3599                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3600                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3601
3602                         if (parms->EndofSearch)
3603                                 psrch_inf->endOfSearch = true;
3604                         else
3605                                 psrch_inf->endOfSearch = false;
3606
3607                         psrch_inf->entries_in_buffer =
3608                                         le16_to_cpu(parms->SearchCount);
3609                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3610                                 psrch_inf->entries_in_buffer;
3611                         *pnetfid = parms->SearchHandle;
3612                 } else {
3613                         cifs_buf_release(pSMB);
3614                 }
3615         }
3616
3617         return rc;
3618 }
3619
3620 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3621                  __u16 searchHandle, struct cifs_search_info *psrch_inf)
3622 {
3623         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3624         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3625         T2_FNEXT_RSP_PARMS *parms;
3626         char *response_data;
3627         int rc = 0;
3628         int bytes_returned, name_len;
3629         __u16 params, byte_count;
3630
3631         cFYI(1, ("In FindNext"));
3632
3633         if (psrch_inf->endOfSearch)
3634                 return -ENOENT;
3635
3636         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3637                 (void **) &pSMBr);
3638         if (rc)
3639                 return rc;
3640
3641         params = 14; /* includes 2 bytes of null string, converted to LE below*/
3642         byte_count = 0;
3643         pSMB->TotalDataCount = 0;       /* no EAs */
3644         pSMB->MaxParameterCount = cpu_to_le16(8);
3645         pSMB->MaxDataCount =
3646                 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3647                                 0xFFFFFF00);
3648         pSMB->MaxSetupCount = 0;
3649         pSMB->Reserved = 0;
3650         pSMB->Flags = 0;
3651         pSMB->Timeout = 0;
3652         pSMB->Reserved2 = 0;
3653         pSMB->ParameterOffset =  cpu_to_le16(
3654               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3655         pSMB->DataCount = 0;
3656         pSMB->DataOffset = 0;
3657         pSMB->SetupCount = 1;
3658         pSMB->Reserved3 = 0;
3659         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3660         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3661         pSMB->SearchCount =
3662                 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3663         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3664         pSMB->ResumeKey = psrch_inf->resume_key;
3665         pSMB->SearchFlags =
3666               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3667
3668         name_len = psrch_inf->resume_name_len;
3669         params += name_len;
3670         if (name_len < PATH_MAX) {
3671                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3672                 byte_count += name_len;
3673                 /* 14 byte parm len above enough for 2 byte null terminator */
3674                 pSMB->ResumeFileName[name_len] = 0;
3675                 pSMB->ResumeFileName[name_len+1] = 0;
3676         } else {
3677                 rc = -EINVAL;
3678                 goto FNext2_err_exit;
3679         }
3680         byte_count = params + 1 /* pad */ ;
3681         pSMB->TotalParameterCount = cpu_to_le16(params);
3682         pSMB->ParameterCount = pSMB->TotalParameterCount;
3683         pSMB->hdr.smb_buf_length += byte_count;
3684         pSMB->ByteCount = cpu_to_le16(byte_count);
3685
3686         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3687                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3688         cifs_stats_inc(&tcon->num_fnext);
3689         if (rc) {
3690                 if (rc == -EBADF) {
3691                         psrch_inf->endOfSearch = true;
3692                         cifs_buf_release(pSMB);
3693                         rc = 0; /* search probably was closed at end of search*/
3694                 } else
3695                         cFYI(1, ("FindNext returned = %d", rc));
3696         } else {                /* decode response */
3697                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3698
3699                 if (rc == 0) {
3700                         /* BB fixme add lock for file (srch_info) struct here */
3701                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3702                                 psrch_inf->unicode = true;
3703                         else
3704                                 psrch_inf->unicode = false;
3705                         response_data = (char *) &pSMBr->hdr.Protocol +
3706                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3707                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3708                         response_data = (char *)&pSMBr->hdr.Protocol +
3709                                 le16_to_cpu(pSMBr->t2.DataOffset);
3710                         if (psrch_inf->smallBuf)
3711                                 cifs_small_buf_release(
3712                                         psrch_inf->ntwrk_buf_start);
3713                         else
3714                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3715                         psrch_inf->srch_entries_start = response_data;
3716                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3717                         psrch_inf->smallBuf = 0;
3718                         if (parms->EndofSearch)
3719                                 psrch_inf->endOfSearch = true;
3720                         else
3721                                 psrch_inf->endOfSearch = false;
3722                         psrch_inf->entries_in_buffer =
3723                                                 le16_to_cpu(parms->SearchCount);
3724                         psrch_inf->index_of_last_entry +=
3725                                 psrch_inf->entries_in_buffer;
3726 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3727             psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3728
3729                         /* BB fixme add unlock here */
3730                 }
3731
3732         }
3733
3734         /* BB On error, should we leave previous search buf (and count and
3735         last entry fields) intact or free the previous one? */
3736
3737         /* Note: On -EAGAIN error only caller can retry on handle based calls
3738         since file handle passed in no longer valid */
3739 FNext2_err_exit:
3740         if (rc != 0)
3741                 cifs_buf_release(pSMB);
3742         return rc;
3743 }
3744
3745 int
3746 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3747               const __u16 searchHandle)
3748 {
3749         int rc = 0;
3750         FINDCLOSE_REQ *pSMB = NULL;
3751
3752         cFYI(1, ("In CIFSSMBFindClose"));
3753         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3754
3755         /* no sense returning error if session restarted
3756                 as file handle has been closed */
3757         if (rc == -EAGAIN)
3758                 return 0;
3759         if (rc)
3760                 return rc;
3761
3762         pSMB->FileID = searchHandle;
3763         pSMB->ByteCount = 0;
3764         rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3765         if (rc)
3766                 cERROR(1, ("Send error in FindClose = %d", rc));
3767
3768         cifs_stats_inc(&tcon->num_fclose);
3769
3770         /* Since session is dead, search handle closed on server already */
3771         if (rc == -EAGAIN)
3772                 rc = 0;
3773
3774         return rc;
3775 }
3776
3777 int
3778 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3779                       const unsigned char *searchName,
3780                       __u64 *inode_number,
3781                       const struct nls_table *nls_codepage, int remap)
3782 {
3783         int rc = 0;
3784         TRANSACTION2_QPI_REQ *pSMB = NULL;
3785         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3786         int name_len, bytes_returned;
3787         __u16 params, byte_count;
3788
3789         cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3790         if (tcon == NULL)
3791                 return -ENODEV;
3792
3793 GetInodeNumberRetry:
3794         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3795                       (void **) &pSMBr);
3796         if (rc)
3797                 return rc;
3798
3799         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3800                 name_len =
3801                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3802                                          PATH_MAX, nls_codepage, remap);
3803                 name_len++;     /* trailing null */
3804                 name_len *= 2;
3805         } else {        /* BB improve the check for buffer overruns BB */
3806                 name_len = strnlen(searchName, PATH_MAX);
3807                 name_len++;     /* trailing null */
3808                 strncpy(pSMB->FileName, searchName, name_len);
3809         }
3810
3811         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3812         pSMB->TotalDataCount = 0;
3813         pSMB->MaxParameterCount = cpu_to_le16(2);
3814         /* BB find exact max data count below from sess structure BB */
3815         pSMB->MaxDataCount = cpu_to_le16(4000);
3816         pSMB->MaxSetupCount = 0;
3817         pSMB->Reserved = 0;
3818         pSMB->Flags = 0;
3819         pSMB->Timeout = 0;
3820         pSMB->Reserved2 = 0;
3821         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3822                 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3823         pSMB->DataCount = 0;
3824         pSMB->DataOffset = 0;
3825         pSMB->SetupCount = 1;
3826         pSMB->Reserved3 = 0;
3827         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3828         byte_count = params + 1 /* pad */ ;
3829         pSMB->TotalParameterCount = cpu_to_le16(params);
3830         pSMB->ParameterCount = pSMB->TotalParameterCount;
3831         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3832         pSMB->Reserved4 = 0;
3833         pSMB->hdr.smb_buf_length += byte_count;
3834         pSMB->ByteCount = cpu_to_le16(byte_count);
3835
3836         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3837                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3838         if (rc) {
3839                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3840         } else {
3841                 /* decode response */
3842                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3843                 if (rc || (pSMBr->ByteCount < 2))
3844                 /* BB also check enough total bytes returned */
3845                         /* If rc should we check for EOPNOSUPP and
3846                         disable the srvino flag? or in caller? */
3847                         rc = -EIO;      /* bad smb */
3848                 else {
3849                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3850                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3851                         struct file_internal_info *pfinfo;
3852                         /* BB Do we need a cast or hash here ? */
3853                         if (count < 8) {
3854                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3855                                 rc = -EIO;
3856                                 goto GetInodeNumOut;
3857                         }
3858                         pfinfo = (struct file_internal_info *)
3859                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3860                         *inode_number = pfinfo->UniqueId;
3861                 }
3862         }
3863 GetInodeNumOut:
3864         cifs_buf_release(pSMB);
3865         if (rc == -EAGAIN)
3866                 goto GetInodeNumberRetry;
3867         return rc;
3868 }
3869
3870 int
3871 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3872                 const unsigned char *searchName,
3873                 struct dfs_info3_param **target_nodes,
3874                 unsigned int *num_of_nodes,
3875                 const struct nls_table *nls_codepage, int remap)
3876 {
3877 /* TRANS2_GET_DFS_REFERRAL */
3878         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3879         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3880         struct dfs_referral_level_3 *referrals = NULL;
3881         int rc = 0;
3882         int bytes_returned;
3883         int name_len;
3884         unsigned int i;
3885         char *temp;
3886         __u16 params, byte_count;
3887         *num_of_nodes = 0;
3888         *target_nodes = NULL;
3889
3890         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3891         if (ses == NULL)
3892                 return -ENODEV;
3893 getDFSRetry:
3894         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3895                       (void **) &pSMBr);
3896         if (rc)
3897                 return rc;
3898
3899         /* server pointer checked in called function,
3900         but should never be null here anyway */
3901         pSMB->hdr.Mid = GetNextMid(ses->server);
3902         pSMB->hdr.Tid = ses->ipc_tid;
3903         pSMB->hdr.Uid = ses->Suid;
3904         if (ses->capabilities & CAP_STATUS32)
3905                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3906         if (ses->capabilities & CAP_DFS)
3907                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3908
3909         if (ses->capabilities & CAP_UNICODE) {
3910                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3911                 name_len =
3912                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3913                                      searchName, PATH_MAX, nls_codepage, remap);
3914                 name_len++;     /* trailing null */
3915                 name_len *= 2;
3916         } else {        /* BB improve the check for buffer overruns BB */
3917                 name_len = strnlen(searchName, PATH_MAX);
3918                 name_len++;     /* trailing null */
3919                 strncpy(pSMB->RequestFileName, searchName, name_len);
3920         }
3921
3922         if (ses->server) {
3923                 if (ses->server->secMode &
3924                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3925                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3926         }
3927
3928         pSMB->hdr.Uid = ses->Suid;
3929
3930         params = 2 /* level */  + name_len /*includes null */ ;
3931         pSMB->TotalDataCount = 0;
3932         pSMB->DataCount = 0;
3933         pSMB->DataOffset = 0;
3934         pSMB->MaxParameterCount = 0;
3935         /* BB find exact max SMB PDU from sess structure BB */
3936         pSMB->MaxDataCount = cpu_to_le16(4000);
3937         pSMB->MaxSetupCount = 0;
3938         pSMB->Reserved = 0;
3939         pSMB->Flags = 0;
3940         pSMB->Timeout = 0;
3941         pSMB->Reserved2 = 0;
3942         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3943           struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3944         pSMB->SetupCount = 1;
3945         pSMB->Reserved3 = 0;
3946         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3947         byte_count = params + 3 /* pad */ ;
3948         pSMB->ParameterCount = cpu_to_le16(params);
3949         pSMB->TotalParameterCount = pSMB->ParameterCount;
3950         pSMB->MaxReferralLevel = cpu_to_le16(3);
3951         pSMB->hdr.smb_buf_length += byte_count;
3952         pSMB->ByteCount = cpu_to_le16(byte_count);
3953
3954         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3955                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3956         if (rc) {
3957                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3958                 goto GetDFSRefExit;
3959         }
3960         rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3961
3962         /* BB Also check if enough total bytes returned? */
3963         if (rc || (pSMBr->ByteCount < 17))
3964                 rc = -EIO;      /* bad smb */
3965         else {
3966                 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3967                 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3968
3969                 cFYI(1, ("Decoding GetDFSRefer response BCC: %d  Offset %d",
3970                          pSMBr->ByteCount, data_offset));
3971                 referrals =
3972                     (struct dfs_referral_level_3 *)
3973                                 (8 /* sizeof start of data block */ +
3974                                 data_offset +
3975                                 (char *) &pSMBr->hdr.Protocol);
3976                 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3977                         "for referral one refer size: 0x%x srv "
3978                         "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3979                         le16_to_cpu(pSMBr->NumberOfReferrals),
3980                         le16_to_cpu(pSMBr->DFSFlags),
3981                         le16_to_cpu(referrals->ReferralSize),
3982                         le16_to_cpu(referrals->ServerType),
3983                         le16_to_cpu(referrals->ReferralFlags),
3984                         le16_to_cpu(referrals->TimeToLive)));
3985                 /* BB This field is actually two bytes in from start of
3986                    data block so we could do safety check that DataBlock
3987                    begins at address of pSMBr->NumberOfReferrals */
3988                 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3989
3990                 /* BB Fix below so can return more than one referral */
3991                 if (*num_of_nodes > 1)
3992                         *num_of_nodes = 1;
3993
3994                 /* get the length of the strings describing refs */
3995                 name_len = 0;
3996                 for (i = 0; i < *num_of_nodes; i++) {
3997                         /* make sure that DfsPathOffset not past end */
3998                         __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3999                         if (offset > data_count) {
4000                                 /* if invalid referral, stop here and do
4001                                 not try to copy any more */
4002                                 *num_of_nodes = i;
4003                                 break;
4004                         }
4005                         temp = ((char *)referrals) + offset;
4006
4007                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4008                                 name_len += UniStrnlen((wchar_t *)temp,
4009                                                         data_count);
4010                         } else {
4011                                 name_len += strnlen(temp, data_count);
4012                         }
4013                         referrals++;
4014                         /* BB add check that referral pointer does
4015                            not fall off end PDU */
4016                 }
4017                 /* BB add check for name_len bigger than bcc */
4018                 *target_nodes =
4019                         kmalloc(name_len+1+(*num_of_nodes),
4020                                 GFP_KERNEL);
4021                 if (*target_nodes == NULL) {
4022                         rc = -ENOMEM;
4023                         goto GetDFSRefExit;
4024                 }
4025
4026                 referrals = (struct dfs_referral_level_3 *)
4027                                 (8 /* sizeof data hdr */ + data_offset +
4028                                 (char *) &pSMBr->hdr.Protocol);
4029
4030                 for (i = 0; i < *num_of_nodes; i++) {
4031                         temp = ((char *)referrals) +
4032                                   le16_to_cpu(referrals->DfsPathOffset);
4033                         /*  BB update target_uncs pointers */
4034                         referrals++;
4035                 }
4036         }
4037 GetDFSRefExit:
4038         if (pSMB)
4039                 cifs_buf_release(pSMB);
4040
4041         if (rc == -EAGAIN)
4042                 goto getDFSRetry;
4043
4044         return rc;
4045 }
4046
4047 /* Query File System Info such as free space to old servers such as Win 9x */
4048 int
4049 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4050 {
4051 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4052         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4053         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4054         FILE_SYSTEM_ALLOC_INFO *response_data;
4055         int rc = 0;
4056         int bytes_returned = 0;
4057         __u16 params, byte_count;
4058
4059         cFYI(1, ("OldQFSInfo"));
4060 oldQFSInfoRetry:
4061         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062                 (void **) &pSMBr);
4063         if (rc)
4064                 return rc;
4065
4066         params = 2;     /* level */
4067         pSMB->TotalDataCount = 0;
4068         pSMB->MaxParameterCount = cpu_to_le16(2);
4069         pSMB->MaxDataCount = cpu_to_le16(1000);
4070         pSMB->MaxSetupCount = 0;
4071         pSMB->Reserved = 0;
4072         pSMB->Flags = 0;
4073         pSMB->Timeout = 0;
4074         pSMB->Reserved2 = 0;
4075         byte_count = params + 1 /* pad */ ;
4076         pSMB->TotalParameterCount = cpu_to_le16(params);
4077         pSMB->ParameterCount = pSMB->TotalParameterCount;
4078         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4079         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4080         pSMB->DataCount = 0;
4081         pSMB->DataOffset = 0;
4082         pSMB->SetupCount = 1;
4083         pSMB->Reserved3 = 0;
4084         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4085         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4086         pSMB->hdr.smb_buf_length += byte_count;
4087         pSMB->ByteCount = cpu_to_le16(byte_count);
4088
4089         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091         if (rc) {
4092                 cFYI(1, ("Send error in QFSInfo = %d", rc));
4093         } else {                /* decode response */
4094                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4095
4096                 if (rc || (pSMBr->ByteCount < 18))
4097                         rc = -EIO;      /* bad smb */
4098                 else {
4099                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4100                         cFYI(1, ("qfsinf resp BCC: %d  Offset %d",
4101                                  pSMBr->ByteCount, data_offset));
4102
4103                         response_data = (FILE_SYSTEM_ALLOC_INFO *)
4104                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4105                         FSData->f_bsize =
4106                                 le16_to_cpu(response_data->BytesPerSector) *
4107                                 le32_to_cpu(response_data->
4108                                         SectorsPerAllocationUnit);
4109                         FSData->f_blocks =
4110                                le32_to_cpu(response_data->TotalAllocationUnits);
4111                         FSData->f_bfree = FSData->f_bavail =
4112                                 le32_to_cpu(response_data->FreeAllocationUnits);
4113                         cFYI(1,
4114                              ("Blocks: %lld  Free: %lld Block size %ld",
4115                               (unsigned long long)FSData->f_blocks,
4116                               (unsigned long long)FSData->f_bfree,
4117                               FSData->f_bsize));
4118                 }
4119         }
4120         cifs_buf_release(pSMB);
4121
4122         if (rc == -EAGAIN)
4123                 goto oldQFSInfoRetry;
4124
4125         return rc;
4126 }
4127
4128 int
4129 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4130 {
4131 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4132         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4133         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4134         FILE_SYSTEM_INFO *response_data;
4135         int rc = 0;
4136         int bytes_returned = 0;
4137         __u16 params, byte_count;
4138
4139         cFYI(1, ("In QFSInfo"));
4140 QFSInfoRetry:
4141         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4142                       (void **) &pSMBr);
4143         if (rc)
4144                 return rc;
4145
4146         params = 2;     /* level */
4147         pSMB->TotalDataCount = 0;
4148         pSMB->MaxParameterCount = cpu_to_le16(2);
4149         pSMB->MaxDataCount = cpu_to_le16(1000);
4150         pSMB->MaxSetupCount = 0;
4151         pSMB->Reserved = 0;
4152         pSMB->Flags = 0;
4153         pSMB->Timeout = 0;
4154         pSMB->Reserved2 = 0;
4155         byte_count = params + 1 /* pad */ ;
4156         pSMB->TotalParameterCount = cpu_to_le16(params);
4157         pSMB->ParameterCount = pSMB->TotalParameterCount;
4158         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4159                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4160         pSMB->DataCount = 0;
4161         pSMB->DataOffset = 0;
4162         pSMB->SetupCount = 1;
4163         pSMB->Reserved3 = 0;
4164         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4165         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4166         pSMB->hdr.smb_buf_length += byte_count;
4167         pSMB->ByteCount = cpu_to_le16(byte_count);
4168
4169         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171         if (rc) {
4172                 cFYI(1, ("Send error in QFSInfo = %d", rc));
4173         } else {                /* decode response */
4174                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4175
4176                 if (rc || (pSMBr->ByteCount < 24))
4177                         rc = -EIO;      /* bad smb */
4178                 else {
4179                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4180
4181                         response_data =
4182                             (FILE_SYSTEM_INFO
4183                              *) (((char *) &pSMBr->hdr.Protocol) +
4184                                  data_offset);
4185                         FSData->f_bsize =
4186                             le32_to_cpu(response_data->BytesPerSector) *
4187                             le32_to_cpu(response_data->
4188                                         SectorsPerAllocationUnit);
4189                         FSData->f_blocks =
4190                             le64_to_cpu(response_data->TotalAllocationUnits);
4191                         FSData->f_bfree = FSData->f_bavail =
4192                             le64_to_cpu(response_data->FreeAllocationUnits);
4193                         cFYI(1,
4194                              ("Blocks: %lld  Free: %lld Block size %ld",
4195                               (unsigned long long)FSData->f_blocks,
4196                               (unsigned long long)FSData->f_bfree,
4197                               FSData->f_bsize));
4198                 }
4199         }
4200         cifs_buf_release(pSMB);
4201
4202         if (rc == -EAGAIN)
4203                 goto QFSInfoRetry;
4204
4205         return rc;
4206 }
4207
4208 int
4209 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4210 {
4211 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
4212         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4215         int rc = 0;
4216         int bytes_returned = 0;
4217         __u16 params, byte_count;
4218
4219         cFYI(1, ("In QFSAttributeInfo"));
4220 QFSAttributeRetry:
4221         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4222                       (void **) &pSMBr);
4223         if (rc)
4224                 return rc;
4225
4226         params = 2;     /* level */
4227         pSMB->TotalDataCount = 0;
4228         pSMB->MaxParameterCount = cpu_to_le16(2);
4229         /* BB find exact max SMB PDU from sess structure BB */
4230         pSMB->MaxDataCount = cpu_to_le16(1000);
4231         pSMB->MaxSetupCount = 0;
4232         pSMB->Reserved = 0;
4233         pSMB->Flags = 0;
4234         pSMB->Timeout = 0;
4235         pSMB->Reserved2 = 0;
4236         byte_count = params + 1 /* pad */ ;
4237         pSMB->TotalParameterCount = cpu_to_le16(params);
4238         pSMB->ParameterCount = pSMB->TotalParameterCount;
4239         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4240                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4241         pSMB->DataCount = 0;
4242         pSMB->DataOffset = 0;
4243         pSMB->SetupCount = 1;
4244         pSMB->Reserved3 = 0;
4245         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4246         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4247         pSMB->hdr.smb_buf_length += byte_count;
4248         pSMB->ByteCount = cpu_to_le16(byte_count);
4249
4250         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4251                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4252         if (rc) {
4253                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4254         } else {                /* decode response */
4255                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4256
4257                 if (rc || (pSMBr->ByteCount < 13)) {
4258                         /* BB also check if enough bytes returned */
4259                         rc = -EIO;      /* bad smb */
4260                 } else {
4261                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4262                         response_data =
4263                             (FILE_SYSTEM_ATTRIBUTE_INFO
4264                              *) (((char *) &pSMBr->hdr.Protocol) +
4265                                  data_offset);
4266                         memcpy(&tcon->fsAttrInfo, response_data,
4267                                sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4268                 }
4269         }
4270         cifs_buf_release(pSMB);
4271
4272         if (rc == -EAGAIN)
4273                 goto QFSAttributeRetry;
4274
4275         return rc;
4276 }
4277
4278 int
4279 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4280 {
4281 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4282         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4283         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4284         FILE_SYSTEM_DEVICE_INFO *response_data;
4285         int rc = 0;
4286         int bytes_returned = 0;
4287         __u16 params, byte_count;
4288
4289         cFYI(1, ("In QFSDeviceInfo"));
4290 QFSDeviceRetry:
4291         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4292                       (void **) &pSMBr);
4293         if (rc)
4294                 return rc;
4295
4296         params = 2;     /* level */
4297         pSMB->TotalDataCount = 0;
4298         pSMB->MaxParameterCount = cpu_to_le16(2);
4299         /* BB find exact max SMB PDU from sess structure BB */
4300         pSMB->MaxDataCount = cpu_to_le16(1000);
4301         pSMB->MaxSetupCount = 0;
4302         pSMB->Reserved = 0;
4303         pSMB->Flags = 0;
4304         pSMB->Timeout = 0;
4305         pSMB->Reserved2 = 0;
4306         byte_count = params + 1 /* pad */ ;
4307         pSMB->TotalParameterCount = cpu_to_le16(params);
4308         pSMB->ParameterCount = pSMB->TotalParameterCount;
4309         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4310                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4311
4312         pSMB->DataCount = 0;
4313         pSMB->DataOffset = 0;
4314         pSMB->SetupCount = 1;
4315         pSMB->Reserved3 = 0;
4316         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4317         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4318         pSMB->hdr.smb_buf_length += byte_count;
4319         pSMB->ByteCount = cpu_to_le16(byte_count);
4320
4321         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4322                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4323         if (rc) {
4324                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4325         } else {                /* decode response */
4326                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4327
4328                 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4329                         rc = -EIO;      /* bad smb */
4330                 else {
4331                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4332                         response_data =
4333                             (FILE_SYSTEM_DEVICE_INFO *)
4334                                 (((char *) &pSMBr->hdr.Protocol) +
4335                                  data_offset);
4336                         memcpy(&tcon->fsDevInfo, response_data,
4337                                sizeof(FILE_SYSTEM_DEVICE_INFO));
4338                 }
4339         }
4340         cifs_buf_release(pSMB);
4341
4342         if (rc == -EAGAIN)
4343                 goto QFSDeviceRetry;
4344
4345         return rc;
4346 }
4347
4348 int
4349 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4350 {
4351 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
4352         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4353         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4354         FILE_SYSTEM_UNIX_INFO *response_data;
4355         int rc = 0;
4356         int bytes_returned = 0;
4357         __u16 params, byte_count;
4358
4359         cFYI(1, ("In QFSUnixInfo"));
4360 QFSUnixRetry:
4361         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4362                       (void **) &pSMBr);
4363         if (rc)
4364                 return rc;
4365
4366         params = 2;     /* level */
4367         pSMB->TotalDataCount = 0;
4368         pSMB->DataCount = 0;
4369         pSMB->DataOffset = 0;
4370         pSMB->MaxParameterCount = cpu_to_le16(2);
4371         /* BB find exact max SMB PDU from sess structure BB */
4372         pSMB->MaxDataCount = cpu_to_le16(100);
4373         pSMB->MaxSetupCount = 0;
4374         pSMB->Reserved = 0;
4375         pSMB->Flags = 0;
4376         pSMB->Timeout = 0;
4377         pSMB->Reserved2 = 0;
4378         byte_count = params + 1 /* pad */ ;
4379         pSMB->ParameterCount = cpu_to_le16(params);
4380         pSMB->TotalParameterCount = pSMB->ParameterCount;
4381         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4382                         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4383         pSMB->SetupCount = 1;
4384         pSMB->Reserved3 = 0;
4385         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4386         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4387         pSMB->hdr.smb_buf_length += byte_count;
4388         pSMB->ByteCount = cpu_to_le16(byte_count);
4389
4390         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4391                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4392         if (rc) {
4393                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4394         } else {                /* decode response */
4395                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4396
4397                 if (rc || (pSMBr->ByteCount < 13)) {
4398                         rc = -EIO;      /* bad smb */
4399                 } else {
4400                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4401                         response_data =
4402                             (FILE_SYSTEM_UNIX_INFO
4403                              *) (((char *) &pSMBr->hdr.Protocol) +
4404                                  data_offset);
4405                         memcpy(&tcon->fsUnixInfo, response_data,
4406                                sizeof(FILE_SYSTEM_UNIX_INFO));
4407                 }
4408         }
4409         cifs_buf_release(pSMB);
4410
4411         if (rc == -EAGAIN)
4412                 goto QFSUnixRetry;
4413
4414
4415         return rc;
4416 }
4417
4418 int
4419 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4420 {
4421 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
4422         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4423         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4424         int rc = 0;
4425         int bytes_returned = 0;
4426         __u16 params, param_offset, offset, byte_count;
4427
4428         cFYI(1, ("In SETFSUnixInfo"));
4429 SETFSUnixRetry:
4430         /* BB switch to small buf init to save memory */
4431         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4432                       (void **) &pSMBr);
4433         if (rc)
4434                 return rc;
4435
4436         params = 4;     /* 2 bytes zero followed by info level. */
4437         pSMB->MaxSetupCount = 0;
4438         pSMB->Reserved = 0;
4439         pSMB->Flags = 0;
4440         pSMB->Timeout = 0;
4441         pSMB->Reserved2 = 0;
4442         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4443                                 - 4;
4444         offset = param_offset + params;
4445
4446         pSMB->MaxParameterCount = cpu_to_le16(4);
4447         /* BB find exact max SMB PDU from sess structure BB */
4448         pSMB->MaxDataCount = cpu_to_le16(100);
4449         pSMB->SetupCount = 1;
4450         pSMB->Reserved3 = 0;
4451         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4452         byte_count = 1 /* pad */ + params + 12;
4453
4454         pSMB->DataCount = cpu_to_le16(12);
4455         pSMB->ParameterCount = cpu_to_le16(params);
4456         pSMB->TotalDataCount = pSMB->DataCount;
4457         pSMB->TotalParameterCount = pSMB->ParameterCount;
4458         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4459         pSMB->DataOffset = cpu_to_le16(offset);
4460
4461         /* Params. */
4462         pSMB->FileNum = 0;
4463         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4464
4465         /* Data. */
4466         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4467         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4468         pSMB->ClientUnixCap = cpu_to_le64(cap);
4469
4470         pSMB->hdr.smb_buf_length += byte_count;
4471         pSMB->ByteCount = cpu_to_le16(byte_count);
4472
4473         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4474                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4475         if (rc) {
4476                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4477         } else {                /* decode response */
4478                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4479                 if (rc)
4480                         rc = -EIO;      /* bad smb */
4481         }
4482         cifs_buf_release(pSMB);
4483
4484         if (rc == -EAGAIN)
4485                 goto SETFSUnixRetry;
4486
4487         return rc;
4488 }
4489
4490
4491
4492 int
4493 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4494                    struct kstatfs *FSData)
4495 {
4496 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4497         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4498         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4499         FILE_SYSTEM_POSIX_INFO *response_data;
4500         int rc = 0;
4501         int bytes_returned = 0;
4502         __u16 params, byte_count;
4503
4504         cFYI(1, ("In QFSPosixInfo"));
4505 QFSPosixRetry:
4506         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4507                       (void **) &pSMBr);
4508         if (rc)
4509                 return rc;
4510
4511         params = 2;     /* level */
4512         pSMB->TotalDataCount = 0;
4513         pSMB->DataCount = 0;
4514         pSMB->DataOffset = 0;
4515         pSMB->MaxParameterCount = cpu_to_le16(2);
4516         /* BB find exact max SMB PDU from sess structure BB */
4517         pSMB->MaxDataCount = cpu_to_le16(100);
4518         pSMB->MaxSetupCount = 0;
4519         pSMB->Reserved = 0;
4520         pSMB->Flags = 0;
4521         pSMB->Timeout = 0;
4522         pSMB->Reserved2 = 0;
4523         byte_count = params + 1 /* pad */ ;
4524         pSMB->ParameterCount = cpu_to_le16(params);
4525         pSMB->TotalParameterCount = pSMB->ParameterCount;
4526         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4527                         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4528         pSMB->SetupCount = 1;
4529         pSMB->Reserved3 = 0;
4530         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4531         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4532         pSMB->hdr.smb_buf_length += byte_count;
4533         pSMB->ByteCount = cpu_to_le16(byte_count);
4534
4535         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4536                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4537         if (rc) {
4538                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4539         } else {                /* decode response */
4540                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4541
4542                 if (rc || (pSMBr->ByteCount < 13)) {
4543                         rc = -EIO;      /* bad smb */
4544                 } else {
4545                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4546                         response_data =
4547                             (FILE_SYSTEM_POSIX_INFO
4548                              *) (((char *) &pSMBr->hdr.Protocol) +
4549                                  data_offset);
4550                         FSData->f_bsize =
4551                                         le32_to_cpu(response_data->BlockSize);
4552                         FSData->f_blocks =
4553                                         le64_to_cpu(response_data->TotalBlocks);
4554                         FSData->f_bfree =
4555                             le64_to_cpu(response_data->BlocksAvail);
4556                         if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4557                                 FSData->f_bavail = FSData->f_bfree;
4558                         } else {
4559                                 FSData->f_bavail =
4560                                     le64_to_cpu(response_data->UserBlocksAvail);
4561                         }
4562                         if (response_data->TotalFileNodes != cpu_to_le64(-1))
4563                                 FSData->f_files =
4564                                      le64_to_cpu(response_data->TotalFileNodes);
4565                         if (response_data->FreeFileNodes != cpu_to_le64(-1))
4566                                 FSData->f_ffree =
4567                                       le64_to_cpu(response_data->FreeFileNodes);
4568                 }
4569         }
4570         cifs_buf_release(pSMB);
4571
4572         if (rc == -EAGAIN)
4573                 goto QFSPosixRetry;
4574
4575         return rc;
4576 }
4577
4578
4579 /* We can not use write of zero bytes trick to
4580    set file size due to need for large file support.  Also note that
4581    this SetPathInfo is preferred to SetFileInfo based method in next
4582    routine which is only needed to work around a sharing violation bug
4583    in Samba which this routine can run into */
4584
4585 int
4586 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4587               __u64 size, bool SetAllocation,
4588               const struct nls_table *nls_codepage, int remap)
4589 {
4590         struct smb_com_transaction2_spi_req *pSMB = NULL;
4591         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4592         struct file_end_of_file_info *parm_data;
4593         int name_len;
4594         int rc = 0;
4595         int bytes_returned = 0;
4596         __u16 params, byte_count, data_count, param_offset, offset;
4597
4598         cFYI(1, ("In SetEOF"));
4599 SetEOFRetry:
4600         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4601                       (void **) &pSMBr);
4602         if (rc)
4603                 return rc;
4604
4605         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4606                 name_len =
4607                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4608                                      PATH_MAX, nls_codepage, remap);
4609                 name_len++;     /* trailing null */
4610                 name_len *= 2;
4611         } else {        /* BB improve the check for buffer overruns BB */
4612                 name_len = strnlen(fileName, PATH_MAX);
4613                 name_len++;     /* trailing null */
4614                 strncpy(pSMB->FileName, fileName, name_len);
4615         }
4616         params = 6 + name_len;
4617         data_count = sizeof(struct file_end_of_file_info);
4618         pSMB->MaxParameterCount = cpu_to_le16(2);
4619         pSMB->MaxDataCount = cpu_to_le16(4100);
4620         pSMB->MaxSetupCount = 0;
4621         pSMB->Reserved = 0;
4622         pSMB->Flags = 0;
4623         pSMB->Timeout = 0;
4624         pSMB->Reserved2 = 0;
4625         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4626                                 InformationLevel) - 4;
4627         offset = param_offset + params;
4628         if (SetAllocation) {
4629                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4630                         pSMB->InformationLevel =
4631                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4632                 else
4633                         pSMB->InformationLevel =
4634                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4635         } else /* Set File Size */  {
4636             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4637                     pSMB->InformationLevel =
4638                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4639             else
4640                     pSMB->InformationLevel =
4641                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4642         }
4643
4644         parm_data =
4645             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4646                                        offset);
4647         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4648         pSMB->DataOffset = cpu_to_le16(offset);
4649         pSMB->SetupCount = 1;
4650         pSMB->Reserved3 = 0;
4651         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4652         byte_count = 3 /* pad */  + params + data_count;
4653         pSMB->DataCount = cpu_to_le16(data_count);
4654         pSMB->TotalDataCount = pSMB->DataCount;
4655         pSMB->ParameterCount = cpu_to_le16(params);
4656         pSMB->TotalParameterCount = pSMB->ParameterCount;
4657         pSMB->Reserved4 = 0;
4658         pSMB->hdr.smb_buf_length += byte_count;
4659         parm_data->FileSize = cpu_to_le64(size);
4660         pSMB->ByteCount = cpu_to_le16(byte_count);
4661         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4662                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4663         if (rc)
4664                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4665
4666         cifs_buf_release(pSMB);
4667
4668         if (rc == -EAGAIN)
4669                 goto SetEOFRetry;
4670
4671         return rc;
4672 }
4673
4674 int
4675 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4676                    __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4677 {
4678         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4679         char *data_offset;
4680         struct file_end_of_file_info *parm_data;
4681         int rc = 0;
4682         __u16 params, param_offset, offset, byte_count, count;
4683
4684         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4685                         (long long)size));
4686         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4687
4688         if (rc)
4689                 return rc;
4690
4691         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4692         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4693
4694         params = 6;
4695         pSMB->MaxSetupCount = 0;
4696         pSMB->Reserved = 0;
4697         pSMB->Flags = 0;
4698         pSMB->Timeout = 0;
4699         pSMB->Reserved2 = 0;
4700         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4701         offset = param_offset + params;
4702
4703         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4704
4705         count = sizeof(struct file_end_of_file_info);
4706         pSMB->MaxParameterCount = cpu_to_le16(2);
4707         /* BB find exact max SMB PDU from sess structure BB */
4708         pSMB->MaxDataCount = cpu_to_le16(1000);
4709         pSMB->SetupCount = 1;
4710         pSMB->Reserved3 = 0;
4711         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4712         byte_count = 3 /* pad */  + params + count;
4713         pSMB->DataCount = cpu_to_le16(count);
4714         pSMB->ParameterCount = cpu_to_le16(params);
4715         pSMB->TotalDataCount = pSMB->DataCount;
4716         pSMB->TotalParameterCount = pSMB->ParameterCount;
4717         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4718         parm_data =
4719                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4720                                 + offset);
4721         pSMB->DataOffset = cpu_to_le16(offset);
4722         parm_data->FileSize = cpu_to_le64(size);
4723         pSMB->Fid = fid;
4724         if (SetAllocation) {
4725                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4726                         pSMB->InformationLevel =
4727                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4728                 else
4729                         pSMB->InformationLevel =
4730                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4731         } else /* Set File Size */  {
4732             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733                     pSMB->InformationLevel =
4734                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4735             else
4736                     pSMB->InformationLevel =
4737                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4738         }
4739         pSMB->Reserved4 = 0;
4740         pSMB->hdr.smb_buf_length += byte_count;
4741         pSMB->ByteCount = cpu_to_le16(byte_count);
4742         rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4743         if (rc) {
4744                 cFYI(1,
4745                      ("Send error in SetFileInfo (SetFileSize) = %d",
4746                       rc));
4747         }
4748
4749         /* Note: On -EAGAIN error only caller can retry on handle based calls
4750                 since file handle passed in no longer valid */
4751
4752         return rc;
4753 }
4754
4755 /* Some legacy servers such as NT4 require that the file times be set on
4756    an open handle, rather than by pathname - this is awkward due to
4757    potential access conflicts on the open, but it is unavoidable for these
4758    old servers since the only other choice is to go from 100 nanosecond DCE
4759    time and resort to the original setpathinfo level which takes the ancient
4760    DOS time format with 2 second granularity */
4761 int
4762 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4763                     const FILE_BASIC_INFO *data, __u16 fid)
4764 {
4765         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4766         char *data_offset;
4767         int rc = 0;
4768         __u16 params, param_offset, offset, byte_count, count;
4769
4770         cFYI(1, ("Set Times (via SetFileInfo)"));
4771         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4772
4773         if (rc)
4774                 return rc;
4775
4776         /* At this point there is no need to override the current pid
4777         with the pid of the opener, but that could change if we someday
4778         use an existing handle (rather than opening one on the fly) */
4779         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4780         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4781
4782         params = 6;
4783         pSMB->MaxSetupCount = 0;
4784         pSMB->Reserved = 0;
4785         pSMB->Flags = 0;
4786         pSMB->Timeout = 0;
4787         pSMB->Reserved2 = 0;
4788         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4789         offset = param_offset + params;
4790
4791         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4792
4793         count = sizeof(FILE_BASIC_INFO);
4794         pSMB->MaxParameterCount = cpu_to_le16(2);
4795         /* BB find max SMB PDU from sess */
4796         pSMB->MaxDataCount = cpu_to_le16(1000);
4797         pSMB->SetupCount = 1;
4798         pSMB->Reserved3 = 0;
4799         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4800         byte_count = 3 /* pad */  + params + count;
4801         pSMB->DataCount = cpu_to_le16(count);
4802         pSMB->ParameterCount = cpu_to_le16(params);
4803         pSMB->TotalDataCount = pSMB->DataCount;
4804         pSMB->TotalParameterCount = pSMB->ParameterCount;
4805         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4806         pSMB->DataOffset = cpu_to_le16(offset);
4807         pSMB->Fid = fid;
4808         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4809                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4810         else
4811                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4812         pSMB->Reserved4 = 0;
4813         pSMB->hdr.smb_buf_length += byte_count;
4814         pSMB->ByteCount = cpu_to_le16(byte_count);
4815         memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4816         rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4817         if (rc)
4818                 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4819
4820         /* Note: On -EAGAIN error only caller can retry on handle based calls
4821                 since file handle passed in no longer valid */
4822
4823         return rc;
4824 }
4825
4826
4827 int
4828 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4829                 const FILE_BASIC_INFO *data,
4830                 const struct nls_table *nls_codepage, int remap)
4831 {
4832         TRANSACTION2_SPI_REQ *pSMB = NULL;
4833         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4834         int name_len;
4835         int rc = 0;
4836         int bytes_returned = 0;
4837         char *data_offset;
4838         __u16 params, param_offset, offset, byte_count, count;
4839
4840         cFYI(1, ("In SetTimes"));
4841
4842 SetTimesRetry:
4843         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4844                       (void **) &pSMBr);
4845         if (rc)
4846                 return rc;
4847
4848         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4849                 name_len =
4850                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4851                                      PATH_MAX, nls_codepage, remap);
4852                 name_len++;     /* trailing null */
4853                 name_len *= 2;
4854         } else {        /* BB improve the check for buffer overruns BB */
4855                 name_len = strnlen(fileName, PATH_MAX);
4856                 name_len++;     /* trailing null */
4857                 strncpy(pSMB->FileName, fileName, name_len);
4858         }
4859
4860         params = 6 + name_len;
4861         count = sizeof(FILE_BASIC_INFO);
4862         pSMB->MaxParameterCount = cpu_to_le16(2);
4863         /* BB find max SMB PDU from sess structure BB */
4864         pSMB->MaxDataCount = cpu_to_le16(1000);
4865         pSMB->MaxSetupCount = 0;
4866         pSMB->Reserved = 0;
4867         pSMB->Flags = 0;
4868         pSMB->Timeout = 0;
4869         pSMB->Reserved2 = 0;
4870         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4871                                 InformationLevel) - 4;
4872         offset = param_offset + params;
4873         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4874         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4875         pSMB->DataOffset = cpu_to_le16(offset);
4876         pSMB->SetupCount = 1;
4877         pSMB->Reserved3 = 0;
4878         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4879         byte_count = 3 /* pad */  + params + count;
4880
4881         pSMB->DataCount = cpu_to_le16(count);
4882         pSMB->ParameterCount = cpu_to_le16(params);
4883         pSMB->TotalDataCount = pSMB->DataCount;
4884         pSMB->TotalParameterCount = pSMB->ParameterCount;
4885         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4886                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4887         else
4888                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4889         pSMB->Reserved4 = 0;
4890         pSMB->hdr.smb_buf_length += byte_count;
4891         memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4892         pSMB->ByteCount = cpu_to_le16(byte_count);
4893         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4894                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4895         if (rc)
4896                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4897
4898         cifs_buf_release(pSMB);
4899
4900         if (rc == -EAGAIN)
4901                 goto SetTimesRetry;
4902
4903         return rc;
4904 }
4905
4906 /* Can not be used to set time stamps yet (due to old DOS time format) */
4907 /* Can be used to set attributes */
4908 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4909           handling it anyway and NT4 was what we thought it would be needed for
4910           Do not delete it until we prove whether needed for Win9x though */
4911 int
4912 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4913                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4914 {
4915         SETATTR_REQ *pSMB = NULL;
4916         SETATTR_RSP *pSMBr = NULL;
4917         int rc = 0;
4918         int bytes_returned;
4919         int name_len;
4920
4921         cFYI(1, ("In SetAttrLegacy"));
4922
4923 SetAttrLgcyRetry:
4924         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4925                       (void **) &pSMBr);
4926         if (rc)
4927                 return rc;
4928
4929         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4930                 name_len =
4931                         ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4932                                 PATH_MAX, nls_codepage);
4933                 name_len++;     /* trailing null */
4934                 name_len *= 2;
4935         } else {        /* BB improve the check for buffer overruns BB */
4936                 name_len = strnlen(fileName, PATH_MAX);
4937                 name_len++;     /* trailing null */
4938                 strncpy(pSMB->fileName, fileName, name_len);
4939         }
4940         pSMB->attr = cpu_to_le16(dos_attrs);
4941         pSMB->BufferFormat = 0x04;
4942         pSMB->hdr.smb_buf_length += name_len + 1;
4943         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4944         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4945                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4946         if (rc)
4947                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4948
4949         cifs_buf_release(pSMB);
4950
4951         if (rc == -EAGAIN)
4952                 goto SetAttrLgcyRetry;
4953
4954         return rc;
4955 }
4956 #endif /* temporarily unneeded SetAttr legacy function */
4957
4958 int
4959 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4960                     char *fileName, __u64 mode, __u64 uid, __u64 gid,
4961                     dev_t device, const struct nls_table *nls_codepage,
4962                     int remap)
4963 {
4964         TRANSACTION2_SPI_REQ *pSMB = NULL;
4965         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4966         int name_len;
4967         int rc = 0;
4968         int bytes_returned = 0;
4969         FILE_UNIX_BASIC_INFO *data_offset;
4970         __u16 params, param_offset, offset, count, byte_count;
4971
4972         cFYI(1, ("In SetUID/GID/Mode"));
4973 setPermsRetry:
4974         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4975                       (void **) &pSMBr);
4976         if (rc)
4977                 return rc;
4978
4979         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4980                 name_len =
4981                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4982                                      PATH_MAX, nls_codepage, remap);
4983                 name_len++;     /* trailing null */
4984                 name_len *= 2;
4985         } else {        /* BB improve the check for buffer overruns BB */
4986                 name_len = strnlen(fileName, PATH_MAX);
4987                 name_len++;     /* trailing null */
4988                 strncpy(pSMB->FileName, fileName, name_len);
4989         }
4990
4991         params = 6 + name_len;
4992         count = sizeof(FILE_UNIX_BASIC_INFO);
4993         pSMB->MaxParameterCount = cpu_to_le16(2);
4994         /* BB find max SMB PDU from sess structure BB */
4995         pSMB->MaxDataCount = cpu_to_le16(1000);
4996         pSMB->MaxSetupCount = 0;
4997         pSMB->Reserved = 0;
4998         pSMB->Flags = 0;
4999         pSMB->Timeout = 0;
5000         pSMB->Reserved2 = 0;
5001         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5002                                 InformationLevel) - 4;
5003         offset = param_offset + params;
5004         data_offset =
5005             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5006                                       offset);
5007         memset(data_offset, 0, count);
5008         pSMB->DataOffset = cpu_to_le16(offset);
5009         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5010         pSMB->SetupCount = 1;
5011         pSMB->Reserved3 = 0;
5012         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5013         byte_count = 3 /* pad */  + params + count;
5014         pSMB->ParameterCount = cpu_to_le16(params);
5015         pSMB->DataCount = cpu_to_le16(count);
5016         pSMB->TotalParameterCount = pSMB->ParameterCount;
5017         pSMB->TotalDataCount = pSMB->DataCount;
5018         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5019         pSMB->Reserved4 = 0;
5020         pSMB->hdr.smb_buf_length += byte_count;
5021         /* Samba server ignores set of file size to zero due to bugs in some
5022         older clients, but we should be precise - we use SetFileSize to
5023         set file size and do not want to truncate file size to zero
5024         accidently as happened on one Samba server beta by putting
5025         zero instead of -1 here */
5026         data_offset->EndOfFile = NO_CHANGE_64;
5027         data_offset->NumOfBytes = NO_CHANGE_64;
5028         data_offset->LastStatusChange = NO_CHANGE_64;
5029         data_offset->LastAccessTime = NO_CHANGE_64;
5030         data_offset->LastModificationTime = NO_CHANGE_64;
5031         data_offset->Uid = cpu_to_le64(uid);
5032         data_offset->Gid = cpu_to_le64(gid);
5033         /* better to leave device as zero when it is  */
5034         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5035         data_offset->DevMinor = cpu_to_le64(MINOR(device));
5036         data_offset->Permissions = cpu_to_le64(mode);
5037
5038         if (S_ISREG(mode))
5039                 data_offset->Type = cpu_to_le32(UNIX_FILE);
5040         else if (S_ISDIR(mode))
5041                 data_offset->Type = cpu_to_le32(UNIX_DIR);
5042         else if (S_ISLNK(mode))
5043                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5044         else if (S_ISCHR(mode))
5045                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5046         else if (S_ISBLK(mode))
5047                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5048         else if (S_ISFIFO(mode))
5049                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5050         else if (S_ISSOCK(mode))
5051                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5052
5053
5054         pSMB->ByteCount = cpu_to_le16(byte_count);
5055         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5056                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5057         if (rc)
5058                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5059
5060         if (pSMB)
5061                 cifs_buf_release(pSMB);
5062         if (rc == -EAGAIN)
5063                 goto setPermsRetry;
5064         return rc;
5065 }
5066
5067 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5068                   const int notify_subdirs, const __u16 netfid,
5069                   __u32 filter, struct file *pfile, int multishot,
5070                   const struct nls_table *nls_codepage)
5071 {
5072         int rc = 0;
5073         struct smb_com_transaction_change_notify_req *pSMB = NULL;
5074         struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5075         struct dir_notify_req *dnotify_req;
5076         int bytes_returned;
5077
5078         cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5079         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5080                       (void **) &pSMBr);
5081         if (rc)
5082                 return rc;
5083
5084         pSMB->TotalParameterCount = 0 ;
5085         pSMB->TotalDataCount = 0;
5086         pSMB->MaxParameterCount = cpu_to_le32(2);
5087         /* BB find exact data count max from sess structure BB */
5088         pSMB->MaxDataCount = 0; /* same in little endian or be */
5089 /* BB VERIFY verify which is correct for above BB */
5090         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5091                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5092
5093         pSMB->MaxSetupCount = 4;
5094         pSMB->Reserved = 0;
5095         pSMB->ParameterOffset = 0;
5096         pSMB->DataCount = 0;
5097         pSMB->DataOffset = 0;
5098         pSMB->SetupCount = 4; /* single byte does not need le conversion */
5099         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5100         pSMB->ParameterCount = pSMB->TotalParameterCount;
5101         if (notify_subdirs)
5102                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5103         pSMB->Reserved2 = 0;
5104         pSMB->CompletionFilter = cpu_to_le32(filter);
5105         pSMB->Fid = netfid; /* file handle always le */
5106         pSMB->ByteCount = 0;
5107
5108         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5109                          (struct smb_hdr *)pSMBr, &bytes_returned,
5110                          CIFS_ASYNC_OP);
5111         if (rc) {
5112                 cFYI(1, ("Error in Notify = %d", rc));
5113         } else {
5114                 /* Add file to outstanding requests */
5115                 /* BB change to kmem cache alloc */
5116                 dnotify_req = kmalloc(
5117                                                 sizeof(struct dir_notify_req),
5118                                                  GFP_KERNEL);
5119                 if (dnotify_req) {
5120                         dnotify_req->Pid = pSMB->hdr.Pid;
5121                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5122                         dnotify_req->Mid = pSMB->hdr.Mid;
5123                         dnotify_req->Tid = pSMB->hdr.Tid;
5124                         dnotify_req->Uid = pSMB->hdr.Uid;
5125                         dnotify_req->netfid = netfid;
5126                         dnotify_req->pfile = pfile;
5127                         dnotify_req->filter = filter;
5128                         dnotify_req->multishot = multishot;
5129                         spin_lock(&GlobalMid_Lock);
5130                         list_add_tail(&dnotify_req->lhead,
5131                                         &GlobalDnotifyReqList);
5132                         spin_unlock(&GlobalMid_Lock);
5133                 } else
5134                         rc = -ENOMEM;
5135         }
5136         cifs_buf_release(pSMB);
5137         return rc;
5138 }
5139 #ifdef CONFIG_CIFS_XATTR
5140 ssize_t
5141 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5142                  const unsigned char *searchName,
5143                  char *EAData, size_t buf_size,
5144                  const struct nls_table *nls_codepage, int remap)
5145 {
5146                 /* BB assumes one setup word */
5147         TRANSACTION2_QPI_REQ *pSMB = NULL;
5148         TRANSACTION2_QPI_RSP *pSMBr = NULL;
5149         int rc = 0;
5150         int bytes_returned;
5151         int name_len;
5152         struct fea *temp_fea;
5153         char *temp_ptr;
5154         __u16 params, byte_count;
5155
5156         cFYI(1, ("In Query All EAs path %s", searchName));
5157 QAllEAsRetry:
5158         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5159                       (void **) &pSMBr);
5160         if (rc)
5161                 return rc;
5162
5163         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5164                 name_len =
5165                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5166                                      PATH_MAX, nls_codepage, remap);
5167                 name_len++;     /* trailing null */
5168                 name_len *= 2;
5169         } else {        /* BB improve the check for buffer overruns BB */
5170                 name_len = strnlen(searchName, PATH_MAX);
5171                 name_len++;     /* trailing null */
5172                 strncpy(pSMB->FileName, searchName, name_len);
5173         }
5174
5175         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5176         pSMB->TotalDataCount = 0;
5177         pSMB->MaxParameterCount = cpu_to_le16(2);
5178         /* BB find exact max SMB PDU from sess structure BB */
5179         pSMB->MaxDataCount = cpu_to_le16(4000);
5180         pSMB->MaxSetupCount = 0;
5181         pSMB->Reserved = 0;
5182         pSMB->Flags = 0;
5183         pSMB->Timeout = 0;
5184         pSMB->Reserved2 = 0;
5185         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5186         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5187         pSMB->DataCount = 0;
5188         pSMB->DataOffset = 0;
5189         pSMB->SetupCount = 1;
5190         pSMB->Reserved3 = 0;
5191         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5192         byte_count = params + 1 /* pad */ ;
5193         pSMB->TotalParameterCount = cpu_to_le16(params);
5194         pSMB->ParameterCount = pSMB->TotalParameterCount;
5195         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5196         pSMB->Reserved4 = 0;
5197         pSMB->hdr.smb_buf_length += byte_count;
5198         pSMB->ByteCount = cpu_to_le16(byte_count);
5199
5200         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5201                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5202         if (rc) {
5203                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5204         } else {                /* decode response */
5205                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5206
5207                 /* BB also check enough total bytes returned */
5208                 /* BB we need to improve the validity checking
5209                 of these trans2 responses */
5210                 if (rc || (pSMBr->ByteCount < 4))
5211                         rc = -EIO;      /* bad smb */
5212            /* else if (pFindData){
5213                         memcpy((char *) pFindData,
5214                                (char *) &pSMBr->hdr.Protocol +
5215                                data_offset, kl);
5216                 }*/ else {
5217                         /* check that length of list is not more than bcc */
5218                         /* check that each entry does not go beyond length
5219                            of list */
5220                         /* check that each element of each entry does not
5221                            go beyond end of list */
5222                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5223                         struct fealist *ea_response_data;
5224                         rc = 0;
5225                         /* validate_trans2_offsets() */
5226                         /* BB check if start of smb + data_offset > &bcc+ bcc */
5227                         ea_response_data = (struct fealist *)
5228                                 (((char *) &pSMBr->hdr.Protocol) +
5229                                 data_offset);
5230                         name_len = le32_to_cpu(ea_response_data->list_len);
5231                         cFYI(1, ("ea length %d", name_len));
5232                         if (name_len <= 8) {
5233                         /* returned EA size zeroed at top of function */
5234                                 cFYI(1, ("empty EA list returned from server"));
5235                         } else {
5236                                 /* account for ea list len */
5237                                 name_len -= 4;
5238                                 temp_fea = ea_response_data->list;
5239                                 temp_ptr = (char *)temp_fea;
5240                                 while (name_len > 0) {
5241                                         __u16 value_len;
5242                                         name_len -= 4;
5243                                         temp_ptr += 4;
5244                                         rc += temp_fea->name_len;
5245                                 /* account for prefix user. and trailing null */
5246                                         rc = rc + 5 + 1;
5247                                         if (rc < (int)buf_size) {
5248                                                 memcpy(EAData, "user.", 5);
5249                                                 EAData += 5;
5250                                                 memcpy(EAData, temp_ptr,
5251                                                        temp_fea->name_len);
5252                                                 EAData += temp_fea->name_len;
5253                                                 /* null terminate name */
5254                                                 *EAData = 0;
5255                                                 EAData = EAData + 1;
5256                                         } else if (buf_size == 0) {
5257                                                 /* skip copy - calc size only */
5258                                         } else {
5259                                                 /* stop before overrun buffer */
5260                                                 rc = -ERANGE;
5261                                                 break;
5262                                         }
5263                                         name_len -= temp_fea->name_len;
5264                                         temp_ptr += temp_fea->name_len;
5265                                         /* account for trailing null */
5266                                         name_len--;
5267                                         temp_ptr++;
5268                                         value_len =
5269                                               le16_to_cpu(temp_fea->value_len);
5270                                         name_len -= value_len;
5271                                         temp_ptr += value_len;
5272                                         /* BB check that temp_ptr is still
5273                                               within the SMB BB*/
5274
5275                                         /* no trailing null to account for
5276                                            in value len */
5277                                         /* go on to next EA */
5278                                         temp_fea = (struct fea *)temp_ptr;
5279                                 }
5280                         }
5281                 }
5282         }
5283         if (pSMB)
5284                 cifs_buf_release(pSMB);
5285         if (rc == -EAGAIN)
5286                 goto QAllEAsRetry;
5287
5288         return (ssize_t)rc;
5289 }
5290
5291 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5292                 const unsigned char *searchName, const unsigned char *ea_name,
5293                 unsigned char *ea_value, size_t buf_size,
5294                 const struct nls_table *nls_codepage, int remap)
5295 {
5296         TRANSACTION2_QPI_REQ *pSMB = NULL;
5297         TRANSACTION2_QPI_RSP *pSMBr = NULL;
5298         int rc = 0;
5299         int bytes_returned;
5300         int name_len;
5301         struct fea *temp_fea;
5302         char *temp_ptr;
5303         __u16 params, byte_count;
5304
5305         cFYI(1, ("In Query EA path %s", searchName));
5306 QEARetry:
5307         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5308                       (void **) &pSMBr);
5309         if (rc)
5310                 return rc;
5311
5312         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5313                 name_len =
5314                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5315                                      PATH_MAX, nls_codepage, remap);
5316                 name_len++;     /* trailing null */
5317                 name_len *= 2;
5318         } else {        /* BB improve the check for buffer overruns BB */
5319                 name_len = strnlen(searchName, PATH_MAX);
5320                 name_len++;     /* trailing null */
5321                 strncpy(pSMB->FileName, searchName, name_len);
5322         }
5323
5324         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5325         pSMB->TotalDataCount = 0;
5326         pSMB->MaxParameterCount = cpu_to_le16(2);
5327         /* BB find exact max SMB PDU from sess structure BB */
5328         pSMB->MaxDataCount = cpu_to_le16(4000);
5329         pSMB->MaxSetupCount = 0;
5330         pSMB->Reserved = 0;
5331         pSMB->Flags = 0;
5332         pSMB->Timeout = 0;
5333         pSMB->Reserved2 = 0;
5334         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5335                 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5336         pSMB->DataCount = 0;
5337         pSMB->DataOffset = 0;
5338         pSMB->SetupCount = 1;
5339         pSMB->Reserved3 = 0;
5340         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5341         byte_count = params + 1 /* pad */ ;
5342         pSMB->TotalParameterCount = cpu_to_le16(params);
5343         pSMB->ParameterCount = pSMB->TotalParameterCount;
5344         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5345         pSMB->Reserved4 = 0;
5346         pSMB->hdr.smb_buf_length += byte_count;
5347         pSMB->ByteCount = cpu_to_le16(byte_count);
5348
5349         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5350                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5351         if (rc) {
5352                 cFYI(1, ("Send error in Query EA = %d", rc));
5353         } else {                /* decode response */
5354                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5355
5356                 /* BB also check enough total bytes returned */
5357                 /* BB we need to improve the validity checking
5358                 of these trans2 responses */
5359                 if (rc || (pSMBr->ByteCount < 4))
5360                         rc = -EIO;      /* bad smb */
5361            /* else if (pFindData){
5362                         memcpy((char *) pFindData,
5363                                (char *) &pSMBr->hdr.Protocol +
5364                                data_offset, kl);
5365                 }*/ else {
5366                         /* check that length of list is not more than bcc */
5367                         /* check that each entry does not go beyond length
5368                            of list */
5369                         /* check that each element of each entry does not
5370                            go beyond end of list */
5371                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5372                         struct fealist *ea_response_data;
5373                         rc = -ENODATA;
5374                         /* validate_trans2_offsets() */
5375                         /* BB check if start of smb + data_offset > &bcc+ bcc*/
5376                         ea_response_data = (struct fealist *)
5377                                 (((char *) &pSMBr->hdr.Protocol) +
5378                                 data_offset);
5379                         name_len = le32_to_cpu(ea_response_data->list_len);
5380                         cFYI(1, ("ea length %d", name_len));
5381                         if (name_len <= 8) {
5382                         /* returned EA size zeroed at top of function */
5383                                 cFYI(1, ("empty EA list returned from server"));
5384                         } else {
5385                                 /* account for ea list len */
5386                                 name_len -= 4;
5387                                 temp_fea = ea_response_data->list;
5388                                 temp_ptr = (char *)temp_fea;
5389                                 /* loop through checking if we have a matching
5390                                 name and then return the associated value */
5391                                 while (name_len > 0) {
5392                                         __u16 value_len;
5393                                         name_len -= 4;
5394                                         temp_ptr += 4;
5395                                         value_len =
5396                                               le16_to_cpu(temp_fea->value_len);
5397                                 /* BB validate that value_len falls within SMB,
5398                                 even though maximum for name_len is 255 */
5399                                         if (memcmp(temp_fea->name, ea_name,
5400                                                   temp_fea->name_len) == 0) {
5401                                                 /* found a match */
5402                                                 rc = value_len;
5403                                 /* account for prefix user. and trailing null */
5404                                                 if (rc <= (int)buf_size) {
5405                                                         memcpy(ea_value,
5406                                                                 temp_fea->name+temp_fea->name_len+1,
5407                                                                 rc);
5408                                                         /* ea values, unlike ea
5409                                                            names, are not null
5410                                                            terminated */
5411                                                 } else if (buf_size == 0) {
5412                                                 /* skip copy - calc size only */
5413                                                 } else {
5414                                                 /* stop before overrun buffer */
5415                                                         rc = -ERANGE;
5416                                                 }
5417                                                 break;
5418                                         }
5419                                         name_len -= temp_fea->name_len;
5420                                         temp_ptr += temp_fea->name_len;
5421                                         /* account for trailing null */
5422                                         name_len--;
5423                                         temp_ptr++;
5424                                         name_len -= value_len;
5425                                         temp_ptr += value_len;
5426                                         /* No trailing null to account for in
5427                                            value_len.  Go on to next EA */
5428                                         temp_fea = (struct fea *)temp_ptr;
5429                                 }
5430                         }
5431                 }
5432         }
5433         if (pSMB)
5434                 cifs_buf_release(pSMB);
5435         if (rc == -EAGAIN)
5436                 goto QEARetry;
5437
5438         return (ssize_t)rc;
5439 }
5440
5441 int
5442 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5443              const char *ea_name, const void *ea_value,
5444              const __u16 ea_value_len, const struct nls_table *nls_codepage,
5445              int remap)
5446 {
5447         struct smb_com_transaction2_spi_req *pSMB = NULL;
5448         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5449         struct fealist *parm_data;
5450         int name_len;
5451         int rc = 0;
5452         int bytes_returned = 0;
5453         __u16 params, param_offset, byte_count, offset, count;
5454
5455         cFYI(1, ("In SetEA"));
5456 SetEARetry:
5457         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5458                       (void **) &pSMBr);
5459         if (rc)
5460                 return rc;
5461
5462         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5463                 name_len =
5464                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5465                                      PATH_MAX, nls_codepage, remap);
5466                 name_len++;     /* trailing null */
5467                 name_len *= 2;
5468         } else {        /* BB improve the check for buffer overruns BB */
5469                 name_len = strnlen(fileName, PATH_MAX);
5470                 name_len++;     /* trailing null */
5471                 strncpy(pSMB->FileName, fileName, name_len);
5472         }
5473
5474         params = 6 + name_len;
5475
5476         /* done calculating parms using name_len of file name,
5477         now use name_len to calculate length of ea name
5478         we are going to create in the inode xattrs */
5479         if (ea_name == NULL)
5480                 name_len = 0;
5481         else
5482                 name_len = strnlen(ea_name, 255);
5483
5484         count = sizeof(*parm_data) + ea_value_len + name_len;
5485         pSMB->MaxParameterCount = cpu_to_le16(2);
5486         /* BB find max SMB PDU from sess */
5487         pSMB->MaxDataCount = cpu_to_le16(1000);
5488         pSMB->MaxSetupCount = 0;
5489         pSMB->Reserved = 0;
5490         pSMB->Flags = 0;
5491         pSMB->Timeout = 0;
5492         pSMB->Reserved2 = 0;
5493         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5494                                 InformationLevel) - 4;
5495         offset = param_offset + params;
5496         pSMB->InformationLevel =
5497                 cpu_to_le16(SMB_SET_FILE_EA);
5498
5499         parm_data =
5500                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5501                                        offset);
5502         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5503         pSMB->DataOffset = cpu_to_le16(offset);
5504         pSMB->SetupCount = 1;
5505         pSMB->Reserved3 = 0;
5506         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5507         byte_count = 3 /* pad */  + params + count;
5508         pSMB->DataCount = cpu_to_le16(count);
5509         parm_data->list_len = cpu_to_le32(count);
5510         parm_data->list[0].EA_flags = 0;
5511         /* we checked above that name len is less than 255 */
5512         parm_data->list[0].name_len = (__u8)name_len;
5513         /* EA names are always ASCII */
5514         if (ea_name)
5515                 strncpy(parm_data->list[0].name, ea_name, name_len);
5516         parm_data->list[0].name[name_len] = 0;
5517         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5518         /* caller ensures that ea_value_len is less than 64K but
5519         we need to ensure that it fits within the smb */
5520
5521         /*BB add length check to see if it would fit in
5522              negotiated SMB buffer size BB */
5523         /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5524         if (ea_value_len)
5525                 memcpy(parm_data->list[0].name+name_len+1,
5526                        ea_value, ea_value_len);
5527
5528         pSMB->TotalDataCount = pSMB->DataCount;
5529         pSMB->ParameterCount = cpu_to_le16(params);
5530         pSMB->TotalParameterCount = pSMB->ParameterCount;
5531         pSMB->Reserved4 = 0;
5532         pSMB->hdr.smb_buf_length += byte_count;
5533         pSMB->ByteCount = cpu_to_le16(byte_count);
5534         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5535                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5536         if (rc)
5537                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5538
5539         cifs_buf_release(pSMB);
5540
5541         if (rc == -EAGAIN)
5542                 goto SetEARetry;
5543
5544         return rc;
5545 }
5546
5547 #endif