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