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