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