]> bbs.cooldavid.org Git - net-next-2.6.git/blob - fs/cifs/cifssmb.c
[CIFS] log better errors on failed mounts
[net-next-2.6.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2007
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly differently for reconnection purposes since we never     */
28  /* want to reuse a stale file handle and only the caller knows the file info */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "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 /* Initialize NT TRANSACT SMB into small smb request buffer.
2490    This assumes that all NT TRANSACTS that we init here have
2491    total parm and data under about 400 bytes (to fit in small cifs
2492    buffer size), which is the case so far, it easily fits. NB:
2493         Setup words themselves and ByteCount
2494         MaxSetupCount (size of returned setup area) and
2495         MaxParameterCount (returned parms size) must be set by caller */
2496 static int
2497 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2498                    const int parm_len, struct cifsTconInfo *tcon,
2499                    void **ret_buf)
2500 {
2501         int rc;
2502         __u32 temp_offset;
2503         struct smb_com_ntransact_req *pSMB;
2504
2505         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2506                                 (void **)&pSMB);
2507         if (rc)
2508                 return rc;
2509         *ret_buf = (void *)pSMB;
2510         pSMB->Reserved = 0;
2511         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2512         pSMB->TotalDataCount  = 0;
2513         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2514                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2515         pSMB->ParameterCount = pSMB->TotalParameterCount;
2516         pSMB->DataCount  = pSMB->TotalDataCount;
2517         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2518                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
2519         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2520         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2521         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2522         pSMB->SubCommand = cpu_to_le16(sub_command);
2523         return 0;
2524 }
2525
2526 static int
2527 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2528                    int *pdatalen, int *pparmlen)
2529 {
2530         char *end_of_smb;
2531         __u32 data_count, data_offset, parm_count, parm_offset;
2532         struct smb_com_ntransact_rsp *pSMBr;
2533
2534         if (buf == NULL)
2535                 return -EINVAL;
2536
2537         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2538
2539         /* ByteCount was converted from little endian in SendReceive */
2540         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2541                         (char *)&pSMBr->ByteCount;
2542
2543         data_offset = le32_to_cpu(pSMBr->DataOffset);
2544         data_count = le32_to_cpu(pSMBr->DataCount);
2545         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2546         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2547
2548         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2549         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2550
2551         /* should we also check that parm and data areas do not overlap? */
2552         if (*ppparm > end_of_smb) {
2553                 cFYI(1, ("parms start after end of smb"));
2554                 return -EINVAL;
2555         } else if (parm_count + *ppparm > end_of_smb) {
2556                 cFYI(1, ("parm end after end of smb"));
2557                 return -EINVAL;
2558         } else if (*ppdata > end_of_smb) {
2559                 cFYI(1, ("data starts after end of smb"));
2560                 return -EINVAL;
2561         } else if (data_count + *ppdata > end_of_smb) {
2562                 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2563                         *ppdata, data_count, (data_count + *ppdata),
2564                         end_of_smb, pSMBr));
2565                 return -EINVAL;
2566         } else if (parm_count + data_count > pSMBr->ByteCount) {
2567                 cFYI(1, ("parm count and data count larger than SMB"));
2568                 return -EINVAL;
2569         }
2570         return 0;
2571 }
2572
2573 int
2574 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2575                         const unsigned char *searchName,
2576                         char *symlinkinfo, const int buflen, __u16 fid,
2577                         const struct nls_table *nls_codepage)
2578 {
2579         int rc = 0;
2580         int bytes_returned;
2581         int name_len;
2582         struct smb_com_transaction_ioctl_req *pSMB;
2583         struct smb_com_transaction_ioctl_rsp *pSMBr;
2584
2585         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2586         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2587                       (void **) &pSMBr);
2588         if (rc)
2589                 return rc;
2590
2591         pSMB->TotalParameterCount = 0 ;
2592         pSMB->TotalDataCount = 0;
2593         pSMB->MaxParameterCount = cpu_to_le32(2);
2594         /* BB find exact data count max from sess structure BB */
2595         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2596                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2597         pSMB->MaxSetupCount = 4;
2598         pSMB->Reserved = 0;
2599         pSMB->ParameterOffset = 0;
2600         pSMB->DataCount = 0;
2601         pSMB->DataOffset = 0;
2602         pSMB->SetupCount = 4;
2603         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2604         pSMB->ParameterCount = pSMB->TotalParameterCount;
2605         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2606         pSMB->IsFsctl = 1; /* FSCTL */
2607         pSMB->IsRootFlag = 0;
2608         pSMB->Fid = fid; /* file handle always le */
2609         pSMB->ByteCount = 0;
2610
2611         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2612                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2613         if (rc) {
2614                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2615         } else {                /* decode response */
2616                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2617                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2618                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2619                 /* BB also check enough total bytes returned */
2620                         rc = -EIO;      /* bad smb */
2621                 else {
2622                         if (data_count && (data_count < 2048)) {
2623                                 char *end_of_smb = 2 /* sizeof byte count */ +
2624                                                 pSMBr->ByteCount +
2625                                                 (char *)&pSMBr->ByteCount;
2626
2627                                 struct reparse_data *reparse_buf =
2628                                                 (struct reparse_data *)
2629                                                 ((char *)&pSMBr->hdr.Protocol
2630                                                                  + data_offset);
2631                                 if ((char *)reparse_buf >= end_of_smb) {
2632                                         rc = -EIO;
2633                                         goto qreparse_out;
2634                                 }
2635                                 if ((reparse_buf->LinkNamesBuf +
2636                                         reparse_buf->TargetNameOffset +
2637                                         reparse_buf->TargetNameLen) >
2638                                                 end_of_smb) {
2639                                         cFYI(1, ("reparse buf beyond SMB"));
2640                                         rc = -EIO;
2641                                         goto qreparse_out;
2642                                 }
2643
2644                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2645                                         name_len = UniStrnlen((wchar_t *)
2646                                                 (reparse_buf->LinkNamesBuf +
2647                                                 reparse_buf->TargetNameOffset),
2648                                                 min(buflen/2,
2649                                                 reparse_buf->TargetNameLen / 2));
2650                                         cifs_strfromUCS_le(symlinkinfo,
2651                                                 (__le16 *) (reparse_buf->LinkNamesBuf +
2652                                                 reparse_buf->TargetNameOffset),
2653                                                 name_len, nls_codepage);
2654                                 } else { /* ASCII names */
2655                                         strncpy(symlinkinfo,
2656                                                 reparse_buf->LinkNamesBuf +
2657                                                 reparse_buf->TargetNameOffset,
2658                                                 min_t(const int, buflen,
2659                                                    reparse_buf->TargetNameLen));
2660                                 }
2661                         } else {
2662                                 rc = -EIO;
2663                                 cFYI(1, ("Invalid return data count on "
2664                                          "get reparse info ioctl"));
2665                         }
2666                         symlinkinfo[buflen] = 0; /* just in case so the caller
2667                                         does not go off the end of the buffer */
2668                         cFYI(1, ("readlink result - %s", symlinkinfo));
2669                 }
2670         }
2671 qreparse_out:
2672         cifs_buf_release(pSMB);
2673
2674         /* Note: On -EAGAIN error only caller can retry on handle based calls
2675                 since file handle passed in no longer valid */
2676
2677         return rc;
2678 }
2679
2680 #ifdef CONFIG_CIFS_POSIX
2681
2682 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2683 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2684                              struct cifs_posix_ace *cifs_ace)
2685 {
2686         /* u8 cifs fields do not need le conversion */
2687         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2688         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2689         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2690         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2691
2692         return;
2693 }
2694
2695 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2696 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2697                                const int acl_type, const int size_of_data_area)
2698 {
2699         int size =  0;
2700         int i;
2701         __u16 count;
2702         struct cifs_posix_ace *pACE;
2703         struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2704         posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2705
2706         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2707                 return -EOPNOTSUPP;
2708
2709         if (acl_type & ACL_TYPE_ACCESS) {
2710                 count = le16_to_cpu(cifs_acl->access_entry_count);
2711                 pACE = &cifs_acl->ace_array[0];
2712                 size = sizeof(struct cifs_posix_acl);
2713                 size += sizeof(struct cifs_posix_ace) * count;
2714                 /* check if we would go beyond end of SMB */
2715                 if (size_of_data_area < size) {
2716                         cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2717                                 size_of_data_area, size));
2718                         return -EINVAL;
2719                 }
2720         } else if (acl_type & ACL_TYPE_DEFAULT) {
2721                 count = le16_to_cpu(cifs_acl->access_entry_count);
2722                 size = sizeof(struct cifs_posix_acl);
2723                 size += sizeof(struct cifs_posix_ace) * count;
2724 /* skip past access ACEs to get to default ACEs */
2725                 pACE = &cifs_acl->ace_array[count];
2726                 count = le16_to_cpu(cifs_acl->default_entry_count);
2727                 size += sizeof(struct cifs_posix_ace) * count;
2728                 /* check if we would go beyond end of SMB */
2729                 if (size_of_data_area < size)
2730                         return -EINVAL;
2731         } else {
2732                 /* illegal type */
2733                 return -EINVAL;
2734         }
2735
2736         size = posix_acl_xattr_size(count);
2737         if ((buflen == 0) || (local_acl == NULL)) {
2738                 /* used to query ACL EA size */
2739         } else if (size > buflen) {
2740                 return -ERANGE;
2741         } else /* buffer big enough */ {
2742                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2743                 for (i = 0; i < count ; i++) {
2744                         cifs_convert_ace(&local_acl->a_entries[i], pACE);
2745                         pACE++;
2746                 }
2747         }
2748         return size;
2749 }
2750
2751 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2752                                      const posix_acl_xattr_entry *local_ace)
2753 {
2754         __u16 rc = 0; /* 0 = ACL converted ok */
2755
2756         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2757         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2758         /* BB is there a better way to handle the large uid? */
2759         if (local_ace->e_id == cpu_to_le32(-1)) {
2760         /* Probably no need to le convert -1 on any arch but can not hurt */
2761                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2762         } else
2763                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2764         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2765         return rc;
2766 }
2767
2768 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2769 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2770                                const int buflen, const int acl_type)
2771 {
2772         __u16 rc = 0;
2773         struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2774         posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2775         int count;
2776         int i;
2777
2778         if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2779                 return 0;
2780
2781         count = posix_acl_xattr_count((size_t)buflen);
2782         cFYI(1, ("setting acl with %d entries from buf of length %d and "
2783                 "version of %d",
2784                 count, buflen, le32_to_cpu(local_acl->a_version)));
2785         if (le32_to_cpu(local_acl->a_version) != 2) {
2786                 cFYI(1, ("unknown POSIX ACL version %d",
2787                      le32_to_cpu(local_acl->a_version)));
2788                 return 0;
2789         }
2790         cifs_acl->version = cpu_to_le16(1);
2791         if (acl_type == ACL_TYPE_ACCESS)
2792                 cifs_acl->access_entry_count = cpu_to_le16(count);
2793         else if (acl_type == ACL_TYPE_DEFAULT)
2794                 cifs_acl->default_entry_count = cpu_to_le16(count);
2795         else {
2796                 cFYI(1, ("unknown ACL type %d", acl_type));
2797                 return 0;
2798         }
2799         for (i = 0; i < count; i++) {
2800                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2801                                         &local_acl->a_entries[i]);
2802                 if (rc != 0) {
2803                         /* ACE not converted */
2804                         break;
2805                 }
2806         }
2807         if (rc == 0) {
2808                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2809                 rc += sizeof(struct cifs_posix_acl);
2810                 /* BB add check to make sure ACL does not overflow SMB */
2811         }
2812         return rc;
2813 }
2814
2815 int
2816 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2817                    const unsigned char *searchName,
2818                    char *acl_inf, const int buflen, const int acl_type,
2819                    const struct nls_table *nls_codepage, int remap)
2820 {
2821 /* SMB_QUERY_POSIX_ACL */
2822         TRANSACTION2_QPI_REQ *pSMB = NULL;
2823         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2824         int rc = 0;
2825         int bytes_returned;
2826         int name_len;
2827         __u16 params, byte_count;
2828
2829         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2830
2831 queryAclRetry:
2832         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2833                 (void **) &pSMBr);
2834         if (rc)
2835                 return rc;
2836
2837         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2838                 name_len =
2839                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2840                                          PATH_MAX, nls_codepage, remap);
2841                 name_len++;     /* trailing null */
2842                 name_len *= 2;
2843                 pSMB->FileName[name_len] = 0;
2844                 pSMB->FileName[name_len+1] = 0;
2845         } else {        /* BB improve the check for buffer overruns BB */
2846                 name_len = strnlen(searchName, PATH_MAX);
2847                 name_len++;     /* trailing null */
2848                 strncpy(pSMB->FileName, searchName, name_len);
2849         }
2850
2851         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2852         pSMB->TotalDataCount = 0;
2853         pSMB->MaxParameterCount = cpu_to_le16(2);
2854         /* BB find exact max data count below from sess structure BB */
2855         pSMB->MaxDataCount = cpu_to_le16(4000);
2856         pSMB->MaxSetupCount = 0;
2857         pSMB->Reserved = 0;
2858         pSMB->Flags = 0;
2859         pSMB->Timeout = 0;
2860         pSMB->Reserved2 = 0;
2861         pSMB->ParameterOffset = cpu_to_le16(
2862                 offsetof(struct smb_com_transaction2_qpi_req,
2863                          InformationLevel) - 4);
2864         pSMB->DataCount = 0;
2865         pSMB->DataOffset = 0;
2866         pSMB->SetupCount = 1;
2867         pSMB->Reserved3 = 0;
2868         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2869         byte_count = params + 1 /* pad */ ;
2870         pSMB->TotalParameterCount = cpu_to_le16(params);
2871         pSMB->ParameterCount = pSMB->TotalParameterCount;
2872         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2873         pSMB->Reserved4 = 0;
2874         pSMB->hdr.smb_buf_length += byte_count;
2875         pSMB->ByteCount = cpu_to_le16(byte_count);
2876
2877         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2878                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2879         cifs_stats_inc(&tcon->num_acl_get);
2880         if (rc) {
2881                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2882         } else {
2883                 /* decode response */
2884
2885                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2886                 if (rc || (pSMBr->ByteCount < 2))
2887                 /* BB also check enough total bytes returned */
2888                         rc = -EIO;      /* bad smb */
2889                 else {
2890                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2891                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2892                         rc = cifs_copy_posix_acl(acl_inf,
2893                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2894                                 buflen, acl_type, count);
2895                 }
2896         }
2897         cifs_buf_release(pSMB);
2898         if (rc == -EAGAIN)
2899                 goto queryAclRetry;
2900         return rc;
2901 }
2902
2903 int
2904 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2905                    const unsigned char *fileName,
2906                    const char *local_acl, const int buflen,
2907                    const int acl_type,
2908                    const struct nls_table *nls_codepage, int remap)
2909 {
2910         struct smb_com_transaction2_spi_req *pSMB = NULL;
2911         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2912         char *parm_data;
2913         int name_len;
2914         int rc = 0;
2915         int bytes_returned = 0;
2916         __u16 params, byte_count, data_count, param_offset, offset;
2917
2918         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2919 setAclRetry:
2920         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2921                       (void **) &pSMBr);
2922         if (rc)
2923                 return rc;
2924         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2925                 name_len =
2926                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2927                                       PATH_MAX, nls_codepage, remap);
2928                 name_len++;     /* trailing null */
2929                 name_len *= 2;
2930         } else {        /* BB improve the check for buffer overruns BB */
2931                 name_len = strnlen(fileName, PATH_MAX);
2932                 name_len++;     /* trailing null */
2933                 strncpy(pSMB->FileName, fileName, name_len);
2934         }
2935         params = 6 + name_len;
2936         pSMB->MaxParameterCount = cpu_to_le16(2);
2937         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2938         pSMB->MaxSetupCount = 0;
2939         pSMB->Reserved = 0;
2940         pSMB->Flags = 0;
2941         pSMB->Timeout = 0;
2942         pSMB->Reserved2 = 0;
2943         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2944                                 InformationLevel) - 4;
2945         offset = param_offset + params;
2946         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2947         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2948
2949         /* convert to on the wire format for POSIX ACL */
2950         data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2951
2952         if (data_count == 0) {
2953                 rc = -EOPNOTSUPP;
2954                 goto setACLerrorExit;
2955         }
2956         pSMB->DataOffset = cpu_to_le16(offset);
2957         pSMB->SetupCount = 1;
2958         pSMB->Reserved3 = 0;
2959         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2960         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2961         byte_count = 3 /* pad */  + params + data_count;
2962         pSMB->DataCount = cpu_to_le16(data_count);
2963         pSMB->TotalDataCount = pSMB->DataCount;
2964         pSMB->ParameterCount = cpu_to_le16(params);
2965         pSMB->TotalParameterCount = pSMB->ParameterCount;
2966         pSMB->Reserved4 = 0;
2967         pSMB->hdr.smb_buf_length += byte_count;
2968         pSMB->ByteCount = cpu_to_le16(byte_count);
2969         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2970                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2971         if (rc) {
2972                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2973         }
2974
2975 setACLerrorExit:
2976         cifs_buf_release(pSMB);
2977         if (rc == -EAGAIN)
2978                 goto setAclRetry;
2979         return rc;
2980 }
2981
2982 /* BB fix tabs in this function FIXME BB */
2983 int
2984 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2985                const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2986 {
2987         int rc = 0;
2988         struct smb_t2_qfi_req *pSMB = NULL;
2989         struct smb_t2_qfi_rsp *pSMBr = NULL;
2990         int bytes_returned;
2991         __u16 params, byte_count;
2992
2993         cFYI(1, ("In GetExtAttr"));
2994         if (tcon == NULL)
2995                 return -ENODEV;
2996
2997 GetExtAttrRetry:
2998         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999                         (void **) &pSMBr);
3000         if (rc)
3001                 return rc;
3002
3003         params = 2 /* level */ +2 /* fid */;
3004         pSMB->t2.TotalDataCount = 0;
3005         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3006         /* BB find exact max data count below from sess structure BB */
3007         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3008         pSMB->t2.MaxSetupCount = 0;
3009         pSMB->t2.Reserved = 0;
3010         pSMB->t2.Flags = 0;
3011         pSMB->t2.Timeout = 0;
3012         pSMB->t2.Reserved2 = 0;
3013         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3014                                                Fid) - 4);
3015         pSMB->t2.DataCount = 0;
3016         pSMB->t2.DataOffset = 0;
3017         pSMB->t2.SetupCount = 1;
3018         pSMB->t2.Reserved3 = 0;
3019         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3020         byte_count = params + 1 /* pad */ ;
3021         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3022         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3023         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3024         pSMB->Pad = 0;
3025         pSMB->Fid = netfid;
3026         pSMB->hdr.smb_buf_length += byte_count;
3027         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3028
3029         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3030                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3031         if (rc) {
3032                 cFYI(1, ("error %d in GetExtAttr", rc));
3033         } else {
3034                 /* decode response */
3035                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3036                 if (rc || (pSMBr->ByteCount < 2))
3037                 /* BB also check enough total bytes returned */
3038                         /* If rc should we check for EOPNOSUPP and
3039                            disable the srvino flag? or in caller? */
3040                         rc = -EIO;      /* bad smb */
3041                 else {
3042                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3043                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3044                         struct file_chattr_info *pfinfo;
3045                         /* BB Do we need a cast or hash here ? */
3046                         if (count != 16) {
3047                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
3048                                 rc = -EIO;
3049                                 goto GetExtAttrOut;
3050                         }
3051                         pfinfo = (struct file_chattr_info *)
3052                                  (data_offset + (char *) &pSMBr->hdr.Protocol);
3053                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3054                         *pMask = le64_to_cpu(pfinfo->mask);
3055                 }
3056         }
3057 GetExtAttrOut:
3058         cifs_buf_release(pSMB);
3059         if (rc == -EAGAIN)
3060                 goto GetExtAttrRetry;
3061         return rc;
3062 }
3063
3064 #endif /* CONFIG_POSIX */
3065
3066 #ifdef CONFIG_CIFS_EXPERIMENTAL
3067 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3068 int
3069 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3070                 /* BB fix up return info */ char *acl_inf, const int buflen,
3071                   const int acl_type)
3072 {
3073         int rc = 0;
3074         int buf_type = 0;
3075         QUERY_SEC_DESC_REQ * pSMB;
3076         struct kvec iov[1];
3077
3078         cFYI(1, ("GetCifsACL"));
3079
3080         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3081                         8 /* parm len */, tcon, (void **) &pSMB);
3082         if (rc)
3083                 return rc;
3084
3085         pSMB->MaxParameterCount = cpu_to_le32(4);
3086         /* BB TEST with big acls that might need to be e.g. larger than 16K */
3087         pSMB->MaxSetupCount = 0;
3088         pSMB->Fid = fid; /* file handle always le */
3089         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3090                                      CIFS_ACL_DACL);
3091         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3092         pSMB->hdr.smb_buf_length += 11;
3093         iov[0].iov_base = (char *)pSMB;
3094         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3095
3096         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3097                          0 /* not long op */, 0 /* do not log STATUS codes */ );
3098         cifs_stats_inc(&tcon->num_acl_get);
3099         if (rc) {
3100                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3101         } else {                /* decode response */
3102                 struct cifs_ntsd *psec_desc;
3103                 __le32 * parm;
3104                 int parm_len;
3105                 int data_len;
3106                 int acl_len;
3107                 struct smb_com_ntransact_rsp *pSMBr;
3108
3109 /* validate_nttransact */
3110                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3111                                         (char **)&psec_desc,
3112                                         &parm_len, &data_len);
3113                 if (rc)
3114                         goto qsec_out;
3115                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3116
3117                 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
3118
3119                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3120                         rc = -EIO;      /* bad smb */
3121                         goto qsec_out;
3122                 }
3123
3124 /* BB check that data area is minimum length and as big as acl_len */
3125
3126                 acl_len = le32_to_cpu(*parm);
3127                 /* BB check if (acl_len > bufsize) */
3128
3129                 parse_sec_desc(psec_desc, acl_len);
3130         }
3131 qsec_out:
3132         if (buf_type == CIFS_SMALL_BUFFER)
3133                 cifs_small_buf_release(iov[0].iov_base);
3134         else if (buf_type == CIFS_LARGE_BUFFER)
3135                 cifs_buf_release(iov[0].iov_base);
3136 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3137         return rc;
3138 }
3139 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3140
3141 /* Legacy Query Path Information call for lookup to old servers such
3142    as Win9x/WinME */
3143 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3144                         const unsigned char *searchName,
3145                         FILE_ALL_INFO *pFinfo,
3146                         const struct nls_table *nls_codepage, int remap)
3147 {
3148         QUERY_INFORMATION_REQ * pSMB;
3149         QUERY_INFORMATION_RSP * pSMBr;
3150         int rc = 0;
3151         int bytes_returned;
3152         int name_len;
3153
3154         cFYI(1, ("In SMBQPath path %s", searchName));
3155 QInfRetry:
3156         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3157                       (void **) &pSMBr);
3158         if (rc)
3159                 return rc;
3160
3161         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3162                 name_len =
3163                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3164                                         PATH_MAX, nls_codepage, remap);
3165                 name_len++;     /* trailing null */
3166                 name_len *= 2;
3167         } else {
3168                 name_len = strnlen(searchName, PATH_MAX);
3169                 name_len++;     /* trailing null */
3170                 strncpy(pSMB->FileName, searchName, name_len);
3171         }
3172         pSMB->BufferFormat = 0x04;
3173         name_len++; /* account for buffer type byte */
3174         pSMB->hdr.smb_buf_length += (__u16) name_len;
3175         pSMB->ByteCount = cpu_to_le16(name_len);
3176
3177         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3178                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3179         if (rc) {
3180                 cFYI(1, ("Send error in QueryInfo = %d", rc));
3181         } else if (pFinfo) {            /* decode response */
3182                 struct timespec ts;
3183                 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3184                 /* BB FIXME - add time zone adjustment BB */
3185                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3186                 ts.tv_nsec = 0;
3187                 ts.tv_sec = time;
3188                 /* decode time fields */
3189                 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3190                 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3191                 pFinfo->LastAccessTime = 0;
3192                 pFinfo->AllocationSize =
3193                         cpu_to_le64(le32_to_cpu(pSMBr->size));
3194                 pFinfo->EndOfFile = pFinfo->AllocationSize;
3195                 pFinfo->Attributes =
3196                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
3197         } else
3198                 rc = -EIO; /* bad buffer passed in */
3199
3200         cifs_buf_release(pSMB);
3201
3202         if (rc == -EAGAIN)
3203                 goto QInfRetry;
3204
3205         return rc;
3206 }
3207
3208
3209
3210
3211 int
3212 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3213                  const unsigned char *searchName,
3214                  FILE_ALL_INFO * pFindData,
3215                  int legacy /* old style infolevel */,
3216                  const struct nls_table *nls_codepage, int remap)
3217 {
3218 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3219         TRANSACTION2_QPI_REQ *pSMB = NULL;
3220         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3221         int rc = 0;
3222         int bytes_returned;
3223         int name_len;
3224         __u16 params, byte_count;
3225
3226 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3227 QPathInfoRetry:
3228         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3229                       (void **) &pSMBr);
3230         if (rc)
3231                 return rc;
3232
3233         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3234                 name_len =
3235                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3236                                      PATH_MAX, nls_codepage, remap);
3237                 name_len++;     /* trailing null */
3238                 name_len *= 2;
3239         } else {        /* BB improve the check for buffer overruns BB */
3240                 name_len = strnlen(searchName, PATH_MAX);
3241                 name_len++;     /* trailing null */
3242                 strncpy(pSMB->FileName, searchName, name_len);
3243         }
3244
3245         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3246         pSMB->TotalDataCount = 0;
3247         pSMB->MaxParameterCount = cpu_to_le16(2);
3248         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3249         pSMB->MaxSetupCount = 0;
3250         pSMB->Reserved = 0;
3251         pSMB->Flags = 0;
3252         pSMB->Timeout = 0;
3253         pSMB->Reserved2 = 0;
3254         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3255         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3256         pSMB->DataCount = 0;
3257         pSMB->DataOffset = 0;
3258         pSMB->SetupCount = 1;
3259         pSMB->Reserved3 = 0;
3260         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3261         byte_count = params + 1 /* pad */ ;
3262         pSMB->TotalParameterCount = cpu_to_le16(params);
3263         pSMB->ParameterCount = pSMB->TotalParameterCount;
3264         if (legacy)
3265                 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3266         else
3267                 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3268         pSMB->Reserved4 = 0;
3269         pSMB->hdr.smb_buf_length += byte_count;
3270         pSMB->ByteCount = cpu_to_le16(byte_count);
3271
3272         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3273                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3274         if (rc) {
3275                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3276         } else {                /* decode response */
3277                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3278
3279                 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3280                         rc = -EIO;
3281                 else if (!legacy && (pSMBr->ByteCount < 40))
3282                         rc = -EIO;      /* bad smb */
3283                 else if (legacy && (pSMBr->ByteCount < 24))
3284                         rc = -EIO;  /* 24 or 26 expected but we do not read
3285                                         last field */
3286                 else if (pFindData) {
3287                         int size;
3288                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3289                         if (legacy) /* we do not read the last field, EAsize,
3290                                        fortunately since it varies by subdialect
3291                                        and on Set vs. Get, is two bytes or 4
3292                                        bytes depending but we don't care here */
3293                                 size = sizeof(FILE_INFO_STANDARD);
3294                         else
3295                                 size = sizeof(FILE_ALL_INFO);
3296                         memcpy((char *) pFindData,
3297                                (char *) &pSMBr->hdr.Protocol +
3298                                data_offset, size);
3299                 } else
3300                     rc = -ENOMEM;
3301         }
3302         cifs_buf_release(pSMB);
3303         if (rc == -EAGAIN)
3304                 goto QPathInfoRetry;
3305
3306         return rc;
3307 }
3308
3309 int
3310 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3311                      const unsigned char *searchName,
3312                      FILE_UNIX_BASIC_INFO * pFindData,
3313                      const struct nls_table *nls_codepage, int remap)
3314 {
3315 /* SMB_QUERY_FILE_UNIX_BASIC */
3316         TRANSACTION2_QPI_REQ *pSMB = NULL;
3317         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3318         int rc = 0;
3319         int bytes_returned = 0;
3320         int name_len;
3321         __u16 params, byte_count;
3322
3323         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3324 UnixQPathInfoRetry:
3325         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3326                       (void **) &pSMBr);
3327         if (rc)
3328                 return rc;
3329
3330         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3331                 name_len =
3332                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3333                                   PATH_MAX, nls_codepage, remap);
3334                 name_len++;     /* trailing null */
3335                 name_len *= 2;
3336         } else {        /* BB improve the check for buffer overruns BB */
3337                 name_len = strnlen(searchName, PATH_MAX);
3338                 name_len++;     /* trailing null */
3339                 strncpy(pSMB->FileName, searchName, name_len);
3340         }
3341
3342         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3343         pSMB->TotalDataCount = 0;
3344         pSMB->MaxParameterCount = cpu_to_le16(2);
3345         /* BB find exact max SMB PDU from sess structure BB */
3346         pSMB->MaxDataCount = cpu_to_le16(4000);
3347         pSMB->MaxSetupCount = 0;
3348         pSMB->Reserved = 0;
3349         pSMB->Flags = 0;
3350         pSMB->Timeout = 0;
3351         pSMB->Reserved2 = 0;
3352         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3353         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3354         pSMB->DataCount = 0;
3355         pSMB->DataOffset = 0;
3356         pSMB->SetupCount = 1;
3357         pSMB->Reserved3 = 0;
3358         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3359         byte_count = params + 1 /* pad */ ;
3360         pSMB->TotalParameterCount = cpu_to_le16(params);
3361         pSMB->ParameterCount = pSMB->TotalParameterCount;
3362         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3363         pSMB->Reserved4 = 0;
3364         pSMB->hdr.smb_buf_length += byte_count;
3365         pSMB->ByteCount = cpu_to_le16(byte_count);
3366
3367         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3368                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3369         if (rc) {
3370                 cFYI(1, ("Send error in QPathInfo = %d", rc));
3371         } else {                /* decode response */
3372                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3373
3374                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3375                         cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3376                                    "Unix Extensions can be disabled on mount "
3377                                    "by specifying the nosfu mount option."));
3378                         rc = -EIO;      /* bad smb */
3379                 } else {
3380                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3381                         memcpy((char *) pFindData,
3382                                (char *) &pSMBr->hdr.Protocol +
3383                                data_offset,
3384                                sizeof (FILE_UNIX_BASIC_INFO));
3385                 }
3386         }
3387         cifs_buf_release(pSMB);
3388         if (rc == -EAGAIN)
3389                 goto UnixQPathInfoRetry;
3390
3391         return rc;
3392 }
3393
3394 #if 0  /* function unused at present */
3395 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3396                const char *searchName, FILE_ALL_INFO * findData,
3397                const struct nls_table *nls_codepage)
3398 {
3399 /* level 257 SMB_ */
3400         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3401         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3402         int rc = 0;
3403         int bytes_returned;
3404         int name_len;
3405         __u16 params, byte_count;
3406
3407         cFYI(1, ("In FindUnique"));
3408 findUniqueRetry:
3409         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3410                       (void **) &pSMBr);
3411         if (rc)
3412                 return rc;
3413
3414         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3415                 name_len =
3416                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3417                                      PATH_MAX, nls_codepage);
3418                 name_len++;     /* trailing null */
3419                 name_len *= 2;
3420         } else {        /* BB improve the check for buffer overruns BB */
3421                 name_len = strnlen(searchName, PATH_MAX);
3422                 name_len++;     /* trailing null */
3423                 strncpy(pSMB->FileName, searchName, name_len);
3424         }
3425
3426         params = 12 + name_len /* includes null */ ;
3427         pSMB->TotalDataCount = 0;       /* no EAs */
3428         pSMB->MaxParameterCount = cpu_to_le16(2);
3429         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3430         pSMB->MaxSetupCount = 0;
3431         pSMB->Reserved = 0;
3432         pSMB->Flags = 0;
3433         pSMB->Timeout = 0;
3434         pSMB->Reserved2 = 0;
3435         pSMB->ParameterOffset = cpu_to_le16(
3436          offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
3437         pSMB->DataCount = 0;
3438         pSMB->DataOffset = 0;
3439         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
3440         pSMB->Reserved3 = 0;
3441         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3442         byte_count = params + 1 /* pad */ ;
3443         pSMB->TotalParameterCount = cpu_to_le16(params);
3444         pSMB->ParameterCount = pSMB->TotalParameterCount;
3445         pSMB->SearchAttributes =
3446             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3447                         ATTR_DIRECTORY);
3448         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
3449         pSMB->SearchFlags = cpu_to_le16(1);
3450         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3451         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
3452         pSMB->hdr.smb_buf_length += byte_count;
3453         pSMB->ByteCount = cpu_to_le16(byte_count);
3454
3455         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3456                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3457
3458         if (rc) {
3459                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3460         } else {                /* decode response */
3461                 cifs_stats_inc(&tcon->num_ffirst);
3462                 /* BB fill in */
3463         }
3464
3465         cifs_buf_release(pSMB);
3466         if (rc == -EAGAIN)
3467                 goto findUniqueRetry;
3468
3469         return rc;
3470 }
3471 #endif /* end unused (temporarily) function */
3472
3473 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3474 int
3475 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3476               const char *searchName,
3477               const struct nls_table *nls_codepage,
3478               __u16 *pnetfid,
3479               struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3480 {
3481 /* level 257 SMB_ */
3482         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3483         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3484         T2_FFIRST_RSP_PARMS * parms;
3485         int rc = 0;
3486         int bytes_returned = 0;
3487         int name_len;
3488         __u16 params, byte_count;
3489
3490         cFYI(1, ("In FindFirst for %s", searchName));
3491
3492 findFirstRetry:
3493         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3494                       (void **) &pSMBr);
3495         if (rc)
3496                 return rc;
3497
3498         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3499                 name_len =
3500                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3501                                  PATH_MAX, nls_codepage, remap);
3502                 /* We can not add the asterik earlier in case
3503                 it got remapped to 0xF03A as if it were part of the
3504                 directory name instead of a wildcard */
3505                 name_len *= 2;
3506                 pSMB->FileName[name_len] = dirsep;
3507                 pSMB->FileName[name_len+1] = 0;
3508                 pSMB->FileName[name_len+2] = '*';
3509                 pSMB->FileName[name_len+3] = 0;
3510                 name_len += 4; /* now the trailing null */
3511                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3512                 pSMB->FileName[name_len+1] = 0;
3513                 name_len += 2;
3514         } else {        /* BB add check for overrun of SMB buf BB */
3515                 name_len = strnlen(searchName, PATH_MAX);
3516 /* BB fix here and in unicode clause above ie
3517                 if (name_len > buffersize-header)
3518                         free buffer exit; BB */
3519                 strncpy(pSMB->FileName, searchName, name_len);
3520                 pSMB->FileName[name_len] = dirsep;
3521                 pSMB->FileName[name_len+1] = '*';
3522                 pSMB->FileName[name_len+2] = 0;
3523                 name_len += 3;
3524         }
3525
3526         params = 12 + name_len /* includes null */ ;
3527         pSMB->TotalDataCount = 0;       /* no EAs */
3528         pSMB->MaxParameterCount = cpu_to_le16(10);
3529         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3530                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3531         pSMB->MaxSetupCount = 0;
3532         pSMB->Reserved = 0;
3533         pSMB->Flags = 0;
3534         pSMB->Timeout = 0;
3535         pSMB->Reserved2 = 0;
3536         byte_count = params + 1 /* pad */ ;
3537         pSMB->TotalParameterCount = cpu_to_le16(params);
3538         pSMB->ParameterCount = pSMB->TotalParameterCount;
3539         pSMB->ParameterOffset = cpu_to_le16(
3540               offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3541                 - 4);
3542         pSMB->DataCount = 0;
3543         pSMB->DataOffset = 0;
3544         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3545         pSMB->Reserved3 = 0;
3546         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3547         pSMB->SearchAttributes =
3548             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3549                         ATTR_DIRECTORY);
3550         pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3551         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3552                 CIFS_SEARCH_RETURN_RESUME);
3553         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3554
3555         /* BB what should we set StorageType to? Does it matter? BB */
3556         pSMB->SearchStorageType = 0;
3557         pSMB->hdr.smb_buf_length += byte_count;
3558         pSMB->ByteCount = cpu_to_le16(byte_count);
3559
3560         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3561                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3562         cifs_stats_inc(&tcon->num_ffirst);
3563
3564         if (rc) {/* BB add logic to retry regular search if Unix search
3565                         rejected unexpectedly by server */
3566                 /* BB Add code to handle unsupported level rc */
3567                 cFYI(1, ("Error in FindFirst = %d", rc));
3568
3569                 cifs_buf_release(pSMB);
3570
3571                 /* BB eventually could optimize out free and realloc of buf */
3572                 /*    for this case */
3573                 if (rc == -EAGAIN)
3574                         goto findFirstRetry;
3575         } else { /* decode response */
3576                 /* BB remember to free buffer if error BB */
3577                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3578                 if (rc == 0) {
3579                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3580                                 psrch_inf->unicode = TRUE;
3581                         else
3582                                 psrch_inf->unicode = FALSE;
3583
3584                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3585                         psrch_inf->smallBuf = 0;
3586                         psrch_inf->srch_entries_start =
3587                                 (char *) &pSMBr->hdr.Protocol +
3588                                         le16_to_cpu(pSMBr->t2.DataOffset);
3589                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3590                                le16_to_cpu(pSMBr->t2.ParameterOffset));
3591
3592                         if (parms->EndofSearch)
3593                                 psrch_inf->endOfSearch = TRUE;
3594                         else
3595                                 psrch_inf->endOfSearch = FALSE;
3596
3597                         psrch_inf->entries_in_buffer =
3598                                         le16_to_cpu(parms->SearchCount);
3599                         psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3600                                 psrch_inf->entries_in_buffer;
3601                         *pnetfid = parms->SearchHandle;
3602                 } else {
3603                         cifs_buf_release(pSMB);
3604                 }
3605         }
3606
3607         return rc;
3608 }
3609
3610 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3611                  __u16 searchHandle, struct cifs_search_info *psrch_inf)
3612 {
3613         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3614         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3615         T2_FNEXT_RSP_PARMS * parms;
3616         char *response_data;
3617         int rc = 0;
3618         int bytes_returned, name_len;
3619         __u16 params, byte_count;
3620
3621         cFYI(1, ("In FindNext"));
3622
3623         if (psrch_inf->endOfSearch == TRUE)
3624                 return -ENOENT;
3625
3626         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3627                 (void **) &pSMBr);
3628         if (rc)
3629                 return rc;
3630
3631         params = 14; /* includes 2 bytes of null string, converted to LE below*/
3632         byte_count = 0;
3633         pSMB->TotalDataCount = 0;       /* no EAs */
3634         pSMB->MaxParameterCount = cpu_to_le16(8);
3635         pSMB->MaxDataCount =
3636                 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3637                                 0xFFFFFF00);
3638         pSMB->MaxSetupCount = 0;
3639         pSMB->Reserved = 0;
3640         pSMB->Flags = 0;
3641         pSMB->Timeout = 0;
3642         pSMB->Reserved2 = 0;
3643         pSMB->ParameterOffset =  cpu_to_le16(
3644               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3645         pSMB->DataCount = 0;
3646         pSMB->DataOffset = 0;
3647         pSMB->SetupCount = 1;
3648         pSMB->Reserved3 = 0;
3649         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3650         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3651         pSMB->SearchCount =
3652                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3653         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3654         pSMB->ResumeKey = psrch_inf->resume_key;
3655         pSMB->SearchFlags =
3656               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3657
3658         name_len = psrch_inf->resume_name_len;
3659         params += name_len;
3660         if (name_len < PATH_MAX) {
3661                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3662                 byte_count += name_len;
3663                 /* 14 byte parm len above enough for 2 byte null terminator */
3664                 pSMB->ResumeFileName[name_len] = 0;
3665                 pSMB->ResumeFileName[name_len+1] = 0;
3666         } else {
3667                 rc = -EINVAL;
3668                 goto FNext2_err_exit;
3669         }
3670         byte_count = params + 1 /* pad */ ;
3671         pSMB->TotalParameterCount = cpu_to_le16(params);
3672         pSMB->ParameterCount = pSMB->TotalParameterCount;
3673         pSMB->hdr.smb_buf_length += byte_count;
3674         pSMB->ByteCount = cpu_to_le16(byte_count);
3675
3676         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3677                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3678         cifs_stats_inc(&tcon->num_fnext);
3679         if (rc) {
3680                 if (rc == -EBADF) {
3681                         psrch_inf->endOfSearch = TRUE;
3682                         rc = 0; /* search probably was closed at end of search*/
3683                 } else
3684                         cFYI(1, ("FindNext returned = %d", rc));
3685         } else {                /* decode response */
3686                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3687
3688                 if (rc == 0) {
3689                         /* BB fixme add lock for file (srch_info) struct here */
3690                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3691                                 psrch_inf->unicode = TRUE;
3692                         else
3693                                 psrch_inf->unicode = FALSE;
3694                         response_data = (char *) &pSMBr->hdr.Protocol +
3695                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3696                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3697                         response_data = (char *)&pSMBr->hdr.Protocol +
3698                                 le16_to_cpu(pSMBr->t2.DataOffset);
3699                         if (psrch_inf->smallBuf)
3700                                 cifs_small_buf_release(
3701                                         psrch_inf->ntwrk_buf_start);
3702                         else
3703                                 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3704                         psrch_inf->srch_entries_start = response_data;
3705                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3706                         psrch_inf->smallBuf = 0;
3707                         if (parms->EndofSearch)
3708                                 psrch_inf->endOfSearch = TRUE;
3709                         else
3710                                 psrch_inf->endOfSearch = FALSE;
3711                         psrch_inf->entries_in_buffer =
3712                                                 le16_to_cpu(parms->SearchCount);
3713                         psrch_inf->index_of_last_entry +=
3714                                 psrch_inf->entries_in_buffer;
3715 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3716             psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3717
3718                         /* BB fixme add unlock here */
3719                 }
3720
3721         }
3722
3723         /* BB On error, should we leave previous search buf (and count and
3724         last entry fields) intact or free the previous one? */
3725
3726         /* Note: On -EAGAIN error only caller can retry on handle based calls
3727         since file handle passed in no longer valid */
3728 FNext2_err_exit:
3729         if (rc != 0)
3730                 cifs_buf_release(pSMB);
3731         return rc;
3732 }
3733
3734 int
3735 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3736               const __u16 searchHandle)
3737 {
3738         int rc = 0;
3739         FINDCLOSE_REQ *pSMB = NULL;
3740         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3741         int bytes_returned;
3742
3743         cFYI(1, ("In CIFSSMBFindClose"));
3744         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3745
3746         /* no sense returning error if session restarted
3747                 as file handle has been closed */
3748         if (rc == -EAGAIN)
3749                 return 0;
3750         if (rc)
3751                 return rc;
3752
3753         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3754         pSMB->FileID = searchHandle;
3755         pSMB->ByteCount = 0;
3756         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3757                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3758         if (rc) {
3759                 cERROR(1, ("Send error in FindClose = %d", rc));
3760         }
3761         cifs_stats_inc(&tcon->num_fclose);
3762         cifs_small_buf_release(pSMB);
3763
3764         /* Since session is dead, search handle closed on server already */
3765         if (rc == -EAGAIN)
3766                 rc = 0;
3767
3768         return rc;
3769 }
3770
3771 int
3772 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3773                       const unsigned char *searchName,
3774                       __u64 * inode_number,
3775                       const struct nls_table *nls_codepage, int remap)
3776 {
3777         int rc = 0;
3778         TRANSACTION2_QPI_REQ *pSMB = NULL;
3779         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3780         int name_len, bytes_returned;
3781         __u16 params, byte_count;
3782
3783         cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3784         if (tcon == NULL)
3785                 return -ENODEV;
3786
3787 GetInodeNumberRetry:
3788         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3789                       (void **) &pSMBr);
3790         if (rc)
3791                 return rc;
3792
3793         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3794                 name_len =
3795                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3796                                          PATH_MAX, nls_codepage, remap);
3797                 name_len++;     /* trailing null */
3798                 name_len *= 2;
3799         } else {        /* BB improve the check for buffer overruns BB */
3800                 name_len = strnlen(searchName, PATH_MAX);
3801                 name_len++;     /* trailing null */
3802                 strncpy(pSMB->FileName, searchName, name_len);
3803         }
3804
3805         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3806         pSMB->TotalDataCount = 0;
3807         pSMB->MaxParameterCount = cpu_to_le16(2);
3808         /* BB find exact max data count below from sess structure BB */
3809         pSMB->MaxDataCount = cpu_to_le16(4000);
3810         pSMB->MaxSetupCount = 0;
3811         pSMB->Reserved = 0;
3812         pSMB->Flags = 0;
3813         pSMB->Timeout = 0;
3814         pSMB->Reserved2 = 0;
3815         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3816                 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3817         pSMB->DataCount = 0;
3818         pSMB->DataOffset = 0;
3819         pSMB->SetupCount = 1;
3820         pSMB->Reserved3 = 0;
3821         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3822         byte_count = params + 1 /* pad */ ;
3823         pSMB->TotalParameterCount = cpu_to_le16(params);
3824         pSMB->ParameterCount = pSMB->TotalParameterCount;
3825         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3826         pSMB->Reserved4 = 0;
3827         pSMB->hdr.smb_buf_length += byte_count;
3828         pSMB->ByteCount = cpu_to_le16(byte_count);
3829
3830         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3831                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3832         if (rc) {
3833                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3834         } else {
3835                 /* decode response */
3836                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3837                 if (rc || (pSMBr->ByteCount < 2))
3838                 /* BB also check enough total bytes returned */
3839                         /* If rc should we check for EOPNOSUPP and
3840                         disable the srvino flag? or in caller? */
3841                         rc = -EIO;      /* bad smb */
3842                 else {
3843                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3844                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3845                         struct file_internal_info *pfinfo;
3846                         /* BB Do we need a cast or hash here ? */
3847                         if (count < 8) {
3848                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3849                                 rc = -EIO;
3850                                 goto GetInodeNumOut;
3851                         }
3852                         pfinfo = (struct file_internal_info *)
3853                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3854                         *inode_number = pfinfo->UniqueId;
3855                 }
3856         }
3857 GetInodeNumOut:
3858         cifs_buf_release(pSMB);
3859         if (rc == -EAGAIN)
3860                 goto GetInodeNumberRetry;
3861         return rc;
3862 }
3863
3864 int
3865 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3866                 const unsigned char *searchName,
3867                 unsigned char **targetUNCs,
3868                 unsigned int *number_of_UNC_in_array,
3869                 const struct nls_table *nls_codepage, int remap)
3870 {
3871 /* TRANS2_GET_DFS_REFERRAL */
3872         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3873         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3874         struct dfs_referral_level_3 *referrals = NULL;
3875         int rc = 0;
3876         int bytes_returned;
3877         int name_len;
3878         unsigned int i;
3879         char *temp;
3880         __u16 params, byte_count;
3881         *number_of_UNC_in_array = 0;
3882         *targetUNCs = NULL;
3883
3884         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3885         if (ses == NULL)
3886                 return -ENODEV;
3887 getDFSRetry:
3888         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3889                       (void **) &pSMBr);
3890         if (rc)
3891                 return rc;
3892
3893         /* server pointer checked in called function,
3894         but should never be null here anyway */
3895         pSMB->hdr.Mid = GetNextMid(ses->server);
3896         pSMB->hdr.Tid = ses->ipc_tid;
3897         pSMB->hdr.Uid = ses->Suid;
3898         if (ses->capabilities & CAP_STATUS32)
3899                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3900         if (ses->capabilities & CAP_DFS)
3901                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3902
3903         if (ses->capabilities & CAP_UNICODE) {
3904                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3905                 name_len =
3906                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3907                                      searchName, PATH_MAX, nls_codepage, remap);
3908                 name_len++;     /* trailing null */
3909                 name_len *= 2;
3910         } else {        /* BB improve the check for buffer overruns BB */
3911                 name_len = strnlen(searchName, PATH_MAX);
3912                 name_len++;     /* trailing null */
3913                 strncpy(pSMB->RequestFileName, searchName, name_len);
3914         }
3915
3916         if (ses->server) {
3917                 if (ses->server->secMode &
3918                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3919                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3920         }
3921
3922         pSMB->hdr.Uid = ses->Suid;
3923
3924         params = 2 /* level */  + name_len /*includes null */ ;
3925         pSMB->TotalDataCount = 0;
3926         pSMB->DataCount = 0;
3927         pSMB->DataOffset = 0;
3928         pSMB->MaxParameterCount = 0;
3929         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3930         pSMB->MaxSetupCount = 0;
3931         pSMB->Reserved = 0;
3932         pSMB->Flags = 0;
3933         pSMB->Timeout = 0;
3934         pSMB->Reserved2 = 0;
3935         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3936           struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3937         pSMB->SetupCount = 1;
3938         pSMB->Reserved3 = 0;
3939         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3940         byte_count = params + 3 /* pad */ ;
3941         pSMB->ParameterCount = cpu_to_le16(params);
3942         pSMB->TotalParameterCount = pSMB->ParameterCount;
3943         pSMB->MaxReferralLevel = cpu_to_le16(3);
3944         pSMB->hdr.smb_buf_length += byte_count;
3945         pSMB->ByteCount = cpu_to_le16(byte_count);
3946
3947         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3948                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3949         if (rc) {
3950                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3951         } else {                /* decode response */
3952 /* BB Add logic to parse referrals here */
3953                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3954
3955                 /* BB Also check if enough total bytes returned? */
3956                 if (rc || (pSMBr->ByteCount < 17))
3957                         rc = -EIO;      /* bad smb */
3958                 else {
3959                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3960                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3961
3962                         cFYI(1,
3963                             ("Decoding GetDFSRefer response BCC: %d  Offset %d",
3964                               pSMBr->ByteCount, data_offset));
3965                         referrals =
3966                             (struct dfs_referral_level_3 *)
3967                                         (8 /* sizeof start of data block */ +
3968                                         data_offset +
3969                                         (char *) &pSMBr->hdr.Protocol);
3970                         cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3971                                 "for referral one refer size: 0x%x srv "
3972                                 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3973                                 le16_to_cpu(pSMBr->NumberOfReferrals),
3974                                 le16_to_cpu(pSMBr->DFSFlags),
3975                                 le16_to_cpu(referrals->ReferralSize),
3976                                 le16_to_cpu(referrals->ServerType),
3977                                 le16_to_cpu(referrals->ReferralFlags),
3978                                 le16_to_cpu(referrals->TimeToLive)));
3979                         /* BB This field is actually two bytes in from start of
3980                            data block so we could do safety check that DataBlock
3981                            begins at address of pSMBr->NumberOfReferrals */
3982                         *number_of_UNC_in_array =
3983                                         le16_to_cpu(pSMBr->NumberOfReferrals);
3984
3985                         /* BB Fix below so can return more than one referral */
3986                         if (*number_of_UNC_in_array > 1)
3987                                 *number_of_UNC_in_array = 1;
3988
3989                         /* get the length of the strings describing refs */
3990                         name_len = 0;
3991                         for (i = 0; i < *number_of_UNC_in_array; i++) {
3992                                 /* make sure that DfsPathOffset not past end */
3993                                 __u16 offset =
3994                                         le16_to_cpu(referrals->DfsPathOffset);
3995                                 if (offset > data_count) {
3996                                         /* if invalid referral, stop here and do
3997                                         not try to copy any more */
3998                                         *number_of_UNC_in_array = i;
3999                                         break;
4000                                 }
4001                                 temp = ((char *)referrals) + offset;
4002
4003                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4004                                         name_len += UniStrnlen((wchar_t *)temp,
4005                                                                 data_count);
4006                                 } else {
4007                                         name_len += strnlen(temp, data_count);
4008                                 }
4009                                 referrals++;
4010                                 /* BB add check that referral pointer does
4011                                    not fall off end PDU */
4012                         }
4013                         /* BB add check for name_len bigger than bcc */
4014                         *targetUNCs =
4015                                 kmalloc(name_len+1+(*number_of_UNC_in_array),
4016                                         GFP_KERNEL);
4017                         if (*targetUNCs == NULL) {
4018                                 rc = -ENOMEM;
4019                                 goto GetDFSRefExit;
4020                         }
4021                         /* copy the ref strings */
4022                         referrals = (struct dfs_referral_level_3 *)
4023                                         (8 /* sizeof data hdr */ + data_offset +
4024                                         (char *) &pSMBr->hdr.Protocol);
4025
4026                         for (i = 0; i < *number_of_UNC_in_array; i++) {
4027                                 temp = ((char *)referrals) +
4028                                           le16_to_cpu(referrals->DfsPathOffset);
4029                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4030                                         cifs_strfromUCS_le(*targetUNCs,
4031                                                           (__le16 *) temp,
4032                                                           name_len,
4033                                                           nls_codepage);
4034                                 } else {
4035                                         strncpy(*targetUNCs, temp, name_len);
4036                                 }
4037                                 /*  BB update target_uncs pointers */
4038                                 referrals++;
4039                         }
4040                         temp = *targetUNCs;
4041                         temp[name_len] = 0;
4042                 }
4043
4044         }
4045 GetDFSRefExit:
4046         if (pSMB)
4047                 cifs_buf_release(pSMB);
4048
4049         if (rc == -EAGAIN)
4050                 goto getDFSRetry;
4051
4052         return rc;
4053 }
4054
4055 /* Query File System Info such as free space to old servers such as Win 9x */
4056 int
4057 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4058 {
4059 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4060         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4061         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4062         FILE_SYSTEM_ALLOC_INFO *response_data;
4063         int rc = 0;
4064         int bytes_returned = 0;
4065         __u16 params, byte_count;
4066
4067         cFYI(1, ("OldQFSInfo"));
4068 oldQFSInfoRetry:
4069         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4070                 (void **) &pSMBr);
4071         if (rc)
4072                 return rc;
4073
4074         params = 2;     /* level */
4075         pSMB->TotalDataCount = 0;
4076         pSMB->MaxParameterCount = cpu_to_le16(2);
4077         pSMB->MaxDataCount = cpu_to_le16(1000);
4078         pSMB->MaxSetupCount = 0;
4079         pSMB->Reserved = 0;
4080         pSMB->Flags = 0;
4081         pSMB->Timeout = 0;
4082         pSMB->Reserved2 = 0;
4083         byte_count = params + 1 /* pad */ ;
4084         pSMB->TotalParameterCount = cpu_to_le16(params);
4085         pSMB->ParameterCount = pSMB->TotalParameterCount;
4086         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4087         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4088         pSMB->DataCount = 0;
4089         pSMB->DataOffset = 0;
4090         pSMB->SetupCount = 1;
4091         pSMB->Reserved3 = 0;
4092         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4093         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4094         pSMB->hdr.smb_buf_length += byte_count;
4095         pSMB->ByteCount = cpu_to_le16(byte_count);
4096
4097         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4098                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4099         if (rc) {
4100                 cFYI(1, ("Send error in QFSInfo = %d", rc));
4101         } else {                /* decode response */
4102                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4103
4104                 if (rc || (pSMBr->ByteCount < 18))
4105                         rc = -EIO;      /* bad smb */
4106                 else {
4107                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4108                         cFYI(1, ("qfsinf resp BCC: %d  Offset %d",
4109                                  pSMBr->ByteCount, data_offset));
4110
4111                         response_data = (FILE_SYSTEM_ALLOC_INFO *)
4112                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4113                         FSData->f_bsize =
4114                                 le16_to_cpu(response_data->BytesPerSector) *
4115                                 le32_to_cpu(response_data->
4116                                         SectorsPerAllocationUnit);
4117                         FSData->f_blocks =
4118                                le32_to_cpu(response_data->TotalAllocationUnits);
4119                         FSData->f_bfree = FSData->f_bavail =
4120                                 le32_to_cpu(response_data->FreeAllocationUnits);
4121                         cFYI(1,
4122                              ("Blocks: %lld  Free: %lld Block size %ld",
4123                               (unsigned long long)FSData->f_blocks,
4124                               (unsigned long long)FSData->f_bfree,
4125                               FSData->f_bsize));
4126                 }
4127         }
4128         cifs_buf_release(pSMB);
4129
4130         if (rc == -EAGAIN)
4131                 goto oldQFSInfoRetry;
4132
4133         return rc;
4134 }
4135
4136 int
4137 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4138 {
4139 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4140         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4141         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4142         FILE_SYSTEM_INFO *response_data;
4143         int rc = 0;
4144         int bytes_returned = 0;
4145         __u16 params, byte_count;
4146
4147         cFYI(1, ("In QFSInfo"));
4148 QFSInfoRetry:
4149         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150                       (void **) &pSMBr);
4151         if (rc)
4152                 return rc;
4153
4154         params = 2;     /* level */
4155         pSMB->TotalDataCount = 0;
4156         pSMB->MaxParameterCount = cpu_to_le16(2);
4157         pSMB->MaxDataCount = cpu_to_le16(1000);
4158         pSMB->MaxSetupCount = 0;
4159         pSMB->Reserved = 0;
4160         pSMB->Flags = 0;
4161         pSMB->Timeout = 0;
4162         pSMB->Reserved2 = 0;
4163         byte_count = params + 1 /* pad */ ;
4164         pSMB->TotalParameterCount = cpu_to_le16(params);
4165         pSMB->ParameterCount = pSMB->TotalParameterCount;
4166         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4167                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4168         pSMB->DataCount = 0;
4169         pSMB->DataOffset = 0;
4170         pSMB->SetupCount = 1;
4171         pSMB->Reserved3 = 0;
4172         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4173         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4174         pSMB->hdr.smb_buf_length += byte_count;
4175         pSMB->ByteCount = cpu_to_le16(byte_count);
4176
4177         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4178                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4179         if (rc) {
4180                 cFYI(1, ("Send error in QFSInfo = %d", rc));
4181         } else {                /* decode response */
4182                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4183
4184                 if (rc || (pSMBr->ByteCount < 24))
4185                         rc = -EIO;      /* bad smb */
4186                 else {
4187                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4188
4189                         response_data =
4190                             (FILE_SYSTEM_INFO
4191                              *) (((char *) &pSMBr->hdr.Protocol) +
4192                                  data_offset);
4193                         FSData->f_bsize =
4194                             le32_to_cpu(response_data->BytesPerSector) *
4195                             le32_to_cpu(response_data->
4196                                         SectorsPerAllocationUnit);
4197                         FSData->f_blocks =
4198                             le64_to_cpu(response_data->TotalAllocationUnits);
4199                         FSData->f_bfree = FSData->f_bavail =
4200                             le64_to_cpu(response_data->FreeAllocationUnits);
4201                         cFYI(1,
4202                              ("Blocks: %lld  Free: %lld Block size %ld",
4203                               (unsigned long long)FSData->f_blocks,
4204                               (unsigned long long)FSData->f_bfree,
4205                               FSData->f_bsize));
4206                 }
4207         }
4208         cifs_buf_release(pSMB);
4209
4210         if (rc == -EAGAIN)
4211                 goto QFSInfoRetry;
4212
4213         return rc;
4214 }
4215
4216 int
4217 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4218 {
4219 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
4220         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4221         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4222         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4223         int rc = 0;
4224         int bytes_returned = 0;
4225         __u16 params, byte_count;
4226
4227         cFYI(1, ("In QFSAttributeInfo"));
4228 QFSAttributeRetry:
4229         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4230                       (void **) &pSMBr);
4231         if (rc)
4232                 return rc;
4233
4234         params = 2;     /* level */
4235         pSMB->TotalDataCount = 0;
4236         pSMB->MaxParameterCount = cpu_to_le16(2);
4237         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4238         pSMB->MaxSetupCount = 0;
4239         pSMB->Reserved = 0;
4240         pSMB->Flags = 0;
4241         pSMB->Timeout = 0;
4242         pSMB->Reserved2 = 0;
4243         byte_count = params + 1 /* pad */ ;
4244         pSMB->TotalParameterCount = cpu_to_le16(params);
4245         pSMB->ParameterCount = pSMB->TotalParameterCount;
4246         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4247                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4248         pSMB->DataCount = 0;
4249         pSMB->DataOffset = 0;
4250         pSMB->SetupCount = 1;
4251         pSMB->Reserved3 = 0;
4252         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4253         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4254         pSMB->hdr.smb_buf_length += byte_count;
4255         pSMB->ByteCount = cpu_to_le16(byte_count);
4256
4257         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4258                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4259         if (rc) {
4260                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4261         } else {                /* decode response */
4262                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4263
4264                 if (rc || (pSMBr->ByteCount < 13)) {
4265                         /* BB also check if enough bytes returned */
4266                         rc = -EIO;      /* bad smb */
4267                 } else {
4268                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4269                         response_data =
4270                             (FILE_SYSTEM_ATTRIBUTE_INFO
4271                              *) (((char *) &pSMBr->hdr.Protocol) +
4272                                  data_offset);
4273                         memcpy(&tcon->fsAttrInfo, response_data,
4274                                sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4275                 }
4276         }
4277         cifs_buf_release(pSMB);
4278
4279         if (rc == -EAGAIN)
4280                 goto QFSAttributeRetry;
4281
4282         return rc;
4283 }
4284
4285 int
4286 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4287 {
4288 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4289         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4290         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4291         FILE_SYSTEM_DEVICE_INFO *response_data;
4292         int rc = 0;
4293         int bytes_returned = 0;
4294         __u16 params, byte_count;
4295
4296         cFYI(1, ("In QFSDeviceInfo"));
4297 QFSDeviceRetry:
4298         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4299                       (void **) &pSMBr);
4300         if (rc)
4301                 return rc;
4302
4303         params = 2;     /* level */
4304         pSMB->TotalDataCount = 0;
4305         pSMB->MaxParameterCount = cpu_to_le16(2);
4306         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4307         pSMB->MaxSetupCount = 0;
4308         pSMB->Reserved = 0;
4309         pSMB->Flags = 0;
4310         pSMB->Timeout = 0;
4311         pSMB->Reserved2 = 0;
4312         byte_count = params + 1 /* pad */ ;
4313         pSMB->TotalParameterCount = cpu_to_le16(params);
4314         pSMB->ParameterCount = pSMB->TotalParameterCount;
4315         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4316                 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4317
4318         pSMB->DataCount = 0;
4319         pSMB->DataOffset = 0;
4320         pSMB->SetupCount = 1;
4321         pSMB->Reserved3 = 0;
4322         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4323         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4324         pSMB->hdr.smb_buf_length += byte_count;
4325         pSMB->ByteCount = cpu_to_le16(byte_count);
4326
4327         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4328                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4329         if (rc) {
4330                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4331         } else {                /* decode response */
4332                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4333
4334                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4335                         rc = -EIO;      /* bad smb */
4336                 else {
4337                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4338                         response_data =
4339                             (FILE_SYSTEM_DEVICE_INFO *)
4340                                 (((char *) &pSMBr->hdr.Protocol) +
4341                                  data_offset);
4342                         memcpy(&tcon->fsDevInfo, response_data,
4343                                sizeof(FILE_SYSTEM_DEVICE_INFO));
4344                 }
4345         }
4346         cifs_buf_release(pSMB);
4347
4348         if (rc == -EAGAIN)
4349                 goto QFSDeviceRetry;
4350
4351         return rc;
4352 }
4353
4354 int
4355 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4356 {
4357 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
4358         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4359         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4360         FILE_SYSTEM_UNIX_INFO *response_data;
4361         int rc = 0;
4362         int bytes_returned = 0;
4363         __u16 params, byte_count;
4364
4365         cFYI(1, ("In QFSUnixInfo"));
4366 QFSUnixRetry:
4367         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4368                       (void **) &pSMBr);
4369         if (rc)
4370                 return rc;
4371
4372         params = 2;     /* level */
4373         pSMB->TotalDataCount = 0;
4374         pSMB->DataCount = 0;
4375         pSMB->DataOffset = 0;
4376         pSMB->MaxParameterCount = cpu_to_le16(2);
4377         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4378         pSMB->MaxSetupCount = 0;
4379         pSMB->Reserved = 0;
4380         pSMB->Flags = 0;
4381         pSMB->Timeout = 0;
4382         pSMB->Reserved2 = 0;
4383         byte_count = params + 1 /* pad */ ;
4384         pSMB->ParameterCount = cpu_to_le16(params);
4385         pSMB->TotalParameterCount = pSMB->ParameterCount;
4386         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4387                         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4388         pSMB->SetupCount = 1;
4389         pSMB->Reserved3 = 0;
4390         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4391         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4392         pSMB->hdr.smb_buf_length += byte_count;
4393         pSMB->ByteCount = cpu_to_le16(byte_count);
4394
4395         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4396                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4397         if (rc) {
4398                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4399         } else {                /* decode response */
4400                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4401
4402                 if (rc || (pSMBr->ByteCount < 13)) {
4403                         rc = -EIO;      /* bad smb */
4404                 } else {
4405                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4406                         response_data =
4407                             (FILE_SYSTEM_UNIX_INFO
4408                              *) (((char *) &pSMBr->hdr.Protocol) +
4409                                  data_offset);
4410                         memcpy(&tcon->fsUnixInfo, response_data,
4411                                sizeof(FILE_SYSTEM_UNIX_INFO));
4412                 }
4413         }
4414         cifs_buf_release(pSMB);
4415
4416         if (rc == -EAGAIN)
4417                 goto QFSUnixRetry;
4418
4419
4420         return rc;
4421 }
4422
4423 int
4424 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4425 {
4426 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
4427         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4428         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4429         int rc = 0;
4430         int bytes_returned = 0;
4431         __u16 params, param_offset, offset, byte_count;
4432
4433         cFYI(1, ("In SETFSUnixInfo"));
4434 SETFSUnixRetry:
4435         /* BB switch to small buf init to save memory */
4436         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4437                       (void **) &pSMBr);
4438         if (rc)
4439                 return rc;
4440
4441         params = 4;     /* 2 bytes zero followed by info level. */
4442         pSMB->MaxSetupCount = 0;
4443         pSMB->Reserved = 0;
4444         pSMB->Flags = 0;
4445         pSMB->Timeout = 0;
4446         pSMB->Reserved2 = 0;
4447         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4448                                 - 4;
4449         offset = param_offset + params;
4450
4451         pSMB->MaxParameterCount = cpu_to_le16(4);
4452         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4453         pSMB->SetupCount = 1;
4454         pSMB->Reserved3 = 0;
4455         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4456         byte_count = 1 /* pad */ + params + 12;
4457
4458         pSMB->DataCount = cpu_to_le16(12);
4459         pSMB->ParameterCount = cpu_to_le16(params);
4460         pSMB->TotalDataCount = pSMB->DataCount;
4461         pSMB->TotalParameterCount = pSMB->ParameterCount;
4462         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4463         pSMB->DataOffset = cpu_to_le16(offset);
4464
4465         /* Params. */
4466         pSMB->FileNum = 0;
4467         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4468
4469         /* Data. */
4470         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4471         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4472         pSMB->ClientUnixCap = cpu_to_le64(cap);
4473
4474         pSMB->hdr.smb_buf_length += byte_count;
4475         pSMB->ByteCount = cpu_to_le16(byte_count);
4476
4477         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4478                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4479         if (rc) {
4480                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4481         } else {                /* decode response */
4482                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4483                 if (rc) {
4484                         rc = -EIO;      /* bad smb */
4485                 }
4486         }
4487         cifs_buf_release(pSMB);
4488
4489         if (rc == -EAGAIN)
4490                 goto SETFSUnixRetry;
4491
4492         return rc;
4493 }
4494
4495
4496
4497 int
4498 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4499                    struct kstatfs *FSData)
4500 {
4501 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4502         TRANSACTION2_QFSI_REQ *pSMB = NULL;
4503         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4504         FILE_SYSTEM_POSIX_INFO *response_data;
4505         int rc = 0;
4506         int bytes_returned = 0;
4507         __u16 params, byte_count;
4508
4509         cFYI(1, ("In QFSPosixInfo"));
4510 QFSPosixRetry:
4511         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4512                       (void **) &pSMBr);
4513         if (rc)
4514                 return rc;
4515
4516         params = 2;     /* level */
4517         pSMB->TotalDataCount = 0;
4518         pSMB->DataCount = 0;
4519         pSMB->DataOffset = 0;
4520         pSMB->MaxParameterCount = cpu_to_le16(2);
4521         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
4522         pSMB->MaxSetupCount = 0;
4523         pSMB->Reserved = 0;
4524         pSMB->Flags = 0;
4525         pSMB->Timeout = 0;
4526         pSMB->Reserved2 = 0;
4527         byte_count = params + 1 /* pad */ ;
4528         pSMB->ParameterCount = cpu_to_le16(params);
4529         pSMB->TotalParameterCount = pSMB->ParameterCount;
4530         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4531                         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4532         pSMB->SetupCount = 1;
4533         pSMB->Reserved3 = 0;
4534         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4535         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4536         pSMB->hdr.smb_buf_length += byte_count;
4537         pSMB->ByteCount = cpu_to_le16(byte_count);
4538
4539         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4540                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4541         if (rc) {
4542                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4543         } else {                /* decode response */
4544                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4545
4546                 if (rc || (pSMBr->ByteCount < 13)) {
4547                         rc = -EIO;      /* bad smb */
4548                 } else {
4549                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4550                         response_data =
4551                             (FILE_SYSTEM_POSIX_INFO
4552                              *) (((char *) &pSMBr->hdr.Protocol) +
4553                                  data_offset);
4554                         FSData->f_bsize =
4555                                         le32_to_cpu(response_data->BlockSize);
4556                         FSData->f_blocks =
4557                                         le64_to_cpu(response_data->TotalBlocks);
4558                         FSData->f_bfree =
4559                             le64_to_cpu(response_data->BlocksAvail);
4560                         if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4561                                 FSData->f_bavail = FSData->f_bfree;
4562                         } else {
4563                                 FSData->f_bavail =
4564                                     le64_to_cpu(response_data->UserBlocksAvail);
4565                         }
4566                         if (response_data->TotalFileNodes != cpu_to_le64(-1))
4567                                 FSData->f_files =
4568                                      le64_to_cpu(response_data->TotalFileNodes);
4569                         if (response_data->FreeFileNodes != cpu_to_le64(-1))
4570                                 FSData->f_ffree =
4571                                       le64_to_cpu(response_data->FreeFileNodes);
4572                 }
4573         }
4574         cifs_buf_release(pSMB);
4575
4576         if (rc == -EAGAIN)
4577                 goto QFSPosixRetry;
4578
4579         return rc;
4580 }
4581
4582
4583 /* We can not use write of zero bytes trick to
4584    set file size due to need for large file support.  Also note that
4585    this SetPathInfo is preferred to SetFileInfo based method in next
4586    routine which is only needed to work around a sharing violation bug
4587    in Samba which this routine can run into */
4588
4589 int
4590 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4591               __u64 size, int SetAllocation,
4592               const struct nls_table *nls_codepage, int remap)
4593 {
4594         struct smb_com_transaction2_spi_req *pSMB = NULL;
4595         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4596         struct file_end_of_file_info *parm_data;
4597         int name_len;
4598         int rc = 0;
4599         int bytes_returned = 0;
4600         __u16 params, byte_count, data_count, param_offset, offset;
4601
4602         cFYI(1, ("In SetEOF"));
4603 SetEOFRetry:
4604         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4605                       (void **) &pSMBr);
4606         if (rc)
4607                 return rc;
4608
4609         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4610                 name_len =
4611                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4612                                      PATH_MAX, nls_codepage, remap);
4613                 name_len++;     /* trailing null */
4614                 name_len *= 2;
4615         } else {        /* BB improve the check for buffer overruns BB */
4616                 name_len = strnlen(fileName, PATH_MAX);
4617                 name_len++;     /* trailing null */
4618                 strncpy(pSMB->FileName, fileName, name_len);
4619         }
4620         params = 6 + name_len;
4621         data_count = sizeof(struct file_end_of_file_info);
4622         pSMB->MaxParameterCount = cpu_to_le16(2);
4623         pSMB->MaxDataCount = cpu_to_le16(4100);
4624         pSMB->MaxSetupCount = 0;
4625         pSMB->Reserved = 0;
4626         pSMB->Flags = 0;
4627         pSMB->Timeout = 0;
4628         pSMB->Reserved2 = 0;
4629         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4630                                 InformationLevel) - 4;
4631         offset = param_offset + params;
4632         if (SetAllocation) {
4633                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4634                         pSMB->InformationLevel =
4635                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4636                 else
4637                         pSMB->InformationLevel =
4638                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4639         } else /* Set File Size */  {
4640             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4641                     pSMB->InformationLevel =
4642                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4643             else
4644                     pSMB->InformationLevel =
4645                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4646         }
4647
4648         parm_data =
4649             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4650                                        offset);
4651         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4652         pSMB->DataOffset = cpu_to_le16(offset);
4653         pSMB->SetupCount = 1;
4654         pSMB->Reserved3 = 0;
4655         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4656         byte_count = 3 /* pad */  + params + data_count;
4657         pSMB->DataCount = cpu_to_le16(data_count);
4658         pSMB->TotalDataCount = pSMB->DataCount;
4659         pSMB->ParameterCount = cpu_to_le16(params);
4660         pSMB->TotalParameterCount = pSMB->ParameterCount;
4661         pSMB->Reserved4 = 0;
4662         pSMB->hdr.smb_buf_length += byte_count;
4663         parm_data->FileSize = cpu_to_le64(size);
4664         pSMB->ByteCount = cpu_to_le16(byte_count);
4665         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4666                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4667         if (rc) {
4668                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4669         }
4670
4671         cifs_buf_release(pSMB);
4672
4673         if (rc == -EAGAIN)
4674                 goto SetEOFRetry;
4675
4676         return rc;
4677 }
4678
4679 int
4680 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4681                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4682 {
4683         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4684         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4685         char *data_offset;
4686         struct file_end_of_file_info *parm_data;
4687         int rc = 0;
4688         int bytes_returned = 0;
4689         __u16 params, param_offset, offset, byte_count, count;
4690
4691         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4692                         (long long)size));
4693         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4694
4695         if (rc)
4696                 return rc;
4697
4698         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4699
4700         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4701         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4702
4703         params = 6;
4704         pSMB->MaxSetupCount = 0;
4705         pSMB->Reserved = 0;
4706         pSMB->Flags = 0;
4707         pSMB->Timeout = 0;
4708         pSMB->Reserved2 = 0;
4709         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4710         offset = param_offset + params;
4711
4712         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4713
4714         count = sizeof(struct file_end_of_file_info);
4715         pSMB->MaxParameterCount = cpu_to_le16(2);
4716         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4717         pSMB->SetupCount = 1;
4718         pSMB->Reserved3 = 0;
4719         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4720         byte_count = 3 /* pad */  + params + count;
4721         pSMB->DataCount = cpu_to_le16(count);
4722         pSMB->ParameterCount = cpu_to_le16(params);
4723         pSMB->TotalDataCount = pSMB->DataCount;
4724         pSMB->TotalParameterCount = pSMB->ParameterCount;
4725         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4726         parm_data =
4727                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4728                                 + offset);
4729         pSMB->DataOffset = cpu_to_le16(offset);
4730         parm_data->FileSize = cpu_to_le64(size);
4731         pSMB->Fid = fid;
4732         if (SetAllocation) {
4733                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4734                         pSMB->InformationLevel =
4735                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4736                 else
4737                         pSMB->InformationLevel =
4738                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4739         } else /* Set File Size */  {
4740             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4741                     pSMB->InformationLevel =
4742                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4743             else
4744                     pSMB->InformationLevel =
4745                                 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4746         }
4747         pSMB->Reserved4 = 0;
4748         pSMB->hdr.smb_buf_length += byte_count;
4749         pSMB->ByteCount = cpu_to_le16(byte_count);
4750         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4751                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4752         if (rc) {
4753                 cFYI(1,
4754                      ("Send error in SetFileInfo (SetFileSize) = %d",
4755                       rc));
4756         }
4757
4758         if (pSMB)
4759                 cifs_small_buf_release(pSMB);
4760
4761         /* Note: On -EAGAIN error only caller can retry on handle based calls
4762                 since file handle passed in no longer valid */
4763
4764         return rc;
4765 }
4766
4767 /* Some legacy servers such as NT4 require that the file times be set on
4768    an open handle, rather than by pathname - this is awkward due to
4769    potential access conflicts on the open, but it is unavoidable for these
4770    old servers since the only other choice is to go from 100 nanosecond DCE
4771    time and resort to the original setpathinfo level which takes the ancient
4772    DOS time format with 2 second granularity */
4773 int
4774 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4775                     const FILE_BASIC_INFO *data, __u16 fid)
4776 {
4777         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4778         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4779         char *data_offset;
4780         int rc = 0;
4781         int bytes_returned = 0;
4782         __u16 params, param_offset, offset, byte_count, count;
4783
4784         cFYI(1, ("Set Times (via SetFileInfo)"));
4785         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4786
4787         if (rc)
4788                 return rc;
4789
4790         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4791
4792         /* At this point there is no need to override the current pid
4793         with the pid of the opener, but that could change if we someday
4794         use an existing handle (rather than opening one on the fly) */
4795         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4796         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4797
4798         params = 6;
4799         pSMB->MaxSetupCount = 0;
4800         pSMB->Reserved = 0;
4801         pSMB->Flags = 0;
4802         pSMB->Timeout = 0;
4803         pSMB->Reserved2 = 0;
4804         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4805         offset = param_offset + params;
4806
4807         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4808
4809         count = sizeof(FILE_BASIC_INFO);
4810         pSMB->MaxParameterCount = cpu_to_le16(2);
4811         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4812         pSMB->SetupCount = 1;
4813         pSMB->Reserved3 = 0;
4814         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4815         byte_count = 3 /* pad */  + params + count;
4816         pSMB->DataCount = cpu_to_le16(count);
4817         pSMB->ParameterCount = cpu_to_le16(params);
4818         pSMB->TotalDataCount = pSMB->DataCount;
4819         pSMB->TotalParameterCount = pSMB->ParameterCount;
4820         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4821         pSMB->DataOffset = cpu_to_le16(offset);
4822         pSMB->Fid = fid;
4823         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4824                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4825         else
4826                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4827         pSMB->Reserved4 = 0;
4828         pSMB->hdr.smb_buf_length += byte_count;
4829         pSMB->ByteCount = cpu_to_le16(byte_count);
4830         memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4831         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4832                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4833         if (rc) {
4834                 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4835         }
4836
4837         cifs_small_buf_release(pSMB);
4838
4839         /* Note: On -EAGAIN error only caller can retry on handle based calls
4840                 since file handle passed in no longer valid */
4841
4842         return rc;
4843 }
4844
4845
4846 int
4847 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4848                 const FILE_BASIC_INFO *data,
4849                 const struct nls_table *nls_codepage, int remap)
4850 {
4851         TRANSACTION2_SPI_REQ *pSMB = NULL;
4852         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4853         int name_len;
4854         int rc = 0;
4855         int bytes_returned = 0;
4856         char *data_offset;
4857         __u16 params, param_offset, offset, byte_count, count;
4858
4859         cFYI(1, ("In SetTimes"));
4860
4861 SetTimesRetry:
4862         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4863                       (void **) &pSMBr);
4864         if (rc)
4865                 return rc;
4866
4867         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4868                 name_len =
4869                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4870                                      PATH_MAX, nls_codepage, remap);
4871                 name_len++;     /* trailing null */
4872                 name_len *= 2;
4873         } else {        /* BB improve the check for buffer overruns BB */
4874                 name_len = strnlen(fileName, PATH_MAX);
4875                 name_len++;     /* trailing null */
4876                 strncpy(pSMB->FileName, fileName, name_len);
4877         }
4878
4879         params = 6 + name_len;
4880         count = sizeof(FILE_BASIC_INFO);
4881         pSMB->MaxParameterCount = cpu_to_le16(2);
4882         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4883         pSMB->MaxSetupCount = 0;
4884         pSMB->Reserved = 0;
4885         pSMB->Flags = 0;
4886         pSMB->Timeout = 0;
4887         pSMB->Reserved2 = 0;
4888         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4889                                 InformationLevel) - 4;
4890         offset = param_offset + params;
4891         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4892         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4893         pSMB->DataOffset = cpu_to_le16(offset);
4894         pSMB->SetupCount = 1;
4895         pSMB->Reserved3 = 0;
4896         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4897         byte_count = 3 /* pad */  + params + count;
4898
4899         pSMB->DataCount = cpu_to_le16(count);
4900         pSMB->ParameterCount = cpu_to_le16(params);
4901         pSMB->TotalDataCount = pSMB->DataCount;
4902         pSMB->TotalParameterCount = pSMB->ParameterCount;
4903         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4904                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4905         else
4906                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4907         pSMB->Reserved4 = 0;
4908         pSMB->hdr.smb_buf_length += byte_count;
4909         memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4910         pSMB->ByteCount = cpu_to_le16(byte_count);
4911         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4912                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4913         if (rc) {
4914                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4915         }
4916
4917         cifs_buf_release(pSMB);
4918
4919         if (rc == -EAGAIN)
4920                 goto SetTimesRetry;
4921
4922         return rc;
4923 }
4924
4925 /* Can not be used to set time stamps yet (due to old DOS time format) */
4926 /* Can be used to set attributes */
4927 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4928           handling it anyway and NT4 was what we thought it would be needed for
4929           Do not delete it until we prove whether needed for Win9x though */
4930 int
4931 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4932                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4933 {
4934         SETATTR_REQ *pSMB = NULL;
4935         SETATTR_RSP *pSMBr = NULL;
4936         int rc = 0;
4937         int bytes_returned;
4938         int name_len;
4939
4940         cFYI(1, ("In SetAttrLegacy"));
4941
4942 SetAttrLgcyRetry:
4943         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4944                       (void **) &pSMBr);
4945         if (rc)
4946                 return rc;
4947
4948         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4949                 name_len =
4950                         ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4951                                 PATH_MAX, nls_codepage);
4952                 name_len++;     /* trailing null */
4953                 name_len *= 2;
4954         } else {        /* BB improve the check for buffer overruns BB */
4955                 name_len = strnlen(fileName, PATH_MAX);
4956                 name_len++;     /* trailing null */
4957                 strncpy(pSMB->fileName, fileName, name_len);
4958         }
4959         pSMB->attr = cpu_to_le16(dos_attrs);
4960         pSMB->BufferFormat = 0x04;
4961         pSMB->hdr.smb_buf_length += name_len + 1;
4962         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4963         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4964                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4965         if (rc) {
4966                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4967         }
4968
4969         cifs_buf_release(pSMB);
4970
4971         if (rc == -EAGAIN)
4972                 goto SetAttrLgcyRetry;
4973
4974         return rc;
4975 }
4976 #endif /* temporarily unneeded SetAttr legacy function */
4977
4978 int
4979 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4980                     char *fileName, __u64 mode, __u64 uid, __u64 gid,
4981                     dev_t device, const struct nls_table *nls_codepage,
4982                     int remap)
4983 {
4984         TRANSACTION2_SPI_REQ *pSMB = NULL;
4985         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4986         int name_len;
4987         int rc = 0;
4988         int bytes_returned = 0;
4989         FILE_UNIX_BASIC_INFO *data_offset;
4990         __u16 params, param_offset, offset, count, byte_count;
4991
4992         cFYI(1, ("In SetUID/GID/Mode"));
4993 setPermsRetry:
4994         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4995                       (void **) &pSMBr);
4996         if (rc)
4997                 return rc;
4998
4999         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5000                 name_len =
5001                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5002                                      PATH_MAX, nls_codepage, remap);
5003                 name_len++;     /* trailing null */
5004                 name_len *= 2;
5005         } else {        /* BB improve the check for buffer overruns BB */
5006                 name_len = strnlen(fileName, PATH_MAX);
5007                 name_len++;     /* trailing null */
5008                 strncpy(pSMB->FileName, fileName, name_len);
5009         }
5010
5011         params = 6 + name_len;
5012         count = sizeof(FILE_UNIX_BASIC_INFO);
5013         pSMB->MaxParameterCount = cpu_to_le16(2);
5014         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5015         pSMB->MaxSetupCount = 0;
5016         pSMB->Reserved = 0;
5017         pSMB->Flags = 0;
5018         pSMB->Timeout = 0;
5019         pSMB->Reserved2 = 0;
5020         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5021                                 InformationLevel) - 4;
5022         offset = param_offset + params;
5023         data_offset =
5024             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5025                                       offset);
5026         memset(data_offset, 0, count);
5027         pSMB->DataOffset = cpu_to_le16(offset);
5028         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5029         pSMB->SetupCount = 1;
5030         pSMB->Reserved3 = 0;
5031         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5032         byte_count = 3 /* pad */  + params + count;
5033         pSMB->ParameterCount = cpu_to_le16(params);
5034         pSMB->DataCount = cpu_to_le16(count);
5035         pSMB->TotalParameterCount = pSMB->ParameterCount;
5036         pSMB->TotalDataCount = pSMB->DataCount;
5037         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5038         pSMB->Reserved4 = 0;
5039         pSMB->hdr.smb_buf_length += byte_count;
5040         /* Samba server ignores set of file size to zero due to bugs in some
5041         older clients, but we should be precise - we use SetFileSize to
5042         set file size and do not want to truncate file size to zero
5043         accidently as happened on one Samba server beta by putting
5044         zero instead of -1 here */
5045         data_offset->EndOfFile = NO_CHANGE_64;
5046         data_offset->NumOfBytes = NO_CHANGE_64;
5047         data_offset->LastStatusChange = NO_CHANGE_64;
5048         data_offset->LastAccessTime = NO_CHANGE_64;
5049         data_offset->LastModificationTime = NO_CHANGE_64;
5050         data_offset->Uid = cpu_to_le64(uid);
5051         data_offset->Gid = cpu_to_le64(gid);
5052         /* better to leave device as zero when it is  */
5053         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5054         data_offset->DevMinor = cpu_to_le64(MINOR(device));
5055         data_offset->Permissions = cpu_to_le64(mode);
5056
5057         if (S_ISREG(mode))
5058                 data_offset->Type = cpu_to_le32(UNIX_FILE);
5059         else if (S_ISDIR(mode))
5060                 data_offset->Type = cpu_to_le32(UNIX_DIR);
5061         else if (S_ISLNK(mode))
5062                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5063         else if (S_ISCHR(mode))
5064                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5065         else if (S_ISBLK(mode))
5066                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5067         else if (S_ISFIFO(mode))
5068                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5069         else if (S_ISSOCK(mode))
5070                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5071
5072
5073         pSMB->ByteCount = cpu_to_le16(byte_count);
5074         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5075                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5076         if (rc) {
5077                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5078         }
5079
5080         if (pSMB)
5081                 cifs_buf_release(pSMB);
5082         if (rc == -EAGAIN)
5083                 goto setPermsRetry;
5084         return rc;
5085 }
5086
5087 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5088                   const int notify_subdirs, const __u16 netfid,
5089                   __u32 filter, struct file *pfile, int multishot,
5090                   const struct nls_table *nls_codepage)
5091 {
5092         int rc = 0;
5093         struct smb_com_transaction_change_notify_req *pSMB = NULL;
5094         struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5095         struct dir_notify_req *dnotify_req;
5096         int bytes_returned;
5097
5098         cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5099         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5100                       (void **) &pSMBr);
5101         if (rc)
5102                 return rc;
5103
5104         pSMB->TotalParameterCount = 0 ;
5105         pSMB->TotalDataCount = 0;
5106         pSMB->MaxParameterCount = cpu_to_le32(2);
5107         /* BB find exact data count max from sess structure BB */
5108         pSMB->MaxDataCount = 0; /* same in little endian or be */
5109 /* BB VERIFY verify which is correct for above BB */
5110         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5111                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5112
5113         pSMB->MaxSetupCount = 4;
5114         pSMB->Reserved = 0;
5115         pSMB->ParameterOffset = 0;
5116         pSMB->DataCount = 0;
5117         pSMB->DataOffset = 0;
5118         pSMB->SetupCount = 4; /* single byte does not need le conversion */
5119         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5120         pSMB->ParameterCount = pSMB->TotalParameterCount;
5121         if (notify_subdirs)
5122                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5123         pSMB->Reserved2 = 0;
5124         pSMB->CompletionFilter = cpu_to_le32(filter);
5125         pSMB->Fid = netfid; /* file handle always le */
5126         pSMB->ByteCount = 0;
5127
5128         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5129                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5130         if (rc) {
5131                 cFYI(1, ("Error in Notify = %d", rc));
5132         } else {
5133                 /* Add file to outstanding requests */
5134                 /* BB change to kmem cache alloc */
5135                 dnotify_req = kmalloc(
5136                                                 sizeof(struct dir_notify_req),
5137                                                  GFP_KERNEL);
5138                 if (dnotify_req) {
5139                         dnotify_req->Pid = pSMB->hdr.Pid;
5140                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5141                         dnotify_req->Mid = pSMB->hdr.Mid;
5142                         dnotify_req->Tid = pSMB->hdr.Tid;
5143                         dnotify_req->Uid = pSMB->hdr.Uid;
5144                         dnotify_req->netfid = netfid;
5145                         dnotify_req->pfile = pfile;
5146                         dnotify_req->filter = filter;
5147                         dnotify_req->multishot = multishot;
5148                         spin_lock(&GlobalMid_Lock);
5149                         list_add_tail(&dnotify_req->lhead,
5150                                         &GlobalDnotifyReqList);
5151                         spin_unlock(&GlobalMid_Lock);
5152                 } else
5153                         rc = -ENOMEM;
5154         }
5155         cifs_buf_release(pSMB);
5156         return rc;
5157 }
5158 #ifdef CONFIG_CIFS_XATTR
5159 ssize_t
5160 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5161                  const unsigned char *searchName,
5162                  char *EAData, size_t buf_size,
5163                  const struct nls_table *nls_codepage, int remap)
5164 {
5165                 /* BB assumes one setup word */
5166         TRANSACTION2_QPI_REQ *pSMB = NULL;
5167         TRANSACTION2_QPI_RSP *pSMBr = NULL;
5168         int rc = 0;
5169         int bytes_returned;
5170         int name_len;
5171         struct fea *temp_fea;
5172         char *temp_ptr;
5173         __u16 params, byte_count;
5174
5175         cFYI(1, ("In Query All EAs path %s", searchName));
5176 QAllEAsRetry:
5177         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5178                       (void **) &pSMBr);
5179         if (rc)
5180                 return rc;
5181
5182         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5183                 name_len =
5184                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5185                                      PATH_MAX, nls_codepage, remap);
5186                 name_len++;     /* trailing null */
5187                 name_len *= 2;
5188         } else {        /* BB improve the check for buffer overruns BB */
5189                 name_len = strnlen(searchName, PATH_MAX);
5190                 name_len++;     /* trailing null */
5191                 strncpy(pSMB->FileName, searchName, name_len);
5192         }
5193
5194         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5195         pSMB->TotalDataCount = 0;
5196         pSMB->MaxParameterCount = cpu_to_le16(2);
5197         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5198         pSMB->MaxSetupCount = 0;
5199         pSMB->Reserved = 0;
5200         pSMB->Flags = 0;
5201         pSMB->Timeout = 0;
5202         pSMB->Reserved2 = 0;
5203         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5204         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5205         pSMB->DataCount = 0;
5206         pSMB->DataOffset = 0;
5207         pSMB->SetupCount = 1;
5208         pSMB->Reserved3 = 0;
5209         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5210         byte_count = params + 1 /* pad */ ;
5211         pSMB->TotalParameterCount = cpu_to_le16(params);
5212         pSMB->ParameterCount = pSMB->TotalParameterCount;
5213         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5214         pSMB->Reserved4 = 0;
5215         pSMB->hdr.smb_buf_length += byte_count;
5216         pSMB->ByteCount = cpu_to_le16(byte_count);
5217
5218         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5219                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5220         if (rc) {
5221                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5222         } else {                /* decode response */
5223                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5224
5225                 /* BB also check enough total bytes returned */
5226                 /* BB we need to improve the validity checking
5227                 of these trans2 responses */
5228                 if (rc || (pSMBr->ByteCount < 4))
5229                         rc = -EIO;      /* bad smb */
5230            /* else if (pFindData){
5231                         memcpy((char *) pFindData,
5232                                (char *) &pSMBr->hdr.Protocol +
5233                                data_offset, kl);
5234                 }*/ else {
5235                         /* check that length of list is not more than bcc */
5236                         /* check that each entry does not go beyond length
5237                            of list */
5238                         /* check that each element of each entry does not
5239                            go beyond end of list */
5240                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5241                         struct fealist *ea_response_data;
5242                         rc = 0;
5243                         /* validate_trans2_offsets() */
5244                         /* BB check if start of smb + data_offset > &bcc+ bcc */
5245                         ea_response_data = (struct fealist *)
5246                                 (((char *) &pSMBr->hdr.Protocol) +
5247                                 data_offset);
5248                         name_len = le32_to_cpu(ea_response_data->list_len);
5249                         cFYI(1, ("ea length %d", name_len));
5250                         if (name_len <= 8) {
5251                         /* returned EA size zeroed at top of function */
5252                                 cFYI(1, ("empty EA list returned from server"));
5253                         } else {
5254                                 /* account for ea list len */
5255                                 name_len -= 4;
5256                                 temp_fea = ea_response_data->list;
5257                                 temp_ptr = (char *)temp_fea;
5258                                 while (name_len > 0) {
5259                                         __u16 value_len;
5260                                         name_len -= 4;
5261                                         temp_ptr += 4;
5262                                         rc += temp_fea->name_len;
5263                                 /* account for prefix user. and trailing null */
5264                                         rc = rc + 5 + 1;
5265                                         if (rc < (int)buf_size) {
5266                                                 memcpy(EAData, "user.", 5);
5267                                                 EAData += 5;
5268                                                 memcpy(EAData, temp_ptr,
5269                                                        temp_fea->name_len);
5270                                                 EAData += temp_fea->name_len;
5271                                                 /* null terminate name */
5272                                                 *EAData = 0;
5273                                                 EAData = EAData + 1;
5274                                         } else if (buf_size == 0) {
5275                                                 /* skip copy - calc size only */
5276                                         } else {
5277                                                 /* stop before overrun buffer */
5278                                                 rc = -ERANGE;
5279                                                 break;
5280                                         }
5281                                         name_len -= temp_fea->name_len;
5282                                         temp_ptr += temp_fea->name_len;
5283                                         /* account for trailing null */
5284                                         name_len--;
5285                                         temp_ptr++;
5286                                         value_len =
5287                                               le16_to_cpu(temp_fea->value_len);
5288                                         name_len -= value_len;
5289                                         temp_ptr += value_len;
5290                                         /* BB check that temp_ptr is still
5291                                               within the SMB BB*/
5292
5293                                         /* no trailing null to account for
5294                                            in value len */
5295                                         /* go on to next EA */
5296                                         temp_fea = (struct fea *)temp_ptr;
5297                                 }
5298                         }
5299                 }
5300         }
5301         if (pSMB)
5302                 cifs_buf_release(pSMB);
5303         if (rc == -EAGAIN)
5304                 goto QAllEAsRetry;
5305
5306         return (ssize_t)rc;
5307 }
5308
5309 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5310                 const unsigned char *searchName, const unsigned char *ea_name,
5311                 unsigned char *ea_value, size_t buf_size,
5312                 const struct nls_table *nls_codepage, int remap)
5313 {
5314         TRANSACTION2_QPI_REQ *pSMB = NULL;
5315         TRANSACTION2_QPI_RSP *pSMBr = NULL;
5316         int rc = 0;
5317         int bytes_returned;
5318         int name_len;
5319         struct fea *temp_fea;
5320         char *temp_ptr;
5321         __u16 params, byte_count;
5322
5323         cFYI(1, ("In Query EA path %s", searchName));
5324 QEARetry:
5325         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5326                       (void **) &pSMBr);
5327         if (rc)
5328                 return rc;
5329
5330         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5331                 name_len =
5332                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5333                                      PATH_MAX, nls_codepage, remap);
5334                 name_len++;     /* trailing null */
5335                 name_len *= 2;
5336         } else {        /* BB improve the check for buffer overruns BB */
5337                 name_len = strnlen(searchName, PATH_MAX);
5338                 name_len++;     /* trailing null */
5339                 strncpy(pSMB->FileName, searchName, name_len);
5340         }
5341
5342         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5343         pSMB->TotalDataCount = 0;
5344         pSMB->MaxParameterCount = cpu_to_le16(2);
5345         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5346         pSMB->MaxSetupCount = 0;
5347         pSMB->Reserved = 0;
5348         pSMB->Flags = 0;
5349         pSMB->Timeout = 0;
5350         pSMB->Reserved2 = 0;
5351         pSMB->ParameterOffset = cpu_to_le16(offsetof(
5352                 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5353         pSMB->DataCount = 0;
5354         pSMB->DataOffset = 0;
5355         pSMB->SetupCount = 1;
5356         pSMB->Reserved3 = 0;
5357         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5358         byte_count = params + 1 /* pad */ ;
5359         pSMB->TotalParameterCount = cpu_to_le16(params);
5360         pSMB->ParameterCount = pSMB->TotalParameterCount;
5361         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5362         pSMB->Reserved4 = 0;
5363         pSMB->hdr.smb_buf_length += byte_count;
5364         pSMB->ByteCount = cpu_to_le16(byte_count);
5365
5366         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5367                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5368         if (rc) {
5369                 cFYI(1, ("Send error in Query EA = %d", rc));
5370         } else {                /* decode response */
5371                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5372
5373                 /* BB also check enough total bytes returned */
5374                 /* BB we need to improve the validity checking
5375                 of these trans2 responses */
5376                 if (rc || (pSMBr->ByteCount < 4))
5377                         rc = -EIO;      /* bad smb */
5378            /* else if (pFindData){
5379                         memcpy((char *) pFindData,
5380                                (char *) &pSMBr->hdr.Protocol +
5381                                data_offset, kl);
5382                 }*/ else {
5383                         /* check that length of list is not more than bcc */
5384                         /* check that each entry does not go beyond length
5385                            of list */
5386                         /* check that each element of each entry does not
5387                            go beyond end of list */
5388                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5389                         struct fealist *ea_response_data;
5390                         rc = -ENODATA;
5391                         /* validate_trans2_offsets() */
5392                         /* BB check if start of smb + data_offset > &bcc+ bcc*/
5393                         ea_response_data = (struct fealist *)
5394                                 (((char *) &pSMBr->hdr.Protocol) +
5395                                 data_offset);
5396                         name_len = le32_to_cpu(ea_response_data->list_len);
5397                         cFYI(1, ("ea length %d", name_len));
5398                         if (name_len <= 8) {
5399                         /* returned EA size zeroed at top of function */
5400                                 cFYI(1, ("empty EA list returned from server"));
5401                         } else {
5402                                 /* account for ea list len */
5403                                 name_len -= 4;
5404                                 temp_fea = ea_response_data->list;
5405                                 temp_ptr = (char *)temp_fea;
5406                                 /* loop through checking if we have a matching
5407                                 name and then return the associated value */
5408                                 while (name_len > 0) {
5409                                         __u16 value_len;
5410                                         name_len -= 4;
5411                                         temp_ptr += 4;
5412                                         value_len =
5413                                               le16_to_cpu(temp_fea->value_len);
5414                                 /* BB validate that value_len falls within SMB,
5415                                 even though maximum for name_len is 255 */
5416                                         if (memcmp(temp_fea->name, ea_name,
5417                                                   temp_fea->name_len) == 0) {
5418                                                 /* found a match */
5419                                                 rc = value_len;
5420                                 /* account for prefix user. and trailing null */
5421                                                 if (rc <= (int)buf_size) {
5422                                                         memcpy(ea_value,
5423                                                                 temp_fea->name+temp_fea->name_len+1,
5424                                                                 rc);
5425                                                         /* ea values, unlike ea
5426                                                            names, are not null
5427                                                            terminated */
5428                                                 } else if (buf_size == 0) {
5429                                                 /* skip copy - calc size only */
5430                                                 } else {
5431                                                 /* stop before overrun buffer */
5432                                                         rc = -ERANGE;
5433                                                 }
5434                                                 break;
5435                                         }
5436                                         name_len -= temp_fea->name_len;
5437                                         temp_ptr += temp_fea->name_len;
5438                                         /* account for trailing null */
5439                                         name_len--;
5440                                         temp_ptr++;
5441                                         name_len -= value_len;
5442                                         temp_ptr += value_len;
5443                                         /* No trailing null to account for in
5444                                            value_len.  Go on to next EA */
5445                                         temp_fea = (struct fea *)temp_ptr;
5446                                 }
5447                         }
5448                 }
5449         }
5450         if (pSMB)
5451                 cifs_buf_release(pSMB);
5452         if (rc == -EAGAIN)
5453                 goto QEARetry;
5454
5455         return (ssize_t)rc;
5456 }
5457
5458 int
5459 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5460              const char *ea_name, const void *ea_value,
5461              const __u16 ea_value_len, const struct nls_table *nls_codepage,
5462              int remap)
5463 {
5464         struct smb_com_transaction2_spi_req *pSMB = NULL;
5465         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5466         struct fealist *parm_data;
5467         int name_len;
5468         int rc = 0;
5469         int bytes_returned = 0;
5470         __u16 params, param_offset, byte_count, offset, count;
5471
5472         cFYI(1, ("In SetEA"));
5473 SetEARetry:
5474         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5475                       (void **) &pSMBr);
5476         if (rc)
5477                 return rc;
5478
5479         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5480                 name_len =
5481                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5482                                      PATH_MAX, nls_codepage, remap);
5483                 name_len++;     /* trailing null */
5484                 name_len *= 2;
5485         } else {        /* BB improve the check for buffer overruns BB */
5486                 name_len = strnlen(fileName, PATH_MAX);
5487                 name_len++;     /* trailing null */
5488                 strncpy(pSMB->FileName, fileName, name_len);
5489         }
5490
5491         params = 6 + name_len;
5492
5493         /* done calculating parms using name_len of file name,
5494         now use name_len to calculate length of ea name
5495         we are going to create in the inode xattrs */
5496         if (ea_name == NULL)
5497                 name_len = 0;
5498         else
5499                 name_len = strnlen(ea_name, 255);
5500
5501         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5502         pSMB->MaxParameterCount = cpu_to_le16(2);
5503         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5504         pSMB->MaxSetupCount = 0;
5505         pSMB->Reserved = 0;
5506         pSMB->Flags = 0;
5507         pSMB->Timeout = 0;
5508         pSMB->Reserved2 = 0;
5509         param_offset = offsetof(struct smb_com_transaction2_spi_req,
5510                                 InformationLevel) - 4;
5511         offset = param_offset + params;
5512         pSMB->InformationLevel =
5513                 cpu_to_le16(SMB_SET_FILE_EA);
5514
5515         parm_data =
5516                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5517                                        offset);
5518         pSMB->ParameterOffset = cpu_to_le16(param_offset);
5519         pSMB->DataOffset = cpu_to_le16(offset);
5520         pSMB->SetupCount = 1;
5521         pSMB->Reserved3 = 0;
5522         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5523         byte_count = 3 /* pad */  + params + count;
5524         pSMB->DataCount = cpu_to_le16(count);
5525         parm_data->list_len = cpu_to_le32(count);
5526         parm_data->list[0].EA_flags = 0;
5527         /* we checked above that name len is less than 255 */
5528         parm_data->list[0].name_len = (__u8)name_len;
5529         /* EA names are always ASCII */
5530         if (ea_name)
5531                 strncpy(parm_data->list[0].name, ea_name, name_len);
5532         parm_data->list[0].name[name_len] = 0;
5533         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5534         /* caller ensures that ea_value_len is less than 64K but
5535         we need to ensure that it fits within the smb */
5536
5537         /*BB add length check to see if it would fit in
5538              negotiated SMB buffer size BB */
5539         /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5540         if (ea_value_len)
5541                 memcpy(parm_data->list[0].name+name_len+1,
5542                        ea_value, ea_value_len);
5543
5544         pSMB->TotalDataCount = pSMB->DataCount;
5545         pSMB->ParameterCount = cpu_to_le16(params);
5546         pSMB->TotalParameterCount = pSMB->ParameterCount;
5547         pSMB->Reserved4 = 0;
5548         pSMB->hdr.smb_buf_length += byte_count;
5549         pSMB->ByteCount = cpu_to_le16(byte_count);
5550         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5551                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5552         if (rc) {
5553                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5554         }
5555
5556         cifs_buf_release(pSMB);
5557
5558         if (rc == -EAGAIN)
5559                 goto SetEARetry;
5560
5561         return rc;
5562 }
5563
5564 #endif