fda8b2490263a8fd437974385fea980bf4dcddcd
[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 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3062 int
3063 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3064                 /* BB fix up return info */ char *acl_inf, const int buflen,
3065                   const int acl_type)
3066 {
3067         int rc = 0;
3068         int buf_type = 0;
3069         QUERY_SEC_DESC_REQ * pSMB;
3070         struct kvec iov[1];
3071
3072         cFYI(1, ("GetCifsACL"));
3073
3074         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3075                         8 /* parm len */, tcon, (void **) &pSMB);
3076         if (rc)
3077                 return rc;
3078
3079         pSMB->MaxParameterCount = cpu_to_le32(4);
3080         /* BB TEST with big acls that might need to be e.g. larger than 16K */
3081         pSMB->MaxSetupCount = 0;
3082         pSMB->Fid = fid; /* file handle always le */
3083         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3084                                      CIFS_ACL_DACL);
3085         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3086         pSMB->hdr.smb_buf_length += 11;
3087         iov[0].iov_base = (char *)pSMB;
3088         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3089
3090         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3091         cifs_stats_inc(&tcon->num_acl_get);
3092         if (rc) {
3093                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3094         } else {                /* decode response */
3095                 struct cifs_ntsd *psec_desc;
3096                 __le32 * parm;
3097                 int parm_len;
3098                 int data_len;
3099                 int acl_len;
3100                 struct smb_com_ntransact_rsp *pSMBr;
3101
3102 /* validate_nttransact */
3103                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3104                                         (char **)&psec_desc,
3105                                         &parm_len, &data_len);
3106                 if (rc)
3107                         goto qsec_out;
3108                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3109
3110                 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
3111
3112                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3113                         rc = -EIO;      /* bad smb */
3114                         goto qsec_out;
3115                 }
3116
3117 /* BB check that data area is minimum length and as big as acl_len */
3118
3119                 acl_len = le32_to_cpu(*(__le32 *)parm);
3120                 /* BB check if (acl_len > bufsize) */
3121
3122                 parse_sec_desc(psec_desc, acl_len);
3123         }
3124 qsec_out:
3125         if (buf_type == CIFS_SMALL_BUFFER)
3126                 cifs_small_buf_release(iov[0].iov_base);
3127         else if (buf_type == CIFS_LARGE_BUFFER)
3128                 cifs_buf_release(iov[0].iov_base);
3129 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3130         return rc;
3131 }
3132
3133 /* Legacy Query Path Information call for lookup to old servers such
3134    as Win9x/WinME */
3135 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3136                         const unsigned char *searchName,
3137                         FILE_ALL_INFO *pFinfo,
3138                         const struct nls_table *nls_codepage, int remap)
3139 {
3140         QUERY_INFORMATION_REQ * pSMB;
3141         QUERY_INFORMATION_RSP * pSMBr;
3142         int rc = 0;
3143         int bytes_returned;
3144         int name_len;
3145
3146         cFYI(1, ("In SMBQPath path %s", searchName));
3147 QInfRetry:
3148         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3149                       (void **) &pSMBr);
3150         if (rc)
3151                 return rc;
3152
3153         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3154                 name_len =
3155                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3156                                         PATH_MAX, nls_codepage, remap);
3157                 name_len++;     /* trailing null */
3158                 name_len *= 2;
3159         } else {
3160                 name_len = strnlen(searchName, PATH_MAX);
3161                 name_len++;     /* trailing null */
3162                 strncpy(pSMB->FileName, searchName, name_len);
3163         }
3164         pSMB->BufferFormat = 0x04;
3165         name_len++; /* account for buffer type byte */
3166         pSMB->hdr.smb_buf_length += (__u16) name_len;
3167         pSMB->ByteCount = cpu_to_le16(name_len);
3168
3169         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3170                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3171         if (rc) {
3172                 cFYI(1, ("Send error in QueryInfo = %d", rc));
3173         } else if (pFinfo) {            /* decode response */
3174                 struct timespec ts;
3175                 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3176                 /* BB FIXME - add time zone adjustment BB */
3177                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3178                 ts.tv_nsec = 0;
3179                 ts.tv_sec = time;
3180                 /* decode time fields */
3181                 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3182                 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3183                 pFinfo->LastAccessTime = 0;
3184                 pFinfo->AllocationSize =
3185                         cpu_to_le64(le32_to_cpu(pSMBr->size));
3186                 pFinfo->EndOfFile = pFinfo->AllocationSize;
3187                 pFinfo->Attributes =
3188                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
3189         } else
3190                 rc = -EIO; /* bad buffer passed in */
3191
3192         cifs_buf_release(pSMB);
3193
3194         if (rc == -EAGAIN)
3195                 goto QInfRetry;
3196
3197         return rc;
3198 }
3199
3200
3201
3202
3203 int
3204 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3205                  const unsigned char *searchName,
3206                  FILE_ALL_INFO * pFindData,
3207                  int legacy /* old style infolevel */,
3208                  const struct nls_table *nls_codepage, int remap)
3209 {
3210 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3211         TRANSACTION2_QPI_REQ *pSMB = NULL;
3212         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3213         int rc = 0;
3214         int bytes_returned;
3215         int name_len;
3216         __u16 params, byte_count;
3217
3218 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3219 QPathInfoRetry:
3220         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3221                       (void **) &pSMBr);
3222         if (rc)
3223                 return rc;
3224
3225         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3226                 name_len =
3227                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3228                                      PATH_MAX, nls_codepage, remap);
3229                 name_len++;     /* trailing null */
3230                 name_len *= 2;
3231         } else {        /* BB improve the check for buffer overruns BB */
3232                 name_len = strnlen(searchName, PATH_MAX);
3233                 name_len++;     /* trailing null */
3234                 strncpy(pSMB->FileName, searchName, name_len);
3235         }
3236
3237         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3238         pSMB->TotalDataCount = 0;
3239         pSMB->MaxParameterCount = cpu_to_le16(2);
3240         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3241         pSMB->MaxSetupCount = 0;
3242         pSMB->Reserved = 0;
3243         pSMB->Flags = 0;
3244         pSMB->Timeout = 0;
3245         pSMB->Reserved2 = 0;
3246         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3247         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3248         pSMB->DataCount = 0;
3249         pSMB->DataOffset = 0;
3250         pSMB->SetupCount = 1;
3251         pSMB->Reserved3 = 0;
3252         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3253         byte_count = params + 1 /* pad */ ;
3254         pSMB->TotalParameterCount = cpu_to_le16(params);
3255         pSMB->ParameterCount = pSMB->TotalParameterCount;
3256         if (legacy)
3257                 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3258         else
3259                 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3260         pSMB->Reserved4 = 0;
3261         pSMB->hdr.smb_buf_length += byte_count;
3262         pSMB->ByteCount = cpu_to_le16(byte_count);
3263
3264         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3265                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3266         if (rc) {
3267                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3268         } else {                /* decode response */
3269                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3270
3271                 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3272                         rc = -EIO;
3273                 else if (!legacy && (pSMBr->ByteCount < 40))
3274                         rc = -EIO;      /* bad smb */
3275                 else if (legacy && (pSMBr->ByteCount < 24))
3276                         rc = -EIO;  /* 24 or 26 expected but we do not read
3277                                         last field */
3278                 else if (pFindData) {
3279                         int size;
3280                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3281                         if (legacy) /* we do not read the last field, EAsize,
3282                                        fortunately since it varies by subdialect
3283                                        and on Set vs. Get, is two bytes or 4
3284                                        bytes depending but we don't care here */
3285                                 size = sizeof(FILE_INFO_STANDARD);
3286                         else
3287                                 size = sizeof(FILE_ALL_INFO);
3288                         memcpy((char *) pFindData,
3289                                (char *) &pSMBr->hdr.Protocol +
3290                                data_offset, size);
3291                 } else
3292                     rc = -ENOMEM;
3293         }
3294         cifs_buf_release(pSMB);
3295         if (rc == -EAGAIN)
3296                 goto QPathInfoRetry;
3297
3298         return rc;
3299 }
3300
3301 int
3302 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3303                      const unsigned char *searchName,
3304                      FILE_UNIX_BASIC_INFO * pFindData,
3305                      const struct nls_table *nls_codepage, int remap)
3306 {
3307 /* SMB_QUERY_FILE_UNIX_BASIC */
3308         TRANSACTION2_QPI_REQ *pSMB = NULL;
3309         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3310         int rc = 0;
3311         int bytes_returned = 0;
3312         int name_len;
3313         __u16 params, byte_count;
3314
3315         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3316 UnixQPathInfoRetry:
3317         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3318                       (void **) &pSMBr);
3319         if (rc)
3320                 return rc;
3321
3322         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3323                 name_len =
3324                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3325                                   PATH_MAX, nls_codepage, remap);
3326                 name_len++;     /* trailing null */
3327                 name_len *= 2;
3328         } else {        /* BB improve the check for buffer overruns BB */
3329                 name_len = strnlen(searchName, PATH_MAX);
3330                 name_len++;     /* trailing null */
3331                 strncpy(pSMB->FileName, searchName, name_len);
3332         }
3333
3334         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3335         pSMB->TotalDataCount = 0;
3336         pSMB->MaxParameterCount = cpu_to_le16(2);
3337         /* BB find exact max SMB PDU from sess structure BB */
3338         pSMB->MaxDataCount = cpu_to_le16(4000);
3339         pSMB->MaxSetupCount = 0;
3340         pSMB->Reserved = 0;
3341         pSMB->Flags = 0;
3342         pSMB->Timeout = 0;
3343         pSMB->Reserved2 = 0;
3344         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3345         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3346         pSMB->DataCount = 0;
3347         pSMB->DataOffset = 0;
3348         pSMB->SetupCount = 1;
3349         pSMB->Reserved3 = 0;
3350         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3351         byte_count = params + 1 /* pad */ ;
3352         pSMB->TotalParameterCount = cpu_to_le16(params);
3353         pSMB->ParameterCount = pSMB->TotalParameterCount;
3354         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3355         pSMB->Reserved4 = 0;
3356         pSMB->hdr.smb_buf_length += byte_count;
3357         pSMB->ByteCount = cpu_to_le16(byte_count);
3358
3359         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3360                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3361         if (rc) {
3362                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3363         } else {                /* decode response */
3364                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365
3366                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3367                         cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3368                                    "Unix Extensions can be disabled on mount "
3369                                    "by specifying the nosfu mount option."));
3370                         rc = -EIO;      /* bad smb */
3371                 } else {
3372                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3373                         memcpy((char *) pFindData,
3374                                (char *) &pSMBr->hdr.Protocol +
3375                                data_offset,
3376                                sizeof (FILE_UNIX_BASIC_INFO));
3377                 }
3378         }
3379         cifs_buf_release(pSMB);
3380         if (rc == -EAGAIN)
3381                 goto UnixQPathInfoRetry;
3382
3383         return rc;
3384 }
3385
3386 #if 0  /* function unused at present */
3387 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3388                const char *searchName, FILE_ALL_INFO * findData,
3389                const struct nls_table *nls_codepage)
3390 {
3391 /* level 257 SMB_ */
3392         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3393         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3394         int rc = 0;
3395         int bytes_returned;
3396         int name_len;
3397         __u16 params, byte_count;
3398
3399         cFYI(1, ("In FindUnique"));
3400 findUniqueRetry:
3401         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3402                       (void **) &pSMBr);
3403         if (rc)
3404                 return rc;
3405
3406         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3407                 name_len =
3408                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3409                                      PATH_MAX, nls_codepage);
3410                 name_len++;     /* trailing null */
3411                 name_len *= 2;
3412         } else {        /* BB improve the check for buffer overruns BB */
3413                 name_len = strnlen(searchName, PATH_MAX);
3414                 name_len++;     /* trailing null */
3415                 strncpy(pSMB->FileName, searchName, name_len);
3416         }
3417
3418         params = 12 + name_len /* includes null */ ;
3419         pSMB->TotalDataCount = 0;       /* no EAs */
3420         pSMB->MaxParameterCount = cpu_to_le16(2);
3421         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3422         pSMB->MaxSetupCount = 0;
3423         pSMB->Reserved = 0;
3424         pSMB->Flags = 0;
3425         pSMB->Timeout = 0;
3426         pSMB->Reserved2 = 0;
3427         pSMB->ParameterOffset = cpu_to_le16(
3428          offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
3429         pSMB->DataCount = 0;
3430         pSMB->DataOffset = 0;
3431         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
3432         pSMB->Reserved3 = 0;
3433         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3434         byte_count = params + 1 /* pad */ ;
3435         pSMB->TotalParameterCount = cpu_to_le16(params);
3436         pSMB->ParameterCount = pSMB->TotalParameterCount;
3437         pSMB->SearchAttributes =
3438             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3439                         ATTR_DIRECTORY);
3440         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
3441         pSMB->SearchFlags = cpu_to_le16(1);
3442         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3443         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
3444         pSMB->hdr.smb_buf_length += byte_count;
3445         pSMB->ByteCount = cpu_to_le16(byte_count);
3446
3447         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3448                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3449
3450         if (rc) {
3451                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3452         } else {                /* decode response */
3453                 cifs_stats_inc(&tcon->num_ffirst);
3454                 /* BB fill in */
3455         }
3456
3457         cifs_buf_release(pSMB);
3458         if (rc == -EAGAIN)
3459                 goto findUniqueRetry;
3460
3461         return rc;
3462 }
3463 #endif /* end unused (temporarily) function */
3464
3465 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3466 int
3467 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3468               const char *searchName,
3469               const struct nls_table *nls_codepage,
3470               __u16 *pnetfid,
3471               struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3472 {
3473 /* level 257 SMB_ */
3474         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3475         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3476         T2_FFIRST_RSP_PARMS * parms;
3477         int rc = 0;
3478         int bytes_returned = 0;
3479         int name_len;
3480         __u16 params, byte_count;
3481
3482         cFYI(1, ("In FindFirst for %s", searchName));
3483
3484 findFirstRetry:
3485         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3486                       (void **) &pSMBr);
3487         if (rc)
3488                 return rc;
3489
3490         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3491                 name_len =
3492                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3493                                  PATH_MAX, nls_codepage, remap);
3494                 /* We can not add the asterik earlier in case
3495                 it got remapped to 0xF03A as if it were part of the
3496                 directory name instead of a wildcard */
3497                 name_len *= 2;
3498                 pSMB->FileName[name_len] = dirsep;
3499                 pSMB->FileName[name_len+1] = 0;
3500                 pSMB->FileName[name_len+2] = '*';
3501                 pSMB->FileName[name_len+3] = 0;
3502                 name_len += 4; /* now the trailing null */
3503                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3504                 pSMB->FileName[name_len+1] = 0;
3505                 name_len += 2;
3506         } else {        /* BB add check for overrun of SMB buf BB */
3507                 name_len = strnlen(searchName, PATH_MAX);
3508 /* BB fix here and in unicode clause above ie
3509                 if (name_len > buffersize-header)
3510                         free buffer exit; BB */
3511                 strncpy(pSMB->FileName, searchName, name_len);
3512                 pSMB->FileName[name_len] = dirsep;
3513                 pSMB->FileName[name_len+1] = '*';
3514                 pSMB->FileName[name_len+2] = 0;
3515                 name_len += 3;
3516         }
3517
3518         params = 12 + name_len /* includes null */ ;
3519         pSMB->TotalDataCount = 0;       /* no EAs */
3520         pSMB->MaxParameterCount = cpu_to_le16(10);
3521         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3522                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3523         pSMB->MaxSetupCount = 0;
3524         pSMB->Reserved = 0;
3525         pSMB->Flags = 0;
3526         pSMB->Timeout = 0;
3527         pSMB->Reserved2 = 0;
3528         byte_count = params + 1 /* pad */ ;
3529         pSMB->TotalParameterCount = cpu_to_le16(params);
3530         pSMB->ParameterCount = pSMB->TotalParameterCount;
3531         pSMB->ParameterOffset = cpu_to_le16(
3532               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3533                 - 4);
3534         pSMB->DataCount = 0;
3535         pSMB->DataOffset = 0;
3536         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3537         pSMB->Reserved3 = 0;
3538         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3539         pSMB->SearchAttributes =
3540             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3541                         ATTR_DIRECTORY);
3542         pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3543         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3544                 CIFS_SEARCH_RETURN_RESUME);
3545         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3546
3547         /* BB what should we set StorageType to? Does it matter? BB */
3548         pSMB->SearchStorageType = 0;
3549         pSMB->hdr.smb_buf_length += byte_count;
3550         pSMB->ByteCount = cpu_to_le16(byte_count);
3551
3552         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3553                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3554         cifs_stats_inc(&tcon->num_ffirst);
3555
3556         if (rc) {/* BB add logic to retry regular search if Unix search
3557                         rejected unexpectedly by server */
3558                 /* BB Add code to handle unsupported level rc */
3559                 cFYI(1, ("Error in FindFirst = %d", rc));
3560
3561                 cifs_buf_release(pSMB);
3562
3563                 /* BB eventually could optimize out free and realloc of buf */
3564                 /*    for this case */
3565                 if (rc == -EAGAIN)
3566                         goto findFirstRetry;
3567         } else { /* decode response */
3568                 /* BB remember to free buffer if error BB */
3569                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3570                 if (rc == 0) {
3571                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3572                                 psrch_inf->unicode = TRUE;
3573                         else
3574                                 psrch_inf->unicode = FALSE;
3575
3576                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3577                         psrch_inf->smallBuf = 0;
3578                         psrch_inf->srch_entries_start =
3579                                 (char *) &pSMBr->hdr.Protocol +
3580                                         le16_to_cpu(pSMBr->t2.DataOffset);
3581                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3582                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3583
3584                         if (parms->EndofSearch)
3585                                 psrch_inf->endOfSearch = TRUE;
3586                         else
3587                                 psrch_inf->endOfSearch = FALSE;
3588
3589                         psrch_inf->entries_in_buffer =
3590                                         le16_to_cpu(parms->SearchCount);
3591                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3592                                 psrch_inf->entries_in_buffer;
3593                         *pnetfid = parms->SearchHandle;
3594                 } else {
3595                         cifs_buf_release(pSMB);
3596                 }
3597         }
3598
3599         return rc;
3600 }
3601
3602 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3603                  __u16 searchHandle, struct cifs_search_info *psrch_inf)
3604 {
3605         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3606         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3607         T2_FNEXT_RSP_PARMS * parms;
3608         char *response_data;
3609         int rc = 0;
3610         int bytes_returned, name_len;
3611         __u16 params, byte_count;
3612
3613         cFYI(1, ("In FindNext"));
3614
3615         if (psrch_inf->endOfSearch == TRUE)
3616                 return -ENOENT;
3617
3618         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3619                 (void **) &pSMBr);
3620         if (rc)
3621                 return rc;
3622
3623         params = 14; /* includes 2 bytes of null string, converted to LE below*/
3624         byte_count = 0;
3625         pSMB->TotalDataCount = 0;       /* no EAs */
3626         pSMB->MaxParameterCount = cpu_to_le16(8);
3627         pSMB->MaxDataCount =
3628                 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3629                                 0xFFFFFF00);
3630         pSMB->MaxSetupCount = 0;
3631         pSMB->Reserved = 0;
3632         pSMB->Flags = 0;
3633         pSMB->Timeout = 0;
3634         pSMB->Reserved2 = 0;
3635         pSMB->ParameterOffset =  cpu_to_le16(
3636               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3637         pSMB->DataCount = 0;
3638         pSMB->DataOffset = 0;
3639         pSMB->SetupCount = 1;
3640         pSMB->Reserved3 = 0;
3641         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3642         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3643         pSMB->SearchCount =
3644                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3645         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3646         pSMB->ResumeKey = psrch_inf->resume_key;
3647         pSMB->SearchFlags =
3648               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3649
3650         name_len = psrch_inf->resume_name_len;
3651         params += name_len;
3652         if (name_len < PATH_MAX) {
3653                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3654                 byte_count += name_len;
3655                 /* 14 byte parm len above enough for 2 byte null terminator */
3656                 pSMB->ResumeFileName[name_len] = 0;
3657                 pSMB->ResumeFileName[name_len+1] = 0;
3658         } else {
3659                 rc = -EINVAL;
3660                 goto FNext2_err_exit;
3661         }
3662         byte_count = params + 1 /* pad */ ;
3663         pSMB->TotalParameterCount = cpu_to_le16(params);
3664         pSMB->ParameterCount = pSMB->TotalParameterCount;
3665         pSMB->hdr.smb_buf_length += byte_count;
3666         pSMB->ByteCount = cpu_to_le16(byte_count);
3667
3668         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3669                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3670         cifs_stats_inc(&tcon->num_fnext);
3671         if (rc) {
3672                 if (rc == -EBADF) {
3673                         psrch_inf->endOfSearch = TRUE;
3674                         rc = 0; /* search probably was closed at end of search*/
3675                 } else
3676                         cFYI(1, ("FindNext returned = %d", rc));
3677         } else {                /* decode response */
3678                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3679
3680                 if (rc == 0) {
3681                         /* BB fixme add lock for file (srch_info) struct here */
3682                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3683                                 psrch_inf->unicode = TRUE;
3684                         else
3685                                 psrch_inf->unicode = FALSE;
3686                         response_data = (char *) &pSMBr->hdr.Protocol +
3687                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3688                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3689                         response_data = (char *)&pSMBr->hdr.Protocol +
3690                                 le16_to_cpu(pSMBr->t2.DataOffset);
3691                         if (psrch_inf->smallBuf)
3692                                 cifs_small_buf_release(
3693                                         psrch_inf->ntwrk_buf_start);
3694                         else
3695                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3696                         psrch_inf->srch_entries_start = response_data;
3697                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3698                         psrch_inf->smallBuf = 0;
3699                         if (parms->EndofSearch)
3700                                 psrch_inf->endOfSearch = TRUE;
3701                         else
3702                                 psrch_inf->endOfSearch = FALSE;
3703                         psrch_inf->entries_in_buffer =
3704                                                 le16_to_cpu(parms->SearchCount);
3705                         psrch_inf->index_of_last_entry +=
3706                                 psrch_inf->entries_in_buffer;
3707 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3708             psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3709
3710                         /* BB fixme add unlock here */
3711                 }
3712
3713         }
3714
3715         /* BB On error, should we leave previous search buf (and count and
3716         last entry fields) intact or free the previous one? */
3717
3718         /* Note: On -EAGAIN error only caller can retry on handle based calls
3719         since file handle passed in no longer valid */
3720 FNext2_err_exit:
3721         if (rc != 0)
3722                 cifs_buf_release(pSMB);
3723         return rc;
3724 }
3725
3726 int
3727 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3728               const __u16 searchHandle)
3729 {
3730         int rc = 0;
3731         FINDCLOSE_REQ *pSMB = NULL;
3732         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3733         int bytes_returned;
3734
3735         cFYI(1, ("In CIFSSMBFindClose"));
3736         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3737
3738         /* no sense returning error if session restarted
3739                 as file handle has been closed */
3740         if (rc == -EAGAIN)
3741                 return 0;
3742         if (rc)
3743                 return rc;
3744
3745         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3746         pSMB->FileID = searchHandle;
3747         pSMB->ByteCount = 0;
3748         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3749                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3750         if (rc) {
3751                 cERROR(1, ("Send error in FindClose = %d", rc));
3752         }
3753         cifs_stats_inc(&tcon->num_fclose);
3754         cifs_small_buf_release(pSMB);
3755
3756         /* Since session is dead, search handle closed on server already */
3757         if (rc == -EAGAIN)
3758                 rc = 0;
3759
3760         return rc;
3761 }
3762
3763 int
3764 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3765                       const unsigned char *searchName,
3766                       __u64 * inode_number,
3767                       const struct nls_table *nls_codepage, int remap)
3768 {
3769         int rc = 0;
3770         TRANSACTION2_QPI_REQ *pSMB = NULL;
3771         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3772         int name_len, bytes_returned;
3773         __u16 params, byte_count;
3774
3775         cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3776         if (tcon == NULL)
3777                 return -ENODEV;
3778
3779 GetInodeNumberRetry:
3780         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3781                       (void **) &pSMBr);
3782         if (rc)
3783                 return rc;
3784
3785         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3786                 name_len =
3787                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3788                                          PATH_MAX, nls_codepage, remap);
3789                 name_len++;     /* trailing null */
3790                 name_len *= 2;
3791         } else {        /* BB improve the check for buffer overruns BB */
3792                 name_len = strnlen(searchName, PATH_MAX);
3793                 name_len++;     /* trailing null */
3794                 strncpy(pSMB->FileName, searchName, name_len);
3795         }
3796
3797         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3798         pSMB->TotalDataCount = 0;
3799         pSMB->MaxParameterCount = cpu_to_le16(2);
3800         /* BB find exact max data count below from sess structure BB */
3801         pSMB->MaxDataCount = cpu_to_le16(4000);
3802         pSMB->MaxSetupCount = 0;
3803         pSMB->Reserved = 0;
3804         pSMB->Flags = 0;
3805         pSMB->Timeout = 0;
3806         pSMB->Reserved2 = 0;
3807         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3808                 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3809         pSMB->DataCount = 0;
3810         pSMB->DataOffset = 0;
3811         pSMB->SetupCount = 1;
3812         pSMB->Reserved3 = 0;
3813         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3814         byte_count = params + 1 /* pad */ ;
3815         pSMB->TotalParameterCount = cpu_to_le16(params);
3816         pSMB->ParameterCount = pSMB->TotalParameterCount;
3817         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3818         pSMB->Reserved4 = 0;
3819         pSMB->hdr.smb_buf_length += byte_count;
3820         pSMB->ByteCount = cpu_to_le16(byte_count);
3821
3822         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3823                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3824         if (rc) {
3825                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3826         } else {
3827                 /* decode response */
3828                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3829                 if (rc || (pSMBr->ByteCount < 2))
3830                 /* BB also check enough total bytes returned */
3831                         /* If rc should we check for EOPNOSUPP and
3832                         disable the srvino flag? or in caller? */
3833                         rc = -EIO;      /* bad smb */
3834                 else {
3835                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3836                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3837                         struct file_internal_info *pfinfo;
3838                         /* BB Do we need a cast or hash here ? */
3839                         if (count < 8) {
3840                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3841                                 rc = -EIO;
3842                                 goto GetInodeNumOut;
3843                         }
3844                         pfinfo = (struct file_internal_info *)
3845                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3846                         *inode_number = pfinfo->UniqueId;
3847                 }
3848         }
3849 GetInodeNumOut:
3850         cifs_buf_release(pSMB);
3851         if (rc == -EAGAIN)
3852                 goto GetInodeNumberRetry;
3853         return rc;
3854 }
3855
3856 int
3857 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3858                 const unsigned char *searchName,
3859                 unsigned char **targetUNCs,
3860                 unsigned int *number_of_UNC_in_array,
3861                 const struct nls_table *nls_codepage, int remap)
3862 {
3863 /* TRANS2_GET_DFS_REFERRAL */
3864         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3865         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3866         struct dfs_referral_level_3 *referrals = NULL;
3867         int rc = 0;
3868         int bytes_returned;
3869         int name_len;
3870         unsigned int i;
3871         char *temp;
3872         __u16 params, byte_count;
3873         *number_of_UNC_in_array = 0;
3874         *targetUNCs = NULL;
3875
3876         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3877         if (ses == NULL)
3878                 return -ENODEV;
3879 getDFSRetry:
3880         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3881                       (void **) &pSMBr);
3882         if (rc)
3883                 return rc;
3884
3885         /* server pointer checked in called function,
3886         but should never be null here anyway */
3887         pSMB->hdr.Mid = GetNextMid(ses->server);
3888         pSMB->hdr.Tid = ses->ipc_tid;
3889         pSMB->hdr.Uid = ses->Suid;
3890         if (ses->capabilities & CAP_STATUS32)
3891                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3892         if (ses->capabilities & CAP_DFS)
3893                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3894
3895         if (ses->capabilities & CAP_UNICODE) {
3896                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3897                 name_len =
3898                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3899                                      searchName, PATH_MAX, nls_codepage, remap);
3900                 name_len++;     /* trailing null */
3901                 name_len *= 2;
3902         } else {        /* BB improve the check for buffer overruns BB */
3903                 name_len = strnlen(searchName, PATH_MAX);
3904                 name_len++;     /* trailing null */
3905                 strncpy(pSMB->RequestFileName, searchName, name_len);
3906         }
3907
3908         if (ses->server) {
3909                 if (ses->server->secMode &
3910                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3911                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3912         }
3913
3914         pSMB->hdr.Uid = ses->Suid;
3915
3916         params = 2 /* level */  + name_len /*includes null */ ;
3917         pSMB->TotalDataCount = 0;
3918         pSMB->DataCount = 0;
3919         pSMB->DataOffset = 0;
3920         pSMB->MaxParameterCount = 0;
3921         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3922         pSMB->MaxSetupCount = 0;
3923         pSMB->Reserved = 0;
3924         pSMB->Flags = 0;
3925         pSMB->Timeout = 0;
3926         pSMB->Reserved2 = 0;
3927         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3928           struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3929         pSMB->SetupCount = 1;
3930         pSMB->Reserved3 = 0;
3931         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3932         byte_count = params + 3 /* pad */ ;
3933         pSMB->ParameterCount = cpu_to_le16(params);
3934         pSMB->TotalParameterCount = pSMB->ParameterCount;
3935         pSMB->MaxReferralLevel = cpu_to_le16(3);
3936         pSMB->hdr.smb_buf_length += byte_count;
3937         pSMB->ByteCount = cpu_to_le16(byte_count);
3938
3939         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3940                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3941         if (rc) {
3942                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3943         } else {                /* decode response */
3944 /* BB Add logic to parse referrals here */
3945                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3946
3947                 /* BB Also check if enough total bytes returned? */
3948                 if (rc || (pSMBr->ByteCount < 17))
3949                         rc = -EIO;      /* bad smb */
3950                 else {
3951                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3952                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3953
3954                         cFYI(1,
3955                             ("Decoding GetDFSRefer response BCC: %d  Offset %d",
3956                               pSMBr->ByteCount, data_offset));
3957                         referrals =
3958                             (struct dfs_referral_level_3 *)
3959                                         (8 /* sizeof start of data block */ +
3960                                         data_offset +
3961                                         (char *) &pSMBr->hdr.Protocol);
3962                         cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3963                                 "for referral one refer size: 0x%x srv "
3964                                 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3965                                 le16_to_cpu(pSMBr->NumberOfReferrals),
3966                                 le16_to_cpu(pSMBr->DFSFlags),
3967                                 le16_to_cpu(referrals->ReferralSize),
3968                                 le16_to_cpu(referrals->ServerType),
3969                                 le16_to_cpu(referrals->ReferralFlags),
3970                                 le16_to_cpu(referrals->TimeToLive)));
3971                         /* BB This field is actually two bytes in from start of
3972                            data block so we could do safety check that DataBlock
3973                            begins at address of pSMBr->NumberOfReferrals */
3974                         *number_of_UNC_in_array =
3975                                         le16_to_cpu(pSMBr->NumberOfReferrals);
3976
3977                         /* BB Fix below so can return more than one referral */
3978                         if (*number_of_UNC_in_array > 1)
3979                                 *number_of_UNC_in_array = 1;
3980
3981                         /* get the length of the strings describing refs */
3982                         name_len = 0;
3983                         for (i = 0; i < *number_of_UNC_in_array; i++) {
3984                                 /* make sure that DfsPathOffset not past end */
3985                                 __u16 offset =
3986                                         le16_to_cpu(referrals->DfsPathOffset);
3987                                 if (offset > data_count) {
3988                                         /* if invalid referral, stop here and do
3989                                         not try to copy any more */
3990                                         *number_of_UNC_in_array = i;
3991                                         break;
3992                                 }
3993                                 temp = ((char *)referrals) + offset;
3994
3995                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3996                                         name_len += UniStrnlen((wchar_t *)temp,
3997                                                                 data_count);
3998                                 } else {
3999                                         name_len += strnlen(temp, data_count);
4000                                 }
4001                                 referrals++;
4002                                 /* BB add check that referral pointer does
4003                                    not fall off end PDU */
4004                         }
4005                         /* BB add check for name_len bigger than bcc */
4006                         *targetUNCs =
4007                                 kmalloc(name_len+1+(*number_of_UNC_in_array),
4008                                         GFP_KERNEL);
4009                         if (*targetUNCs == NULL) {
4010                                 rc = -ENOMEM;
4011                                 goto GetDFSRefExit;
4012                         }
4013                         /* copy the ref strings */
4014                         referrals = (struct dfs_referral_level_3 *)
4015                                         (8 /* sizeof data hdr */ + data_offset +
4016                                         (char *) &pSMBr->hdr.Protocol);
4017
4018                         for (i = 0; i < *number_of_UNC_in_array; i++) {
4019                                 temp = ((char *)referrals) +
4020                                           le16_to_cpu(referrals->DfsPathOffset);
4021                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4022                                         cifs_strfromUCS_le(*targetUNCs,
4023                                                           (__le16 *) temp,
4024                                                           name_len,
4025                                                           nls_codepage);
4026                                 } else {
4027                                         strncpy(*targetUNCs, temp, name_len);
4028                                 }
4029                                 /*  BB update target_uncs pointers */
4030                                 referrals++;
4031                         }
4032                         temp = *targetUNCs;
4033                         temp[name_len] = 0;
4034                 }
4035
4036         }
4037 GetDFSRefExit:
4038         if (pSMB)
4039                 cifs_buf_release(pSMB);
4040
4041         if (rc == -EAGAIN)
4042                 goto getDFSRetry;
4043
4044         return rc;
4045 }
4046
4047 /* Query File System Info such as free space to old servers such as Win 9x */
4048 int
4049 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4050 {
4051 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4052         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4053         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4054         FILE_SYSTEM_ALLOC_INFO *response_data;
4055         int rc = 0;
4056         int bytes_returned = 0;
4057         __u16 params, byte_count;
4058
4059         cFYI(1, ("OldQFSInfo"));
4060 oldQFSInfoRetry:
4061         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062                 (void **) &pSMBr);
4063         if (rc)
4064                 return rc;
4065
4066         params = 2;     /* level */
4067         pSMB->TotalDataCount = 0;
4068         pSMB->MaxParameterCount = cpu_to_le16(2);
4069         pSMB->MaxDataCount = cpu_to_le16(1000);
4070         pSMB->MaxSetupCount = 0;
4071         pSMB->Reserved = 0;
4072         pSMB->Flags = 0;
4073         pSMB->Timeout = 0;
4074         pSMB->Reserved2 = 0;
4075         byte_count = params + 1 /* pad */ ;
4076         pSMB->TotalParameterCount = cpu_to_le16(params);
4077         pSMB->ParameterCount = pSMB->TotalParameterCount;
4078         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4079         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4080         pSMB->DataCount = 0;
4081         pSMB->DataOffset = 0;
4082         pSMB->SetupCount = 1;
4083         pSMB->Reserved3 = 0;
4084         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4085         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4086         pSMB->hdr.smb_buf_length += byte_count;
4087         pSMB->ByteCount = cpu_to_le16(byte_count);
4088
4089         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091         if (rc) {
4092                 cFYI(1, ("Send error in QFSInfo = %d", rc));
4093         } else {                /* decode response */
4094                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4095
4096                 if (rc || (pSMBr->ByteCount < 18))
4097                         rc = -EIO;      /* bad smb */
4098                 else {
4099                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4100                         cFYI(1, ("qfsinf resp BCC: %d  Offset %d",
4101                                  pSMBr->ByteCount, data_offset));
4102
4103                         response_data = (FILE_SYSTEM_ALLOC_INFO *)
4104                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4105                         FSData->f_bsize =
4106                                 le16_to_cpu(response_data->BytesPerSector) *
4107                                 le32_to_cpu(response_data->
4108                                         SectorsPerAllocationUnit);
4109                         FSData->f_blocks =
4110                                le32_to_cpu(response_data->TotalAllocationUnits);
4111                         FSData->f_bfree = FSData->f_bavail =
4112                                 le32_to_cpu(response_data->FreeAllocationUnits);
4113                         cFYI(1,
4114                              ("Blocks: %lld  Free: %lld Block size %ld",
4115                               (unsigned long long)FSData->f_blocks,
4116                               (unsigned long long)FSData->f_bfree,
4117                               FSData->f_bsize));
4118                 }
4119         }
4120         cifs_buf_release(pSMB);
4121
4122         if (rc == -EAGAIN)
4123                 goto oldQFSInfoRetry;
4124
4125         return rc;
4126 }
4127
4128 int
4129 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4130 {
4131 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4132         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4133         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4134         FILE_SYSTEM_INFO *response_data;
4135         int rc = 0;
4136         int bytes_returned = 0;
4137         __u16 params, byte_count;
4138
4139         cFYI(1, ("In QFSInfo"));
4140 QFSInfoRetry:
4141         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4142                       (void **) &pSMBr);
4143         if (rc)
4144                 return rc;
4145
4146         params = 2;     /* level */
4147         pSMB->TotalDataCount = 0;
4148         pSMB->MaxParameterCount = cpu_to_le16(2);
4149         pSMB->MaxDataCount = cpu_to_le16(1000);
4150         pSMB->MaxSetupCount = 0;
4151         pSMB->Reserved = 0;
4152         pSMB->Flags = 0;
4153         pSMB->Timeout = 0;
4154         pSMB->Reserved2 = 0;
4155         byte_count = params + 1 /* pad */ ;
4156         pSMB->TotalParameterCount = cpu_to_le16(params);
4157         pSMB->ParameterCount = pSMB->TotalParameterCount;
4158         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4159                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4160         pSMB->DataCount = 0;
4161         pSMB->DataOffset = 0;
4162         pSMB->SetupCount = 1;
4163         pSMB->Reserved3 = 0;
4164         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4165         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4166         pSMB->hdr.smb_buf_length += byte_count;
4167         pSMB->ByteCount = cpu_to_le16(byte_count);
4168
4169         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171         if (rc) {
4172                 cFYI(1, ("Send error in QFSInfo = %d", rc));
4173         } else {                /* decode response */
4174                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4175
4176                 if (rc || (pSMBr->ByteCount < 24))
4177                         rc = -EIO;      /* bad smb */
4178                 else {
4179                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4180
4181                         response_data =
4182                             (FILE_SYSTEM_INFO
4183                              *) (((char *) &pSMBr->hdr.Protocol) +
4184                                  data_offset);
4185                         FSData->f_bsize =
4186                             le32_to_cpu(response_data->BytesPerSector) *
4187                             le32_to_cpu(response_data->
4188                                         SectorsPerAllocationUnit);
4189                         FSData->f_blocks =
4190                             le64_to_cpu(response_data->TotalAllocationUnits);
4191                         FSData->f_bfree = FSData->f_bavail =
4192                             le64_to_cpu(response_data->FreeAllocationUnits);
4193                         cFYI(1,
4194                              ("Blocks: %lld  Free: %lld Block size %ld",
4195                               (unsigned long long)FSData->f_blocks,
4196                               (unsigned long long)FSData->f_bfree,
4197                               FSData->f_bsize));
4198                 }
4199         }
4200         cifs_buf_release(pSMB);
4201
4202         if (rc == -EAGAIN)
4203                 goto QFSInfoRetry;
4204
4205         return rc;
4206 }
4207
4208 int
4209 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4210 {
4211 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
4212         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4215         int rc = 0;
4216         int bytes_returned = 0;
4217         __u16 params, byte_count;
4218
4219         cFYI(1, ("In QFSAttributeInfo"));
4220 QFSAttributeRetry:
4221         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4222                       (void **) &pSMBr);
4223         if (rc)
4224                 return rc;
4225
4226         params = 2;     /* level */
4227         pSMB->TotalDataCount = 0;
4228         pSMB->MaxParameterCount = cpu_to_le16(2);
4229         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4230         pSMB->MaxSetupCount = 0;
4231         pSMB->Reserved = 0;
4232         pSMB->Flags = 0;
4233         pSMB->Timeout = 0;
4234         pSMB->Reserved2 = 0;
4235         byte_count = params + 1 /* pad */ ;
4236         pSMB->TotalParameterCount = cpu_to_le16(params);
4237         pSMB->ParameterCount = pSMB->TotalParameterCount;
4238         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4239                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4240         pSMB->DataCount = 0;
4241         pSMB->DataOffset = 0;
4242         pSMB->SetupCount = 1;
4243         pSMB->Reserved3 = 0;
4244         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4245         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4246         pSMB->hdr.smb_buf_length += byte_count;
4247         pSMB->ByteCount = cpu_to_le16(byte_count);
4248
4249         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4250                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4251         if (rc) {
4252                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4253         } else {                /* decode response */
4254                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4255
4256                 if (rc || (pSMBr->ByteCount < 13)) {
4257                         /* BB also check if enough bytes returned */
4258                         rc = -EIO;      /* bad smb */
4259                 } else {
4260                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4261                         response_data =
4262                             (FILE_SYSTEM_ATTRIBUTE_INFO
4263                              *) (((char *) &pSMBr->hdr.Protocol) +
4264                                  data_offset);
4265                         memcpy(&tcon->fsAttrInfo, response_data,
4266                                sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4267                 }
4268         }
4269         cifs_buf_release(pSMB);
4270
4271         if (rc == -EAGAIN)
4272                 goto QFSAttributeRetry;
4273
4274         return rc;
4275 }
4276
4277 int
4278 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4279 {
4280 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4281         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4282         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4283         FILE_SYSTEM_DEVICE_INFO *response_data;
4284         int rc = 0;
4285         int bytes_returned = 0;
4286         __u16 params, byte_count;
4287
4288         cFYI(1, ("In QFSDeviceInfo"));
4289 QFSDeviceRetry:
4290         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4291                       (void **) &pSMBr);
4292         if (rc)
4293                 return rc;
4294
4295         params = 2;     /* level */
4296         pSMB->TotalDataCount = 0;
4297         pSMB->MaxParameterCount = cpu_to_le16(2);
4298         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4299         pSMB->MaxSetupCount = 0;
4300         pSMB->Reserved = 0;
4301         pSMB->Flags = 0;
4302         pSMB->Timeout = 0;
4303         pSMB->Reserved2 = 0;
4304         byte_count = params + 1 /* pad */ ;
4305         pSMB->TotalParameterCount = cpu_to_le16(params);
4306         pSMB->ParameterCount = pSMB->TotalParameterCount;
4307         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4308                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4309
4310         pSMB->DataCount = 0;
4311         pSMB->DataOffset = 0;
4312         pSMB->SetupCount = 1;
4313         pSMB->Reserved3 = 0;
4314         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4315         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4316         pSMB->hdr.smb_buf_length += byte_count;
4317         pSMB->ByteCount = cpu_to_le16(byte_count);
4318
4319         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4320                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4321         if (rc) {
4322                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4323         } else {                /* decode response */
4324                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4325
4326                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4327                         rc = -EIO;      /* bad smb */
4328                 else {
4329                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4330                         response_data =
4331                             (FILE_SYSTEM_DEVICE_INFO *)
4332                                 (((char *) &pSMBr->hdr.Protocol) +
4333                                  data_offset);
4334                         memcpy(&tcon->fsDevInfo, response_data,
4335                                sizeof(FILE_SYSTEM_DEVICE_INFO));
4336                 }
4337         }
4338         cifs_buf_release(pSMB);
4339
4340         if (rc == -EAGAIN)
4341                 goto QFSDeviceRetry;
4342
4343         return rc;
4344 }
4345
4346 int
4347 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4348 {
4349 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
4350         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4351         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4352         FILE_SYSTEM_UNIX_INFO *response_data;
4353         int rc = 0;
4354         int bytes_returned = 0;
4355         __u16 params, byte_count;
4356
4357         cFYI(1, ("In QFSUnixInfo"));
4358 QFSUnixRetry:
4359         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360                       (void **) &pSMBr);
4361         if (rc)
4362                 return rc;
4363
4364         params = 2;     /* level */
4365         pSMB->TotalDataCount = 0;
4366         pSMB->DataCount = 0;
4367         pSMB->DataOffset = 0;
4368         pSMB->MaxParameterCount = cpu_to_le16(2);
4369         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4370         pSMB->MaxSetupCount = 0;
4371         pSMB->Reserved = 0;
4372         pSMB->Flags = 0;
4373         pSMB->Timeout = 0;
4374         pSMB->Reserved2 = 0;
4375         byte_count = params + 1 /* pad */ ;
4376         pSMB->ParameterCount = cpu_to_le16(params);
4377         pSMB->TotalParameterCount = pSMB->ParameterCount;
4378         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4379                         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4380         pSMB->SetupCount = 1;
4381         pSMB->Reserved3 = 0;
4382         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4383         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4384         pSMB->hdr.smb_buf_length += byte_count;
4385         pSMB->ByteCount = cpu_to_le16(byte_count);
4386
4387         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4388                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4389         if (rc) {
4390                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4391         } else {                /* decode response */
4392                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4393
4394                 if (rc || (pSMBr->ByteCount < 13)) {
4395                         rc = -EIO;      /* bad smb */
4396                 } else {
4397                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4398                         response_data =
4399                             (FILE_SYSTEM_UNIX_INFO
4400                              *) (((char *) &pSMBr->hdr.Protocol) +
4401                                  data_offset);
4402                         memcpy(&tcon->fsUnixInfo, response_data,
4403                                sizeof(FILE_SYSTEM_UNIX_INFO));
4404                 }
4405         }
4406         cifs_buf_release(pSMB);
4407
4408         if (rc == -EAGAIN)
4409                 goto QFSUnixRetry;
4410
4411
4412         return rc;
4413 }
4414
4415 int
4416 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4417 {
4418 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
4419         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4420         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4421         int rc = 0;
4422         int bytes_returned = 0;
4423         __u16 params, param_offset, offset, byte_count;
4424
4425         cFYI(1, ("In SETFSUnixInfo"));
4426 SETFSUnixRetry:
4427         /* BB switch to small buf init to save memory */
4428         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429                       (void **) &pSMBr);
4430         if (rc)
4431                 return rc;
4432
4433         params = 4;     /* 2 bytes zero followed by info level. */
4434         pSMB->MaxSetupCount = 0;
4435         pSMB->Reserved = 0;
4436         pSMB->Flags = 0;
4437         pSMB->Timeout = 0;
4438         pSMB->Reserved2 = 0;
4439         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4440                                 - 4;
4441         offset = param_offset + params;
4442
4443         pSMB->MaxParameterCount = cpu_to_le16(4);
4444         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4445         pSMB->SetupCount = 1;
4446         pSMB->Reserved3 = 0;
4447         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4448         byte_count = 1 /* pad */ + params + 12;
4449
4450         pSMB->DataCount = cpu_to_le16(12);
4451         pSMB->ParameterCount = cpu_to_le16(params);
4452         pSMB->TotalDataCount = pSMB->DataCount;
4453         pSMB->TotalParameterCount = pSMB->ParameterCount;
4454         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4455         pSMB->DataOffset = cpu_to_le16(offset);
4456
4457         /* Params. */
4458         pSMB->FileNum = 0;
4459         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4460
4461         /* Data. */
4462         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4463         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4464         pSMB->ClientUnixCap = cpu_to_le64(cap);
4465
4466         pSMB->hdr.smb_buf_length += byte_count;
4467         pSMB->ByteCount = cpu_to_le16(byte_count);
4468
4469         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4470                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4471         if (rc) {
4472                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4473         } else {                /* decode response */
4474                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4475                 if (rc) {
4476                         rc = -EIO;      /* bad smb */
4477                 }
4478         }
4479         cifs_buf_release(pSMB);
4480
4481         if (rc == -EAGAIN)
4482                 goto SETFSUnixRetry;
4483
4484         return rc;
4485 }
4486
4487
4488
4489 int
4490 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4491                    struct kstatfs *FSData)
4492 {
4493 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4494         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4495         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4496         FILE_SYSTEM_POSIX_INFO *response_data;
4497         int rc = 0;
4498         int bytes_returned = 0;
4499         __u16 params, byte_count;
4500
4501         cFYI(1, ("In QFSPosixInfo"));
4502 QFSPosixRetry:
4503         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4504                       (void **) &pSMBr);
4505         if (rc)
4506                 return rc;
4507
4508         params = 2;     /* level */
4509         pSMB->TotalDataCount = 0;
4510         pSMB->DataCount = 0;
4511         pSMB->DataOffset = 0;
4512         pSMB->MaxParameterCount = cpu_to_le16(2);
4513         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4514         pSMB->MaxSetupCount = 0;
4515         pSMB->Reserved = 0;
4516         pSMB->Flags = 0;
4517         pSMB->Timeout = 0;
4518         pSMB->Reserved2 = 0;
4519         byte_count = params + 1 /* pad */ ;
4520         pSMB->ParameterCount = cpu_to_le16(params);
4521         pSMB->TotalParameterCount = pSMB->ParameterCount;
4522         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4523                         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4524         pSMB->SetupCount = 1;
4525         pSMB->Reserved3 = 0;
4526         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4527         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4528         pSMB->hdr.smb_buf_length += byte_count;
4529         pSMB->ByteCount = cpu_to_le16(byte_count);
4530
4531         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4532                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4533         if (rc) {
4534                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4535         } else {                /* decode response */
4536                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4537
4538                 if (rc || (pSMBr->ByteCount < 13)) {
4539                         rc = -EIO;      /* bad smb */
4540                 } else {
4541                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4542                         response_data =
4543                             (FILE_SYSTEM_POSIX_INFO
4544                              *) (((char *) &pSMBr->hdr.Protocol) +
4545                                  data_offset);
4546                         FSData->f_bsize =
4547                                         le32_to_cpu(response_data->BlockSize);
4548                         FSData->f_blocks =
4549                                         le64_to_cpu(response_data->TotalBlocks);
4550                         FSData->f_bfree =
4551                             le64_to_cpu(response_data->BlocksAvail);
4552                         if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4553                                 FSData->f_bavail = FSData->f_bfree;
4554                         } else {
4555                                 FSData->f_bavail =
4556                                     le64_to_cpu(response_data->UserBlocksAvail);
4557                         }
4558                         if (response_data->TotalFileNodes != cpu_to_le64(-1))
4559                                 FSData->f_files =
4560                                      le64_to_cpu(response_data->TotalFileNodes);
4561                         if (response_data->FreeFileNodes != cpu_to_le64(-1))
4562                                 FSData->f_ffree =
4563                                       le64_to_cpu(response_data->FreeFileNodes);
4564                 }
4565         }
4566         cifs_buf_release(pSMB);
4567
4568         if (rc == -EAGAIN)
4569                 goto QFSPosixRetry;
4570
4571         return rc;
4572 }
4573
4574
4575 /* We can not use write of zero bytes trick to
4576    set file size due to need for large file support.  Also note that
4577    this SetPathInfo is preferred to SetFileInfo based method in next
4578    routine which is only needed to work around a sharing violation bug
4579    in Samba which this routine can run into */
4580
4581 int
4582 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4583               __u64 size, int SetAllocation,
4584               const struct nls_table *nls_codepage, int remap)
4585 {
4586         struct smb_com_transaction2_spi_req *pSMB = NULL;
4587         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4588         struct file_end_of_file_info *parm_data;
4589         int name_len;
4590         int rc = 0;
4591         int bytes_returned = 0;
4592         __u16 params, byte_count, data_count, param_offset, offset;
4593
4594         cFYI(1, ("In SetEOF"));
4595 SetEOFRetry:
4596         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4597                       (void **) &pSMBr);
4598         if (rc)
4599                 return rc;
4600
4601         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4602                 name_len =
4603                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4604                                      PATH_MAX, nls_codepage, remap);
4605                 name_len++;     /* trailing null */
4606                 name_len *= 2;
4607         } else {        /* BB improve the check for buffer overruns BB */
4608                 name_len = strnlen(fileName, PATH_MAX);
4609                 name_len++;     /* trailing null */
4610                 strncpy(pSMB->FileName, fileName, name_len);
4611         }
4612         params = 6 + name_len;
4613         data_count = sizeof(struct file_end_of_file_info);
4614         pSMB->MaxParameterCount = cpu_to_le16(2);
4615         pSMB->MaxDataCount = cpu_to_le16(4100);
4616         pSMB->MaxSetupCount = 0;
4617         pSMB->Reserved = 0;
4618         pSMB->Flags = 0;
4619         pSMB->Timeout = 0;
4620         pSMB->Reserved2 = 0;
4621         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4622                                 InformationLevel) - 4;
4623         offset = param_offset + params;
4624         if (SetAllocation) {
4625                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4626                         pSMB->InformationLevel =
4627                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4628                 else
4629                         pSMB->InformationLevel =
4630                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4631         } else /* Set File Size */  {
4632             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4633                     pSMB->InformationLevel =
4634                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4635             else
4636                     pSMB->InformationLevel =
4637                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4638         }
4639
4640         parm_data =
4641             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4642                                        offset);
4643         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4644         pSMB->DataOffset = cpu_to_le16(offset);
4645         pSMB->SetupCount = 1;
4646         pSMB->Reserved3 = 0;
4647         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4648         byte_count = 3 /* pad */  + params + data_count;
4649         pSMB->DataCount = cpu_to_le16(data_count);
4650         pSMB->TotalDataCount = pSMB->DataCount;
4651         pSMB->ParameterCount = cpu_to_le16(params);
4652         pSMB->TotalParameterCount = pSMB->ParameterCount;
4653         pSMB->Reserved4 = 0;
4654         pSMB->hdr.smb_buf_length += byte_count;
4655         parm_data->FileSize = cpu_to_le64(size);
4656         pSMB->ByteCount = cpu_to_le16(byte_count);
4657         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4658                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4659         if (rc) {
4660                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4661         }
4662
4663         cifs_buf_release(pSMB);
4664
4665         if (rc == -EAGAIN)
4666                 goto SetEOFRetry;
4667
4668         return rc;
4669 }
4670
4671 int
4672 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4673                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4674 {
4675         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4676         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4677         char *data_offset;
4678         struct file_end_of_file_info *parm_data;
4679         int rc = 0;
4680         int bytes_returned = 0;
4681         __u16 params, param_offset, offset, byte_count, count;
4682
4683         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4684                         (long long)size));
4685         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4686
4687         if (rc)
4688                 return rc;
4689
4690         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4691
4692         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4693         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4694
4695         params = 6;
4696         pSMB->MaxSetupCount = 0;
4697         pSMB->Reserved = 0;
4698         pSMB->Flags = 0;
4699         pSMB->Timeout = 0;
4700         pSMB->Reserved2 = 0;
4701         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4702         offset = param_offset + params;
4703
4704         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4705
4706         count = sizeof(struct file_end_of_file_info);
4707         pSMB->MaxParameterCount = cpu_to_le16(2);
4708         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4709         pSMB->SetupCount = 1;
4710         pSMB->Reserved3 = 0;
4711         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4712         byte_count = 3 /* pad */  + params + count;
4713         pSMB->DataCount = cpu_to_le16(count);
4714         pSMB->ParameterCount = cpu_to_le16(params);
4715         pSMB->TotalDataCount = pSMB->DataCount;
4716         pSMB->TotalParameterCount = pSMB->ParameterCount;
4717         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4718         parm_data =
4719                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4720                                 + offset);
4721         pSMB->DataOffset = cpu_to_le16(offset);
4722         parm_data->FileSize = cpu_to_le64(size);
4723         pSMB->Fid = fid;
4724         if (SetAllocation) {
4725                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4726                         pSMB->InformationLevel =
4727                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4728                 else
4729                         pSMB->InformationLevel =
4730                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4731         } else /* Set File Size */  {
4732             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733                     pSMB->InformationLevel =
4734                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4735             else
4736                     pSMB->InformationLevel =
4737                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4738         }
4739         pSMB->Reserved4 = 0;
4740         pSMB->hdr.smb_buf_length += byte_count;
4741         pSMB->ByteCount = cpu_to_le16(byte_count);
4742         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4743                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4744         if (rc) {
4745                 cFYI(1,
4746                      ("Send error in SetFileInfo (SetFileSize) = %d",
4747                       rc));
4748         }
4749
4750         if (pSMB)
4751                 cifs_small_buf_release(pSMB);
4752
4753         /* Note: On -EAGAIN error only caller can retry on handle based calls
4754                 since file handle passed in no longer valid */
4755
4756         return rc;
4757 }
4758
4759 /* Some legacy servers such as NT4 require that the file times be set on
4760    an open handle, rather than by pathname - this is awkward due to
4761    potential access conflicts on the open, but it is unavoidable for these
4762    old servers since the only other choice is to go from 100 nanosecond DCE
4763    time and resort to the original setpathinfo level which takes the ancient
4764    DOS time format with 2 second granularity */
4765 int
4766 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4767                     const FILE_BASIC_INFO *data, __u16 fid)
4768 {
4769         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4770         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4771         char *data_offset;
4772         int rc = 0;
4773         int bytes_returned = 0;
4774         __u16 params, param_offset, offset, byte_count, count;
4775
4776         cFYI(1, ("Set Times (via SetFileInfo)"));
4777         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4778
4779         if (rc)
4780                 return rc;
4781
4782         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4783
4784         /* At this point there is no need to override the current pid
4785         with the pid of the opener, but that could change if we someday
4786         use an existing handle (rather than opening one on the fly) */
4787         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4788         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4789
4790         params = 6;
4791         pSMB->MaxSetupCount = 0;
4792         pSMB->Reserved = 0;
4793         pSMB->Flags = 0;
4794         pSMB->Timeout = 0;
4795         pSMB->Reserved2 = 0;
4796         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4797         offset = param_offset + params;
4798
4799         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4800
4801         count = sizeof(FILE_BASIC_INFO);
4802         pSMB->MaxParameterCount = cpu_to_le16(2);
4803         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4804         pSMB->SetupCount = 1;
4805         pSMB->Reserved3 = 0;
4806         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4807         byte_count = 3 /* pad */  + params + count;
4808         pSMB->DataCount = cpu_to_le16(count);
4809         pSMB->ParameterCount = cpu_to_le16(params);
4810         pSMB->TotalDataCount = pSMB->DataCount;
4811         pSMB->TotalParameterCount = pSMB->ParameterCount;
4812         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4813         pSMB->DataOffset = cpu_to_le16(offset);
4814         pSMB->Fid = fid;
4815         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4817         else
4818                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4819         pSMB->Reserved4 = 0;
4820         pSMB->hdr.smb_buf_length += byte_count;
4821         pSMB->ByteCount = cpu_to_le16(byte_count);
4822         memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4823         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4824                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4825         if (rc) {
4826                 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4827         }
4828
4829         cifs_small_buf_release(pSMB);
4830
4831         /* Note: On -EAGAIN error only caller can retry on handle based calls
4832                 since file handle passed in no longer valid */
4833
4834         return rc;
4835 }
4836
4837
4838 int
4839 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4840                 const FILE_BASIC_INFO *data,
4841                 const struct nls_table *nls_codepage, int remap)
4842 {
4843         TRANSACTION2_SPI_REQ *pSMB = NULL;
4844         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4845         int name_len;
4846         int rc = 0;
4847         int bytes_returned = 0;
4848         char *data_offset;
4849         __u16 params, param_offset, offset, byte_count, count;
4850
4851         cFYI(1, ("In SetTimes"));
4852
4853 SetTimesRetry:
4854         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4855                       (void **) &pSMBr);
4856         if (rc)
4857                 return rc;
4858
4859         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4860                 name_len =
4861                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4862                                      PATH_MAX, nls_codepage, remap);
4863                 name_len++;     /* trailing null */
4864                 name_len *= 2;
4865         } else {        /* BB improve the check for buffer overruns BB */
4866                 name_len = strnlen(fileName, PATH_MAX);
4867                 name_len++;     /* trailing null */
4868                 strncpy(pSMB->FileName, fileName, name_len);
4869         }
4870
4871         params = 6 + name_len;
4872         count = sizeof(FILE_BASIC_INFO);
4873         pSMB->MaxParameterCount = cpu_to_le16(2);
4874         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4875         pSMB->MaxSetupCount = 0;
4876         pSMB->Reserved = 0;
4877         pSMB->Flags = 0;
4878         pSMB->Timeout = 0;
4879         pSMB->Reserved2 = 0;
4880         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4881                                 InformationLevel) - 4;
4882         offset = param_offset + params;
4883         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4884         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4885         pSMB->DataOffset = cpu_to_le16(offset);
4886         pSMB->SetupCount = 1;
4887         pSMB->Reserved3 = 0;
4888         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4889         byte_count = 3 /* pad */  + params + count;
4890
4891         pSMB->DataCount = cpu_to_le16(count);
4892         pSMB->ParameterCount = cpu_to_le16(params);
4893         pSMB->TotalDataCount = pSMB->DataCount;
4894         pSMB->TotalParameterCount = pSMB->ParameterCount;
4895         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4896                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4897         else
4898                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4899         pSMB->Reserved4 = 0;
4900         pSMB->hdr.smb_buf_length += byte_count;
4901         memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4902         pSMB->ByteCount = cpu_to_le16(byte_count);
4903         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4904                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4905         if (rc) {
4906                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4907         }
4908
4909         cifs_buf_release(pSMB);
4910
4911         if (rc == -EAGAIN)
4912                 goto SetTimesRetry;
4913
4914         return rc;
4915 }
4916
4917 /* Can not be used to set time stamps yet (due to old DOS time format) */
4918 /* Can be used to set attributes */
4919 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4920           handling it anyway and NT4 was what we thought it would be needed for
4921           Do not delete it until we prove whether needed for Win9x though */
4922 int
4923 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4924                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4925 {
4926         SETATTR_REQ *pSMB = NULL;
4927         SETATTR_RSP *pSMBr = NULL;
4928         int rc = 0;
4929         int bytes_returned;
4930         int name_len;
4931
4932         cFYI(1, ("In SetAttrLegacy"));
4933
4934 SetAttrLgcyRetry:
4935         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4936                       (void **) &pSMBr);
4937         if (rc)
4938                 return rc;
4939
4940         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4941                 name_len =
4942                         ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4943                                 PATH_MAX, nls_codepage);
4944                 name_len++;     /* trailing null */
4945                 name_len *= 2;
4946         } else {        /* BB improve the check for buffer overruns BB */
4947                 name_len = strnlen(fileName, PATH_MAX);
4948                 name_len++;     /* trailing null */
4949                 strncpy(pSMB->fileName, fileName, name_len);
4950         }
4951         pSMB->attr = cpu_to_le16(dos_attrs);
4952         pSMB->BufferFormat = 0x04;
4953         pSMB->hdr.smb_buf_length += name_len + 1;
4954         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4955         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4956                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4957         if (rc) {
4958                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4959         }
4960
4961         cifs_buf_release(pSMB);
4962
4963         if (rc == -EAGAIN)
4964                 goto SetAttrLgcyRetry;
4965
4966         return rc;
4967 }
4968 #endif /* temporarily unneeded SetAttr legacy function */
4969
4970 int
4971 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4972                     char *fileName, __u64 mode, __u64 uid, __u64 gid,
4973                     dev_t device, const struct nls_table *nls_codepage,
4974                     int remap)
4975 {
4976         TRANSACTION2_SPI_REQ *pSMB = NULL;
4977         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4978         int name_len;
4979         int rc = 0;
4980         int bytes_returned = 0;
4981         FILE_UNIX_BASIC_INFO *data_offset;
4982         __u16 params, param_offset, offset, count, byte_count;
4983
4984         cFYI(1, ("In SetUID/GID/Mode"));
4985 setPermsRetry:
4986         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4987                       (void **) &pSMBr);
4988         if (rc)
4989                 return rc;
4990
4991         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4992                 name_len =
4993                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4994                                      PATH_MAX, nls_codepage, remap);
4995                 name_len++;     /* trailing null */
4996                 name_len *= 2;
4997         } else {        /* BB improve the check for buffer overruns BB */
4998                 name_len = strnlen(fileName, PATH_MAX);
4999                 name_len++;     /* trailing null */
5000                 strncpy(pSMB->FileName, fileName, name_len);
5001         }
5002
5003         params = 6 + name_len;
5004         count = sizeof(FILE_UNIX_BASIC_INFO);
5005         pSMB->MaxParameterCount = cpu_to_le16(2);
5006         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5007         pSMB->MaxSetupCount = 0;
5008         pSMB->Reserved = 0;
5009         pSMB->Flags = 0;
5010         pSMB->Timeout = 0;
5011         pSMB->Reserved2 = 0;
5012         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5013                                 InformationLevel) - 4;
5014         offset = param_offset + params;
5015         data_offset =
5016             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5017                                       offset);
5018         memset(data_offset, 0, count);
5019         pSMB->DataOffset = cpu_to_le16(offset);
5020         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5021         pSMB->SetupCount = 1;
5022         pSMB->Reserved3 = 0;
5023         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5024         byte_count = 3 /* pad */  + params + count;
5025         pSMB->ParameterCount = cpu_to_le16(params);
5026         pSMB->DataCount = cpu_to_le16(count);
5027         pSMB->TotalParameterCount = pSMB->ParameterCount;
5028         pSMB->TotalDataCount = pSMB->DataCount;
5029         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5030         pSMB->Reserved4 = 0;
5031         pSMB->hdr.smb_buf_length += byte_count;
5032         /* Samba server ignores set of file size to zero due to bugs in some
5033         older clients, but we should be precise - we use SetFileSize to
5034         set file size and do not want to truncate file size to zero
5035         accidently as happened on one Samba server beta by putting
5036         zero instead of -1 here */
5037         data_offset->EndOfFile = NO_CHANGE_64;
5038         data_offset->NumOfBytes = NO_CHANGE_64;
5039         data_offset->LastStatusChange = NO_CHANGE_64;
5040         data_offset->LastAccessTime = NO_CHANGE_64;
5041         data_offset->LastModificationTime = NO_CHANGE_64;
5042         data_offset->Uid = cpu_to_le64(uid);
5043         data_offset->Gid = cpu_to_le64(gid);
5044         /* better to leave device as zero when it is  */
5045         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5046         data_offset->DevMinor = cpu_to_le64(MINOR(device));
5047         data_offset->Permissions = cpu_to_le64(mode);
5048
5049         if (S_ISREG(mode))
5050                 data_offset->Type = cpu_to_le32(UNIX_FILE);
5051         else if (S_ISDIR(mode))
5052                 data_offset->Type = cpu_to_le32(UNIX_DIR);
5053         else if (S_ISLNK(mode))
5054                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5055         else if (S_ISCHR(mode))
5056                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5057         else if (S_ISBLK(mode))
5058                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5059         else if (S_ISFIFO(mode))
5060                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5061         else if (S_ISSOCK(mode))
5062                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5063
5064
5065         pSMB->ByteCount = cpu_to_le16(byte_count);
5066         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5067                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5068         if (rc) {
5069                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5070         }
5071
5072         if (pSMB)
5073                 cifs_buf_release(pSMB);
5074         if (rc == -EAGAIN)
5075                 goto setPermsRetry;
5076         return rc;
5077 }
5078
5079 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5080                   const int notify_subdirs, const __u16 netfid,
5081                   __u32 filter, struct file *pfile, int multishot,
5082                   const struct nls_table *nls_codepage)
5083 {
5084         int rc = 0;
5085         struct smb_com_transaction_change_notify_req *pSMB = NULL;
5086         struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5087         struct dir_notify_req *dnotify_req;
5088         int bytes_returned;
5089
5090         cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5091         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5092                       (void **) &pSMBr);
5093         if (rc)
5094                 return rc;
5095
5096         pSMB->TotalParameterCount = 0 ;
5097         pSMB->TotalDataCount = 0;
5098         pSMB->MaxParameterCount = cpu_to_le32(2);
5099         /* BB find exact data count max from sess structure BB */
5100         pSMB->MaxDataCount = 0; /* same in little endian or be */
5101 /* BB VERIFY verify which is correct for above BB */
5102         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5103                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5104
5105         pSMB->MaxSetupCount = 4;
5106         pSMB->Reserved = 0;
5107         pSMB->ParameterOffset = 0;
5108         pSMB->DataCount = 0;
5109         pSMB->DataOffset = 0;
5110         pSMB->SetupCount = 4; /* single byte does not need le conversion */
5111         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5112         pSMB->ParameterCount = pSMB->TotalParameterCount;
5113         if (notify_subdirs)
5114                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5115         pSMB->Reserved2 = 0;
5116         pSMB->CompletionFilter = cpu_to_le32(filter);
5117         pSMB->Fid = netfid; /* file handle always le */
5118         pSMB->ByteCount = 0;
5119
5120         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5121                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5122         if (rc) {
5123                 cFYI(1, ("Error in Notify = %d", rc));
5124         } else {
5125                 /* Add file to outstanding requests */
5126                 /* BB change to kmem cache alloc */
5127                 dnotify_req = kmalloc(
5128                                                 sizeof(struct dir_notify_req),
5129                                                  GFP_KERNEL);
5130                 if (dnotify_req) {
5131                         dnotify_req->Pid = pSMB->hdr.Pid;
5132                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5133                         dnotify_req->Mid = pSMB->hdr.Mid;
5134                         dnotify_req->Tid = pSMB->hdr.Tid;
5135                         dnotify_req->Uid = pSMB->hdr.Uid;
5136                         dnotify_req->netfid = netfid;
5137                         dnotify_req->pfile = pfile;
5138                         dnotify_req->filter = filter;
5139                         dnotify_req->multishot = multishot;
5140                         spin_lock(&GlobalMid_Lock);
5141                         list_add_tail(&dnotify_req->lhead,
5142                                         &GlobalDnotifyReqList);
5143                         spin_unlock(&GlobalMid_Lock);
5144                 } else
5145                         rc = -ENOMEM;
5146         }
5147         cifs_buf_release(pSMB);
5148         return rc;
5149 }
5150 #ifdef CONFIG_CIFS_XATTR
5151 ssize_t
5152 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5153                  const unsigned char *searchName,
5154                  char *EAData, size_t buf_size,
5155                  const struct nls_table *nls_codepage, int remap)
5156 {
5157                 /* BB assumes one setup word */
5158         TRANSACTION2_QPI_REQ *pSMB = NULL;
5159         TRANSACTION2_QPI_RSP *pSMBr = NULL;
5160         int rc = 0;
5161         int bytes_returned;
5162         int name_len;
5163         struct fea *temp_fea;
5164         char *temp_ptr;
5165         __u16 params, byte_count;
5166
5167         cFYI(1, ("In Query All EAs path %s", searchName));
5168 QAllEAsRetry:
5169         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5170                       (void **) &pSMBr);
5171         if (rc)
5172                 return rc;
5173
5174         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5175                 name_len =
5176                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5177                                      PATH_MAX, nls_codepage, remap);
5178                 name_len++;     /* trailing null */
5179                 name_len *= 2;
5180         } else {        /* BB improve the check for buffer overruns BB */
5181                 name_len = strnlen(searchName, PATH_MAX);
5182                 name_len++;     /* trailing null */
5183                 strncpy(pSMB->FileName, searchName, name_len);
5184         }
5185
5186         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5187         pSMB->TotalDataCount = 0;
5188         pSMB->MaxParameterCount = cpu_to_le16(2);
5189         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5190         pSMB->MaxSetupCount = 0;
5191         pSMB->Reserved = 0;
5192         pSMB->Flags = 0;
5193         pSMB->Timeout = 0;
5194         pSMB->Reserved2 = 0;
5195         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5196         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5197         pSMB->DataCount = 0;
5198         pSMB->DataOffset = 0;
5199         pSMB->SetupCount = 1;
5200         pSMB->Reserved3 = 0;
5201         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5202         byte_count = params + 1 /* pad */ ;
5203         pSMB->TotalParameterCount = cpu_to_le16(params);
5204         pSMB->ParameterCount = pSMB->TotalParameterCount;
5205         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5206         pSMB->Reserved4 = 0;
5207         pSMB->hdr.smb_buf_length += byte_count;
5208         pSMB->ByteCount = cpu_to_le16(byte_count);
5209
5210         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5211                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5212         if (rc) {
5213                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5214         } else {                /* decode response */
5215                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5216
5217                 /* BB also check enough total bytes returned */
5218                 /* BB we need to improve the validity checking
5219                 of these trans2 responses */
5220                 if (rc || (pSMBr->ByteCount < 4))
5221                         rc = -EIO;      /* bad smb */
5222            /* else if (pFindData){
5223                         memcpy((char *) pFindData,
5224                                (char *) &pSMBr->hdr.Protocol +
5225                                data_offset, kl);
5226                 }*/ else {
5227                         /* check that length of list is not more than bcc */
5228                         /* check that each entry does not go beyond length
5229                            of list */
5230                         /* check that each element of each entry does not
5231                            go beyond end of list */
5232                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5233                         struct fealist *ea_response_data;
5234                         rc = 0;
5235                         /* validate_trans2_offsets() */
5236                         /* BB check if start of smb + data_offset > &bcc+ bcc */
5237                         ea_response_data = (struct fealist *)
5238                                 (((char *) &pSMBr->hdr.Protocol) +
5239                                 data_offset);
5240                         name_len = le32_to_cpu(ea_response_data->list_len);
5241                         cFYI(1, ("ea length %d", name_len));
5242                         if (name_len <= 8) {
5243                         /* returned EA size zeroed at top of function */
5244                                 cFYI(1, ("empty EA list returned from server"));
5245                         } else {
5246                                 /* account for ea list len */
5247                                 name_len -= 4;
5248                                 temp_fea = ea_response_data->list;
5249                                 temp_ptr = (char *)temp_fea;
5250                                 while (name_len > 0) {
5251                                         __u16 value_len;
5252                                         name_len -= 4;
5253                                         temp_ptr += 4;
5254                                         rc += temp_fea->name_len;
5255                                 /* account for prefix user. and trailing null */
5256                                         rc = rc + 5 + 1;
5257                                         if (rc < (int)buf_size) {
5258                                                 memcpy(EAData, "user.", 5);
5259                                                 EAData += 5;
5260                                                 memcpy(EAData, temp_ptr,
5261                                                        temp_fea->name_len);
5262                                                 EAData += temp_fea->name_len;
5263                                                 /* null terminate name */
5264                                                 *EAData = 0;
5265                                                 EAData = EAData + 1;
5266                                         } else if (buf_size == 0) {
5267                                                 /* skip copy - calc size only */
5268                                         } else {
5269                                                 /* stop before overrun buffer */
5270                                                 rc = -ERANGE;
5271                                                 break;
5272                                         }
5273                                         name_len -= temp_fea->name_len;
5274                                         temp_ptr += temp_fea->name_len;
5275                                         /* account for trailing null */
5276                                         name_len--;
5277                                         temp_ptr++;
5278                                         value_len =
5279                                               le16_to_cpu(temp_fea->value_len);
5280                                         name_len -= value_len;
5281                                         temp_ptr += value_len;
5282                                         /* BB check that temp_ptr is still
5283                                               within the SMB BB*/
5284
5285                                         /* no trailing null to account for
5286                                            in value len */
5287                                         /* go on to next EA */
5288                                         temp_fea = (struct fea *)temp_ptr;
5289                                 }
5290                         }
5291                 }
5292         }
5293         if (pSMB)
5294                 cifs_buf_release(pSMB);
5295         if (rc == -EAGAIN)
5296                 goto QAllEAsRetry;
5297
5298         return (ssize_t)rc;
5299 }
5300
5301 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5302                 const unsigned char *searchName, const unsigned char *ea_name,
5303                 unsigned char *ea_value, size_t buf_size,
5304                 const struct nls_table *nls_codepage, int remap)
5305 {
5306         TRANSACTION2_QPI_REQ *pSMB = NULL;
5307         TRANSACTION2_QPI_RSP *pSMBr = NULL;
5308         int rc = 0;
5309         int bytes_returned;
5310         int name_len;
5311         struct fea *temp_fea;
5312         char *temp_ptr;
5313         __u16 params, byte_count;
5314
5315         cFYI(1, ("In Query EA path %s", searchName));
5316 QEARetry:
5317         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5318                       (void **) &pSMBr);
5319         if (rc)
5320                 return rc;
5321
5322         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5323                 name_len =
5324                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5325                                      PATH_MAX, nls_codepage, remap);
5326                 name_len++;     /* trailing null */
5327                 name_len *= 2;
5328         } else {        /* BB improve the check for buffer overruns BB */
5329                 name_len = strnlen(searchName, PATH_MAX);
5330                 name_len++;     /* trailing null */
5331                 strncpy(pSMB->FileName, searchName, name_len);
5332         }
5333
5334         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5335         pSMB->TotalDataCount = 0;
5336         pSMB->MaxParameterCount = cpu_to_le16(2);
5337         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5338         pSMB->MaxSetupCount = 0;
5339         pSMB->Reserved = 0;
5340         pSMB->Flags = 0;
5341         pSMB->Timeout = 0;
5342         pSMB->Reserved2 = 0;
5343         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5344                 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5345         pSMB->DataCount = 0;
5346         pSMB->DataOffset = 0;
5347         pSMB->SetupCount = 1;
5348         pSMB->Reserved3 = 0;
5349         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5350         byte_count = params + 1 /* pad */ ;
5351         pSMB->TotalParameterCount = cpu_to_le16(params);
5352         pSMB->ParameterCount = pSMB->TotalParameterCount;
5353         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5354         pSMB->Reserved4 = 0;
5355         pSMB->hdr.smb_buf_length += byte_count;
5356         pSMB->ByteCount = cpu_to_le16(byte_count);
5357
5358         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5359                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5360         if (rc) {
5361                 cFYI(1, ("Send error in Query EA = %d", rc));
5362         } else {                /* decode response */
5363                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5364
5365                 /* BB also check enough total bytes returned */
5366                 /* BB we need to improve the validity checking
5367                 of these trans2 responses */
5368                 if (rc || (pSMBr->ByteCount < 4))
5369                         rc = -EIO;      /* bad smb */
5370            /* else if (pFindData){
5371                         memcpy((char *) pFindData,
5372                                (char *) &pSMBr->hdr.Protocol +
5373                                data_offset, kl);
5374                 }*/ else {
5375                         /* check that length of list is not more than bcc */
5376                         /* check that each entry does not go beyond length
5377                            of list */
5378                         /* check that each element of each entry does not
5379                            go beyond end of list */
5380                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5381                         struct fealist *ea_response_data;
5382                         rc = -ENODATA;
5383                         /* validate_trans2_offsets() */
5384                         /* BB check if start of smb + data_offset > &bcc+ bcc*/
5385                         ea_response_data = (struct fealist *)
5386                                 (((char *) &pSMBr->hdr.Protocol) +
5387                                 data_offset);
5388                         name_len = le32_to_cpu(ea_response_data->list_len);
5389                         cFYI(1, ("ea length %d", name_len));
5390                         if (name_len <= 8) {
5391                         /* returned EA size zeroed at top of function */
5392                                 cFYI(1, ("empty EA list returned from server"));
5393                         } else {
5394                                 /* account for ea list len */
5395                                 name_len -= 4;
5396                                 temp_fea = ea_response_data->list;
5397                                 temp_ptr = (char *)temp_fea;
5398                                 /* loop through checking if we have a matching
5399                                 name and then return the associated value */
5400                                 while (name_len > 0) {
5401                                         __u16 value_len;
5402                                         name_len -= 4;
5403                                         temp_ptr += 4;
5404                                         value_len =
5405                                               le16_to_cpu(temp_fea->value_len);
5406                                 /* BB validate that value_len falls within SMB,
5407                                 even though maximum for name_len is 255 */
5408                                         if (memcmp(temp_fea->name, ea_name,
5409                                                   temp_fea->name_len) == 0) {
5410                                                 /* found a match */
5411                                                 rc = value_len;
5412                                 /* account for prefix user. and trailing null */
5413                                                 if (rc <= (int)buf_size) {
5414                                                         memcpy(ea_value,
5415                                                                 temp_fea->name+temp_fea->name_len+1,
5416                                                                 rc);
5417                                                         /* ea values, unlike ea
5418                                                            names, are not null
5419                                                            terminated */
5420                                                 } else if (buf_size == 0) {
5421                                                 /* skip copy - calc size only */
5422                                                 } else {
5423                                                 /* stop before overrun buffer */
5424                                                         rc = -ERANGE;
5425                                                 }
5426                                                 break;
5427                                         }
5428                                         name_len -= temp_fea->name_len;
5429                                         temp_ptr += temp_fea->name_len;
5430                                         /* account for trailing null */
5431                                         name_len--;
5432                                         temp_ptr++;
5433                                         name_len -= value_len;
5434                                         temp_ptr += value_len;
5435                                         /* No trailing null to account for in
5436                                            value_len.  Go on to next EA */
5437                                         temp_fea = (struct fea *)temp_ptr;
5438                                 }
5439                         }
5440                 }
5441         }
5442         if (pSMB)
5443                 cifs_buf_release(pSMB);
5444         if (rc == -EAGAIN)
5445                 goto QEARetry;
5446
5447         return (ssize_t)rc;
5448 }
5449
5450 int
5451 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5452              const char *ea_name, const void *ea_value,
5453              const __u16 ea_value_len, const struct nls_table *nls_codepage,
5454              int remap)
5455 {
5456         struct smb_com_transaction2_spi_req *pSMB = NULL;
5457         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5458         struct fealist *parm_data;
5459         int name_len;
5460         int rc = 0;
5461         int bytes_returned = 0;
5462         __u16 params, param_offset, byte_count, offset, count;
5463
5464         cFYI(1, ("In SetEA"));
5465 SetEARetry:
5466         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5467                       (void **) &pSMBr);
5468         if (rc)
5469                 return rc;
5470
5471         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5472                 name_len =
5473                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5474                                      PATH_MAX, nls_codepage, remap);
5475                 name_len++;     /* trailing null */
5476                 name_len *= 2;
5477         } else {        /* BB improve the check for buffer overruns BB */
5478                 name_len = strnlen(fileName, PATH_MAX);
5479                 name_len++;     /* trailing null */
5480                 strncpy(pSMB->FileName, fileName, name_len);
5481         }
5482
5483         params = 6 + name_len;
5484
5485         /* done calculating parms using name_len of file name,
5486         now use name_len to calculate length of ea name
5487         we are going to create in the inode xattrs */
5488         if (ea_name == NULL)
5489                 name_len = 0;
5490         else
5491                 name_len = strnlen(ea_name, 255);
5492
5493         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5494         pSMB->MaxParameterCount = cpu_to_le16(2);
5495         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5496         pSMB->MaxSetupCount = 0;
5497         pSMB->Reserved = 0;
5498         pSMB->Flags = 0;
5499         pSMB->Timeout = 0;
5500         pSMB->Reserved2 = 0;
5501         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5502                                 InformationLevel) - 4;
5503         offset = param_offset + params;
5504         pSMB->InformationLevel =
5505                 cpu_to_le16(SMB_SET_FILE_EA);
5506
5507         parm_data =
5508                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5509                                        offset);
5510         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5511         pSMB->DataOffset = cpu_to_le16(offset);
5512         pSMB->SetupCount = 1;
5513         pSMB->Reserved3 = 0;
5514         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5515         byte_count = 3 /* pad */  + params + count;
5516         pSMB->DataCount = cpu_to_le16(count);
5517         parm_data->list_len = cpu_to_le32(count);
5518         parm_data->list[0].EA_flags = 0;
5519         /* we checked above that name len is less than 255 */
5520         parm_data->list[0].name_len = (__u8)name_len;
5521         /* EA names are always ASCII */
5522         if (ea_name)
5523                 strncpy(parm_data->list[0].name, ea_name, name_len);
5524         parm_data->list[0].name[name_len] = 0;
5525         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5526         /* caller ensures that ea_value_len is less than 64K but
5527         we need to ensure that it fits within the smb */
5528
5529         /*BB add length check to see if it would fit in
5530              negotiated SMB buffer size BB */
5531         /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5532         if (ea_value_len)
5533                 memcpy(parm_data->list[0].name+name_len+1,
5534                        ea_value, ea_value_len);
5535
5536         pSMB->TotalDataCount = pSMB->DataCount;
5537         pSMB->ParameterCount = cpu_to_le16(params);
5538         pSMB->TotalParameterCount = pSMB->ParameterCount;
5539         pSMB->Reserved4 = 0;
5540         pSMB->hdr.smb_buf_length += byte_count;
5541         pSMB->ByteCount = cpu_to_le16(byte_count);
5542         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5543                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5544         if (rc) {
5545                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5546         }
5547
5548         cifs_buf_release(pSMB);
5549
5550         if (rc == -EAGAIN)
5551                 goto SetEARetry;
5552
5553         return rc;
5554 }
5555
5556 #endif