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