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