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