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