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