f15848374cfa1a8897db63c81ea6cf7e2bdacce5
[pandora-kernel.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2008
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly differently for reconnection purposes since we never     */
28  /* want to reuse a stale file handle and only the caller knows the file info */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsacl.h"
38 #include "cifsproto.h"
39 #include "cifs_unicode.h"
40 #include "cifs_debug.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44         int index;
45         char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48         {LANMAN_PROT, "\2LM1.2X002"},
49         {LANMAN2_PROT, "\2LANMAN2.1"},
50 #endif /* weak password hashing for legacy clients */
51         {CIFS_PROT, "\2NT LM 0.12"},
52         {POSIX_PROT, "\2POSIX 2"},
53         {BAD_PROT, "\2"}
54 };
55 #else
56 static struct {
57         int index;
58         char *name;
59 } protocols[] = {
60 #ifdef CONFIG_CIFS_WEAK_PW_HASH
61         {LANMAN_PROT, "\2LM1.2X002"},
62         {LANMAN2_PROT, "\2LANMAN2.1"},
63 #endif /* weak password hashing for legacy clients */
64         {CIFS_PROT, "\2NT LM 0.12"},
65         {BAD_PROT, "\2"}
66 };
67 #endif
68
69 /* define the number of elements in the cifs dialect array */
70 #ifdef CONFIG_CIFS_POSIX
71 #ifdef CONFIG_CIFS_WEAK_PW_HASH
72 #define CIFS_NUM_PROT 4
73 #else
74 #define CIFS_NUM_PROT 2
75 #endif /* CIFS_WEAK_PW_HASH */
76 #else /* not posix */
77 #ifdef CONFIG_CIFS_WEAK_PW_HASH
78 #define CIFS_NUM_PROT 3
79 #else
80 #define CIFS_NUM_PROT 1
81 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
82 #endif /* CIFS_POSIX */
83
84 /* Mark as invalid, all open files on tree connections since they
85    were closed when session to server was lost */
86 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
87 {
88         struct cifsFileInfo *open_file = NULL;
89         struct list_head *tmp;
90         struct list_head *tmp1;
91
92 /* list all files open on tree connection and mark them invalid */
93         write_lock(&GlobalSMBSeslock);
94         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
95                 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
96                 open_file->invalidHandle = true;
97         }
98         write_unlock(&GlobalSMBSeslock);
99         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100            to this tcon */
101 }
102
103 /* Allocate and return pointer to an SMB request buffer, and set basic
104    SMB information in the SMB header.  If the return code is zero, this
105    function must have filled in request_buf pointer */
106 static int
107 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108                 void **request_buf)
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 ||
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->need_reconnect)
159                                 rc = cifs_setup_session(0, tcon->ses,
160                                                         nls_codepage);
161                         if (!rc && (tcon->need_reconnect)) {
162                                 mark_open_files_invalid(tcon);
163                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
164                                               tcon, nls_codepage);
165                                 up(&tcon->ses->sesSem);
166                                 /* BB FIXME add code to check if wsize needs
167                                    update due to negotiated smb buffer size
168                                    shrinking */
169                                 if (rc == 0) {
170                                         atomic_inc(&tconInfoReconnectCount);
171                                         /* tell server Unix caps we support */
172                                         if (tcon->ses->capabilities & CAP_UNIX)
173                                                 reset_cifs_unix_caps(
174                                                 0 /* no xid */,
175                                                 tcon,
176                                                 NULL /* we do not know sb */,
177                                                 NULL /* no vol info */);
178                                 }
179
180                                 cFYI(1, ("reconnect tcon rc = %d", rc));
181                                 /* Removed call to reopen open files here.
182                                    It is safer (and faster) to reopen files
183                                    one at a time as needed in read and write */
184
185                                 /* Check if handle based operation so we
186                                    know whether we can continue or not without
187                                    returning to caller to reset file handle */
188                                 switch (smb_command) {
189                                         case SMB_COM_READ_ANDX:
190                                         case SMB_COM_WRITE_ANDX:
191                                         case SMB_COM_CLOSE:
192                                         case SMB_COM_FIND_CLOSE2:
193                                         case SMB_COM_LOCKING_ANDX: {
194                                                 unload_nls(nls_codepage);
195                                                 return -EAGAIN;
196                                         }
197                                 }
198                         } else {
199                                 up(&tcon->ses->sesSem);
200                         }
201                         unload_nls(nls_codepage);
202
203                 } else {
204                         return -EIO;
205                 }
206         }
207         if (rc)
208                 return rc;
209
210         *request_buf = cifs_small_buf_get();
211         if (*request_buf == NULL) {
212                 /* BB should we add a retry in here if not a writepage? */
213                 return -ENOMEM;
214         }
215
216         header_assemble((struct smb_hdr *) *request_buf, smb_command,
217                         tcon, wct);
218
219         if (tcon != NULL)
220                 cifs_stats_inc(&tcon->num_smbs_sent);
221
222         return rc;
223 }
224
225 int
226 small_smb_init_no_tc(const int smb_command, const int wct,
227                      struct cifsSesInfo *ses, void **request_buf)
228 {
229         int rc;
230         struct smb_hdr *buffer;
231
232         rc = small_smb_init(smb_command, wct, NULL, request_buf);
233         if (rc)
234                 return rc;
235
236         buffer = (struct smb_hdr *)*request_buf;
237         buffer->Mid = GetNextMid(ses->server);
238         if (ses->capabilities & CAP_UNICODE)
239                 buffer->Flags2 |= SMBFLG2_UNICODE;
240         if (ses->capabilities & CAP_STATUS32)
241                 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
242
243         /* uid, tid can stay at zero as set in header assemble */
244
245         /* BB add support for turning on the signing when
246         this function is used after 1st of session setup requests */
247
248         return rc;
249 }
250
251 /* If the return code is zero, this function must fill in request_buf pointer */
252 static int
253 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
254          void **request_buf /* returned */ ,
255          void **response_buf /* returned */ )
256 {
257         int rc = 0;
258
259         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
260            check for tcp and smb session status done differently
261            for those three - in the calling routine */
262         if (tcon) {
263                 if (tcon->tidStatus == CifsExiting) {
264                         /* only tree disconnect, open, and write,
265                           (and ulogoff which does not have tcon)
266                           are allowed as we start force umount */
267                         if ((smb_command != SMB_COM_WRITE_ANDX) &&
268                            (smb_command != SMB_COM_OPEN_ANDX) &&
269                            (smb_command != SMB_COM_TREE_DISCONNECT)) {
270                                 cFYI(1, ("can not send cmd %d while umounting",
271                                         smb_command));
272                                 return -ENODEV;
273                         }
274                 }
275
276                 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
277                                   (tcon->ses->server)) {
278                         struct nls_table *nls_codepage;
279                                 /* Give Demultiplex thread up to 10 seconds to
280                                    reconnect, should be greater than cifs socket
281                                    timeout which is 7 seconds */
282                         while (tcon->ses->server->tcpStatus ==
283                                                         CifsNeedReconnect) {
284                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
285                                         (tcon->ses->server->tcpStatus ==
286                                                         CifsGood), 10 * HZ);
287                                 if (tcon->ses->server->tcpStatus ==
288                                                 CifsNeedReconnect) {
289                                         /* on "soft" mounts we wait once */
290                                         if (!tcon->retry ||
291                                            (tcon->ses->status == CifsExiting)) {
292                                                 cFYI(1, ("gave up waiting on "
293                                                       "reconnect in smb_init"));
294                                                 return -EHOSTDOWN;
295                                         } /* else "hard" mount - keep retrying
296                                              until process is killed or server
297                                              comes on-line */
298                                 } else /* TCP session is reestablished now */
299                                         break;
300                         }
301                         nls_codepage = load_nls_default();
302                 /* need to prevent multiple threads trying to
303                 simultaneously reconnect the same SMB session */
304                         down(&tcon->ses->sesSem);
305                         if (tcon->ses->need_reconnect)
306                                 rc = cifs_setup_session(0, tcon->ses,
307                                                         nls_codepage);
308                         if (!rc && (tcon->need_reconnect)) {
309                                 mark_open_files_invalid(tcon);
310                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
311                                               tcon, nls_codepage);
312                                 up(&tcon->ses->sesSem);
313                                 /* BB FIXME add code to check if wsize needs
314                                 update due to negotiated smb buffer size
315                                 shrinking */
316                                 if (rc == 0) {
317                                         atomic_inc(&tconInfoReconnectCount);
318                                         /* tell server Unix caps we support */
319                                         if (tcon->ses->capabilities & CAP_UNIX)
320                                                 reset_cifs_unix_caps(
321                                                 0 /* no xid */,
322                                                 tcon,
323                                                 NULL /* do not know sb */,
324                                                 NULL /* no vol info */);
325                                 }
326
327                                 cFYI(1, ("reconnect tcon rc = %d", rc));
328                                 /* Removed call to reopen open files here.
329                                    It is safer (and faster) to reopen files
330                                    one at a time as needed in read and write */
331
332                                 /* Check if handle based operation so we
333                                    know whether we can continue or not without
334                                    returning to caller to reset file handle */
335                                 switch (smb_command) {
336                                         case SMB_COM_READ_ANDX:
337                                         case SMB_COM_WRITE_ANDX:
338                                         case SMB_COM_CLOSE:
339                                         case SMB_COM_FIND_CLOSE2:
340                                         case SMB_COM_LOCKING_ANDX: {
341                                                 unload_nls(nls_codepage);
342                                                 return -EAGAIN;
343                                         }
344                                 }
345                         } else {
346                                 up(&tcon->ses->sesSem);
347                         }
348                         unload_nls(nls_codepage);
349
350                 } else {
351                         return -EIO;
352                 }
353         }
354         if (rc)
355                 return rc;
356
357         *request_buf = cifs_buf_get();
358         if (*request_buf == NULL) {
359                 /* BB should we add a retry in here if not a writepage? */
360                 return -ENOMEM;
361         }
362     /* Although the original thought was we needed the response buf for  */
363     /* potential retries of smb operations it turns out we can determine */
364     /* from the mid flags when the request buffer can be resent without  */
365     /* having to use a second distinct buffer for the response */
366         if (response_buf)
367                 *response_buf = *request_buf;
368
369         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
370                         wct);
371
372         if (tcon != NULL)
373                 cifs_stats_inc(&tcon->num_smbs_sent);
374
375         return rc;
376 }
377
378 static int validate_t2(struct smb_t2_rsp *pSMB)
379 {
380         int rc = -EINVAL;
381         int total_size;
382         char *pBCC;
383
384         /* check for plausible wct, bcc and t2 data and parm sizes */
385         /* check for parm and data offset going beyond end of smb */
386         if (pSMB->hdr.WordCount >= 10) {
387                 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
388                    (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
389                         /* check that bcc is at least as big as parms + data */
390                         /* check that bcc is less than negotiated smb buffer */
391                         total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
392                         if (total_size < 512) {
393                                 total_size +=
394                                         le16_to_cpu(pSMB->t2_rsp.DataCount);
395                                 /* BCC le converted in SendReceive */
396                                 pBCC = (pSMB->hdr.WordCount * 2) +
397                                         sizeof(struct smb_hdr) +
398                                         (char *)pSMB;
399                                 if ((total_size <= (*(u16 *)pBCC)) &&
400                                    (total_size <
401                                         CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
402                                         return 0;
403                                 }
404                         }
405                 }
406         }
407         cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
408                 sizeof(struct smb_t2_rsp) + 16);
409         return rc;
410 }
411 int
412 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
413 {
414         NEGOTIATE_REQ *pSMB;
415         NEGOTIATE_RSP *pSMBr;
416         int rc = 0;
417         int bytes_returned;
418         int i;
419         struct TCP_Server_Info *server;
420         u16 count;
421         unsigned int secFlags;
422         u16 dialect;
423
424         if (ses->server)
425                 server = ses->server;
426         else {
427                 rc = -EIO;
428                 return rc;
429         }
430         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
431                       (void **) &pSMB, (void **) &pSMBr);
432         if (rc)
433                 return rc;
434
435         /* if any of auth flags (ie not sign or seal) are overriden use them */
436         if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
437                 secFlags = ses->overrideSecFlg;  /* BB FIXME fix sign flags? */
438         else /* if override flags set only sign/seal OR them with global auth */
439                 secFlags = extended_security | ses->overrideSecFlg;
440
441         cFYI(1, ("secFlags 0x%x", secFlags));
442
443         pSMB->hdr.Mid = GetNextMid(server);
444         pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
445
446         if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
447                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
448         else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
449                 cFYI(1, ("Kerberos only mechanism, enable extended security"));
450                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
451         }
452
453         count = 0;
454         for (i = 0; i < CIFS_NUM_PROT; i++) {
455                 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
456                 count += strlen(protocols[i].name) + 1;
457                 /* null at end of source and target buffers anyway */
458         }
459         pSMB->hdr.smb_buf_length += count;
460         pSMB->ByteCount = cpu_to_le16(count);
461
462         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
463                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
464         if (rc != 0)
465                 goto neg_err_exit;
466
467         dialect = le16_to_cpu(pSMBr->DialectIndex);
468         cFYI(1, ("Dialect: %d", dialect));
469         /* Check wct = 1 error case */
470         if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
471                 /* core returns wct = 1, but we do not ask for core - otherwise
472                 small wct just comes when dialect index is -1 indicating we
473                 could not negotiate a common dialect */
474                 rc = -EOPNOTSUPP;
475                 goto neg_err_exit;
476 #ifdef CONFIG_CIFS_WEAK_PW_HASH
477         } else if ((pSMBr->hdr.WordCount == 13)
478                         && ((dialect == LANMAN_PROT)
479                                 || (dialect == LANMAN2_PROT))) {
480                 __s16 tmp;
481                 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
482
483                 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
484                         (secFlags & CIFSSEC_MAY_PLNTXT))
485                         server->secType = LANMAN;
486                 else {
487                         cERROR(1, ("mount failed weak security disabled"
488                                    " in /proc/fs/cifs/SecurityFlags"));
489                         rc = -EOPNOTSUPP;
490                         goto neg_err_exit;
491                 }
492                 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
493                 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
494                 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
495                                 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
496                 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
497                 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
498                 /* even though we do not use raw we might as well set this
499                 accurately, in case we ever find a need for it */
500                 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
501                         server->max_rw = 0xFF00;
502                         server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
503                 } else {
504                         server->max_rw = 0;/* do not need to use raw anyway */
505                         server->capabilities = CAP_MPX_MODE;
506                 }
507                 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
508                 if (tmp == -1) {
509                         /* OS/2 often does not set timezone therefore
510                          * we must use server time to calc time zone.
511                          * Could deviate slightly from the right zone.
512                          * Smallest defined timezone difference is 15 minutes
513                          * (i.e. Nepal).  Rounding up/down is done to match
514                          * this requirement.
515                          */
516                         int val, seconds, remain, result;
517                         struct timespec ts, utc;
518                         utc = CURRENT_TIME;
519                         ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
520                                                 le16_to_cpu(rsp->SrvTime.Time));
521                         cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
522                                 (int)ts.tv_sec, (int)utc.tv_sec,
523                                 (int)(utc.tv_sec - ts.tv_sec)));
524                         val = (int)(utc.tv_sec - ts.tv_sec);
525                         seconds = abs(val);
526                         result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
527                         remain = seconds % MIN_TZ_ADJ;
528                         if (remain >= (MIN_TZ_ADJ / 2))
529                                 result += MIN_TZ_ADJ;
530                         if (val < 0)
531                                 result = -result;
532                         server->timeAdj = result;
533                 } else {
534                         server->timeAdj = (int)tmp;
535                         server->timeAdj *= 60; /* also in seconds */
536                 }
537                 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
538
539
540                 /* BB get server time for time conversions and add
541                 code to use it and timezone since this is not UTC */
542
543                 if (rsp->EncryptionKeyLength ==
544                                 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
545                         memcpy(server->cryptKey, rsp->EncryptionKey,
546                                 CIFS_CRYPTO_KEY_SIZE);
547                 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
548                         rc = -EIO; /* need cryptkey unless plain text */
549                         goto neg_err_exit;
550                 }
551
552                 cFYI(1, ("LANMAN negotiated"));
553                 /* we will not end up setting signing flags - as no signing
554                 was in LANMAN and server did not return the flags on */
555                 goto signing_check;
556 #else /* weak security disabled */
557         } else if (pSMBr->hdr.WordCount == 13) {
558                 cERROR(1, ("mount failed, cifs module not built "
559                           "with CIFS_WEAK_PW_HASH support"));
560                         rc = -EOPNOTSUPP;
561 #endif /* WEAK_PW_HASH */
562                 goto neg_err_exit;
563         } else if (pSMBr->hdr.WordCount != 17) {
564                 /* unknown wct */
565                 rc = -EOPNOTSUPP;
566                 goto neg_err_exit;
567         }
568         /* else wct == 17 NTLM */
569         server->secMode = pSMBr->SecurityMode;
570         if ((server->secMode & SECMODE_USER) == 0)
571                 cFYI(1, ("share mode security"));
572
573         if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
574 #ifdef CONFIG_CIFS_WEAK_PW_HASH
575                 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
576 #endif /* CIFS_WEAK_PW_HASH */
577                         cERROR(1, ("Server requests plain text password"
578                                   " but client support disabled"));
579
580         if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
581                 server->secType = NTLMv2;
582         else if (secFlags & CIFSSEC_MAY_NTLM)
583                 server->secType = NTLM;
584         else if (secFlags & CIFSSEC_MAY_NTLMV2)
585                 server->secType = NTLMv2;
586         else if (secFlags & CIFSSEC_MAY_KRB5)
587                 server->secType = Kerberos;
588         else if (secFlags & CIFSSEC_MAY_LANMAN)
589                 server->secType = LANMAN;
590 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
591         else if (secFlags & CIFSSEC_MAY_PLNTXT)
592                 server->secType = ??
593 #endif */
594         else {
595                 rc = -EOPNOTSUPP;
596                 cERROR(1, ("Invalid security type"));
597                 goto neg_err_exit;
598         }
599         /* else ... any others ...? */
600
601         /* one byte, so no need to convert this or EncryptionKeyLen from
602            little endian */
603         server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
604         /* probably no need to store and check maxvcs */
605         server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
606                         (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
607         server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
608         cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
609         GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
610         server->capabilities = le32_to_cpu(pSMBr->Capabilities);
611         server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
612         server->timeAdj *= 60;
613         if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
614                 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
615                        CIFS_CRYPTO_KEY_SIZE);
616         } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
617                         && (pSMBr->EncryptionKeyLength == 0)) {
618                 /* decode security blob */
619         } else if (server->secMode & SECMODE_PW_ENCRYPT) {
620                 rc = -EIO; /* no crypt key only if plain text pwd */
621                 goto neg_err_exit;
622         }
623
624         /* BB might be helpful to save off the domain of server here */
625
626         if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
627                 (server->capabilities & CAP_EXTENDED_SECURITY)) {
628                 count = pSMBr->ByteCount;
629                 if (count < 16) {
630                         rc = -EIO;
631                         goto neg_err_exit;
632                 }
633                 read_lock(&cifs_tcp_ses_lock);
634                 if (server->srv_count > 1) {
635                         read_unlock(&cifs_tcp_ses_lock);
636                         if (memcmp(server->server_GUID,
637                                    pSMBr->u.extended_response.
638                                    GUID, 16) != 0) {
639                                 cFYI(1, ("server UID changed"));
640                                 memcpy(server->server_GUID,
641                                         pSMBr->u.extended_response.GUID,
642                                         16);
643                         }
644                 } else {
645                         read_unlock(&cifs_tcp_ses_lock);
646                         memcpy(server->server_GUID,
647                                pSMBr->u.extended_response.GUID, 16);
648                 }
649
650                 if (count == 16) {
651                         server->secType = RawNTLMSSP;
652                 } else {
653                         rc = decode_negTokenInit(pSMBr->u.extended_response.
654                                                  SecurityBlob,
655                                                  count - 16,
656                                                  &server->secType);
657                         if (rc == 1)
658                                 rc = 0;
659                         else
660                                 rc = -EINVAL;
661                 }
662         } else
663                 server->capabilities &= ~CAP_EXTENDED_SECURITY;
664
665 #ifdef CONFIG_CIFS_WEAK_PW_HASH
666 signing_check:
667 #endif
668         if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
669                 /* MUST_SIGN already includes the MAY_SIGN FLAG
670                    so if this is zero it means that signing is disabled */
671                 cFYI(1, ("Signing disabled"));
672                 if (server->secMode & SECMODE_SIGN_REQUIRED) {
673                         cERROR(1, ("Server requires "
674                                    "packet signing to be enabled in "
675                                    "/proc/fs/cifs/SecurityFlags."));
676                         rc = -EOPNOTSUPP;
677                 }
678                 server->secMode &=
679                         ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
680         } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
681                 /* signing required */
682                 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
683                 if ((server->secMode &
684                         (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
685                         cERROR(1,
686                                 ("signing required but server lacks support"));
687                         rc = -EOPNOTSUPP;
688                 } else
689                         server->secMode |= SECMODE_SIGN_REQUIRED;
690         } else {
691                 /* signing optional ie CIFSSEC_MAY_SIGN */
692                 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
693                         server->secMode &=
694                                 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
695         }
696
697 neg_err_exit:
698         cifs_buf_release(pSMB);
699
700         cFYI(1, ("negprot rc %d", rc));
701         return rc;
702 }
703
704 int
705 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
706 {
707         struct smb_hdr *smb_buffer;
708         int rc = 0;
709
710         cFYI(1, ("In tree disconnect"));
711
712         /* BB: do we need to check this? These should never be NULL. */
713         if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
714                 return -EIO;
715
716         /*
717          * No need to return error on this operation if tid invalidated and
718          * closed on server already e.g. due to tcp session crashing. Also,
719          * the tcon is no longer on the list, so no need to take lock before
720          * checking this.
721          */
722         if (tcon->need_reconnect)
723                 return 0;
724
725         rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
726                             (void **)&smb_buffer);
727         if (rc)
728                 return rc;
729
730         rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
731         if (rc)
732                 cFYI(1, ("Tree disconnect failed %d", rc));
733
734         /* No need to return error on this operation if tid invalidated and
735            closed on server already e.g. due to tcp session crashing */
736         if (rc == -EAGAIN)
737                 rc = 0;
738
739         return rc;
740 }
741
742 int
743 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
744 {
745         LOGOFF_ANDX_REQ *pSMB;
746         int rc = 0;
747
748         cFYI(1, ("In SMBLogoff for session disconnect"));
749
750         /*
751          * BB: do we need to check validity of ses and server? They should
752          * always be valid since we have an active reference. If not, that
753          * should probably be a BUG()
754          */
755         if (!ses || !ses->server)
756                 return -EIO;
757
758         down(&ses->sesSem);
759         if (ses->need_reconnect)
760                 goto session_already_dead; /* no need to send SMBlogoff if uid
761                                               already closed due to reconnect */
762         rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
763         if (rc) {
764                 up(&ses->sesSem);
765                 return rc;
766         }
767
768         pSMB->hdr.Mid = GetNextMid(ses->server);
769
770         if (ses->server->secMode &
771                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
772                         pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
773
774         pSMB->hdr.Uid = ses->Suid;
775
776         pSMB->AndXCommand = 0xFF;
777         rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
778 session_already_dead:
779         up(&ses->sesSem);
780
781         /* if session dead then we do not need to do ulogoff,
782                 since server closed smb session, no sense reporting
783                 error */
784         if (rc == -EAGAIN)
785                 rc = 0;
786         return rc;
787 }
788
789 int
790 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
791                  __u16 type, const struct nls_table *nls_codepage, int remap)
792 {
793         TRANSACTION2_SPI_REQ *pSMB = NULL;
794         TRANSACTION2_SPI_RSP *pSMBr = NULL;
795         struct unlink_psx_rq *pRqD;
796         int name_len;
797         int rc = 0;
798         int bytes_returned = 0;
799         __u16 params, param_offset, offset, byte_count;
800
801         cFYI(1, ("In POSIX delete"));
802 PsxDelete:
803         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
804                       (void **) &pSMBr);
805         if (rc)
806                 return rc;
807
808         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
809                 name_len =
810                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
811                                      PATH_MAX, nls_codepage, remap);
812                 name_len++;     /* trailing null */
813                 name_len *= 2;
814         } else { /* BB add path length overrun check */
815                 name_len = strnlen(fileName, PATH_MAX);
816                 name_len++;     /* trailing null */
817                 strncpy(pSMB->FileName, fileName, name_len);
818         }
819
820         params = 6 + name_len;
821         pSMB->MaxParameterCount = cpu_to_le16(2);
822         pSMB->MaxDataCount = 0; /* BB double check this with jra */
823         pSMB->MaxSetupCount = 0;
824         pSMB->Reserved = 0;
825         pSMB->Flags = 0;
826         pSMB->Timeout = 0;
827         pSMB->Reserved2 = 0;
828         param_offset = offsetof(struct smb_com_transaction2_spi_req,
829                                 InformationLevel) - 4;
830         offset = param_offset + params;
831
832         /* Setup pointer to Request Data (inode type) */
833         pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
834         pRqD->type = cpu_to_le16(type);
835         pSMB->ParameterOffset = cpu_to_le16(param_offset);
836         pSMB->DataOffset = cpu_to_le16(offset);
837         pSMB->SetupCount = 1;
838         pSMB->Reserved3 = 0;
839         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
840         byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq);
841
842         pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
843         pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
844         pSMB->ParameterCount = cpu_to_le16(params);
845         pSMB->TotalParameterCount = pSMB->ParameterCount;
846         pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
847         pSMB->Reserved4 = 0;
848         pSMB->hdr.smb_buf_length += byte_count;
849         pSMB->ByteCount = cpu_to_le16(byte_count);
850         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
851                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
852         if (rc)
853                 cFYI(1, ("Posix delete returned %d", rc));
854         cifs_buf_release(pSMB);
855
856         cifs_stats_inc(&tcon->num_deletes);
857
858         if (rc == -EAGAIN)
859                 goto PsxDelete;
860
861         return rc;
862 }
863
864 int
865 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
866                const struct nls_table *nls_codepage, int remap)
867 {
868         DELETE_FILE_REQ *pSMB = NULL;
869         DELETE_FILE_RSP *pSMBr = NULL;
870         int rc = 0;
871         int bytes_returned;
872         int name_len;
873
874 DelFileRetry:
875         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
876                       (void **) &pSMBr);
877         if (rc)
878                 return rc;
879
880         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
881                 name_len =
882                     cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
883                                      PATH_MAX, nls_codepage, remap);
884                 name_len++;     /* trailing null */
885                 name_len *= 2;
886         } else {                /* BB improve check for buffer overruns BB */
887                 name_len = strnlen(fileName, PATH_MAX);
888                 name_len++;     /* trailing null */
889                 strncpy(pSMB->fileName, fileName, name_len);
890         }
891         pSMB->SearchAttributes =
892             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
893         pSMB->BufferFormat = 0x04;
894         pSMB->hdr.smb_buf_length += name_len + 1;
895         pSMB->ByteCount = cpu_to_le16(name_len + 1);
896         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
897                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
898         cifs_stats_inc(&tcon->num_deletes);
899         if (rc)
900                 cFYI(1, ("Error in RMFile = %d", rc));
901
902         cifs_buf_release(pSMB);
903         if (rc == -EAGAIN)
904                 goto DelFileRetry;
905
906         return rc;
907 }
908
909 int
910 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
911              const struct nls_table *nls_codepage, int remap)
912 {
913         DELETE_DIRECTORY_REQ *pSMB = NULL;
914         DELETE_DIRECTORY_RSP *pSMBr = NULL;
915         int rc = 0;
916         int bytes_returned;
917         int name_len;
918
919         cFYI(1, ("In CIFSSMBRmDir"));
920 RmDirRetry:
921         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
922                       (void **) &pSMBr);
923         if (rc)
924                 return rc;
925
926         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
927                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
928                                          PATH_MAX, nls_codepage, remap);
929                 name_len++;     /* trailing null */
930                 name_len *= 2;
931         } else {                /* BB improve check for buffer overruns BB */
932                 name_len = strnlen(dirName, PATH_MAX);
933                 name_len++;     /* trailing null */
934                 strncpy(pSMB->DirName, dirName, name_len);
935         }
936
937         pSMB->BufferFormat = 0x04;
938         pSMB->hdr.smb_buf_length += name_len + 1;
939         pSMB->ByteCount = cpu_to_le16(name_len + 1);
940         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
942         cifs_stats_inc(&tcon->num_rmdirs);
943         if (rc)
944                 cFYI(1, ("Error in RMDir = %d", rc));
945
946         cifs_buf_release(pSMB);
947         if (rc == -EAGAIN)
948                 goto RmDirRetry;
949         return rc;
950 }
951
952 int
953 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
954              const char *name, const struct nls_table *nls_codepage, int remap)
955 {
956         int rc = 0;
957         CREATE_DIRECTORY_REQ *pSMB = NULL;
958         CREATE_DIRECTORY_RSP *pSMBr = NULL;
959         int bytes_returned;
960         int name_len;
961
962         cFYI(1, ("In CIFSSMBMkDir"));
963 MkDirRetry:
964         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
965                       (void **) &pSMBr);
966         if (rc)
967                 return rc;
968
969         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
970                 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
971                                             PATH_MAX, nls_codepage, remap);
972                 name_len++;     /* trailing null */
973                 name_len *= 2;
974         } else {                /* BB improve check for buffer overruns BB */
975                 name_len = strnlen(name, PATH_MAX);
976                 name_len++;     /* trailing null */
977                 strncpy(pSMB->DirName, name, name_len);
978         }
979
980         pSMB->BufferFormat = 0x04;
981         pSMB->hdr.smb_buf_length += name_len + 1;
982         pSMB->ByteCount = cpu_to_le16(name_len + 1);
983         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
984                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
985         cifs_stats_inc(&tcon->num_mkdirs);
986         if (rc)
987                 cFYI(1, ("Error in Mkdir = %d", rc));
988
989         cifs_buf_release(pSMB);
990         if (rc == -EAGAIN)
991                 goto MkDirRetry;
992         return rc;
993 }
994
995 int
996 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
997                 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
998                 __u32 *pOplock, const char *name,
999                 const struct nls_table *nls_codepage, int remap)
1000 {
1001         TRANSACTION2_SPI_REQ *pSMB = NULL;
1002         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1003         int name_len;
1004         int rc = 0;
1005         int bytes_returned = 0;
1006         __u16 params, param_offset, offset, byte_count, count;
1007         OPEN_PSX_REQ *pdata;
1008         OPEN_PSX_RSP *psx_rsp;
1009
1010         cFYI(1, ("In POSIX Create"));
1011 PsxCreat:
1012         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1013                       (void **) &pSMBr);
1014         if (rc)
1015                 return rc;
1016
1017         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1018                 name_len =
1019                     cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1020                                      PATH_MAX, nls_codepage, remap);
1021                 name_len++;     /* trailing null */
1022                 name_len *= 2;
1023         } else {        /* BB improve the check for buffer overruns BB */
1024                 name_len = strnlen(name, PATH_MAX);
1025                 name_len++;     /* trailing null */
1026                 strncpy(pSMB->FileName, name, name_len);
1027         }
1028
1029         params = 6 + name_len;
1030         count = sizeof(OPEN_PSX_REQ);
1031         pSMB->MaxParameterCount = cpu_to_le16(2);
1032         pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1033         pSMB->MaxSetupCount = 0;
1034         pSMB->Reserved = 0;
1035         pSMB->Flags = 0;
1036         pSMB->Timeout = 0;
1037         pSMB->Reserved2 = 0;
1038         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1039                                 InformationLevel) - 4;
1040         offset = param_offset + params;
1041         pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1042         pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1043         pdata->Permissions = cpu_to_le64(mode);
1044         pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1045         pdata->OpenFlags =  cpu_to_le32(*pOplock);
1046         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1047         pSMB->DataOffset = cpu_to_le16(offset);
1048         pSMB->SetupCount = 1;
1049         pSMB->Reserved3 = 0;
1050         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1051         byte_count = 3 /* pad */  + params + count;
1052
1053         pSMB->DataCount = cpu_to_le16(count);
1054         pSMB->ParameterCount = cpu_to_le16(params);
1055         pSMB->TotalDataCount = pSMB->DataCount;
1056         pSMB->TotalParameterCount = pSMB->ParameterCount;
1057         pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1058         pSMB->Reserved4 = 0;
1059         pSMB->hdr.smb_buf_length += byte_count;
1060         pSMB->ByteCount = cpu_to_le16(byte_count);
1061         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1062                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1063         if (rc) {
1064                 cFYI(1, ("Posix create returned %d", rc));
1065                 goto psx_create_err;
1066         }
1067
1068         cFYI(1, ("copying inode info"));
1069         rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1070
1071         if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1072                 rc = -EIO;      /* bad smb */
1073                 goto psx_create_err;
1074         }
1075
1076         /* copy return information to pRetData */
1077         psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1078                         + le16_to_cpu(pSMBr->t2.DataOffset));
1079
1080         *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1081         if (netfid)
1082                 *netfid = psx_rsp->Fid;   /* cifs fid stays in le */
1083         /* Let caller know file was created so we can set the mode. */
1084         /* Do we care about the CreateAction in any other cases? */
1085         if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1086                 *pOplock |= CIFS_CREATE_ACTION;
1087         /* check to make sure response data is there */
1088         if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1089                 pRetData->Type = cpu_to_le32(-1); /* unknown */
1090                 cFYI(DBG2, ("unknown type"));
1091         } else {
1092                 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1093                                         + sizeof(FILE_UNIX_BASIC_INFO)) {
1094                         cERROR(1, ("Open response data too small"));
1095                         pRetData->Type = cpu_to_le32(-1);
1096                         goto psx_create_err;
1097                 }
1098                 memcpy((char *) pRetData,
1099                         (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1100                         sizeof(FILE_UNIX_BASIC_INFO));
1101         }
1102
1103 psx_create_err:
1104         cifs_buf_release(pSMB);
1105
1106         cifs_stats_inc(&tcon->num_mkdirs);
1107
1108         if (rc == -EAGAIN)
1109                 goto PsxCreat;
1110
1111         return rc;
1112 }
1113
1114 static __u16 convert_disposition(int disposition)
1115 {
1116         __u16 ofun = 0;
1117
1118         switch (disposition) {
1119                 case FILE_SUPERSEDE:
1120                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1121                         break;
1122                 case FILE_OPEN:
1123                         ofun = SMBOPEN_OAPPEND;
1124                         break;
1125                 case FILE_CREATE:
1126                         ofun = SMBOPEN_OCREATE;
1127                         break;
1128                 case FILE_OPEN_IF:
1129                         ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1130                         break;
1131                 case FILE_OVERWRITE:
1132                         ofun = SMBOPEN_OTRUNC;
1133                         break;
1134                 case FILE_OVERWRITE_IF:
1135                         ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1136                         break;
1137                 default:
1138                         cFYI(1, ("unknown disposition %d", disposition));
1139                         ofun =  SMBOPEN_OAPPEND; /* regular open */
1140         }
1141         return ofun;
1142 }
1143
1144 static int
1145 access_flags_to_smbopen_mode(const int access_flags)
1146 {
1147         int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1148
1149         if (masked_flags == GENERIC_READ)
1150                 return SMBOPEN_READ;
1151         else if (masked_flags == GENERIC_WRITE)
1152                 return SMBOPEN_WRITE;
1153
1154         /* just go for read/write */
1155         return SMBOPEN_READWRITE;
1156 }
1157
1158 int
1159 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1160             const char *fileName, const int openDisposition,
1161             const int access_flags, const int create_options, __u16 *netfid,
1162             int *pOplock, FILE_ALL_INFO *pfile_info,
1163             const struct nls_table *nls_codepage, int remap)
1164 {
1165         int rc = -EACCES;
1166         OPENX_REQ *pSMB = NULL;
1167         OPENX_RSP *pSMBr = NULL;
1168         int bytes_returned;
1169         int name_len;
1170         __u16 count;
1171
1172 OldOpenRetry:
1173         rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1174                       (void **) &pSMBr);
1175         if (rc)
1176                 return rc;
1177
1178         pSMB->AndXCommand = 0xFF;       /* none */
1179
1180         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1181                 count = 1;      /* account for one byte pad to word boundary */
1182                 name_len =
1183                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1184                                     fileName, PATH_MAX, nls_codepage, remap);
1185                 name_len++;     /* trailing null */
1186                 name_len *= 2;
1187         } else {                /* BB improve check for buffer overruns BB */
1188                 count = 0;      /* no pad */
1189                 name_len = strnlen(fileName, PATH_MAX);
1190                 name_len++;     /* trailing null */
1191                 strncpy(pSMB->fileName, fileName, name_len);
1192         }
1193         if (*pOplock & REQ_OPLOCK)
1194                 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1195         else if (*pOplock & REQ_BATCHOPLOCK)
1196                 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1197
1198         pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1199         pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1200         pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1201         /* set file as system file if special file such
1202            as fifo and server expecting SFU style and
1203            no Unix extensions */
1204
1205         if (create_options & CREATE_OPTION_SPECIAL)
1206                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1207         else /* BB FIXME BB */
1208                 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1209
1210         if (create_options & CREATE_OPTION_READONLY)
1211                 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1212
1213         /* BB FIXME BB */
1214 /*      pSMB->CreateOptions = cpu_to_le32(create_options &
1215                                                  CREATE_OPTIONS_MASK); */
1216         /* BB FIXME END BB */
1217
1218         pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1219         pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1220         count += name_len;
1221         pSMB->hdr.smb_buf_length += count;
1222
1223         pSMB->ByteCount = cpu_to_le16(count);
1224         /* long_op set to 1 to allow for oplock break timeouts */
1225         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1226                         (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1227         cifs_stats_inc(&tcon->num_opens);
1228         if (rc) {
1229                 cFYI(1, ("Error in Open = %d", rc));
1230         } else {
1231         /* BB verify if wct == 15 */
1232
1233 /*              *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1234
1235                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1236                 /* Let caller know file was created so we can set the mode. */
1237                 /* Do we care about the CreateAction in any other cases? */
1238         /* BB FIXME BB */
1239 /*              if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1240                         *pOplock |= CIFS_CREATE_ACTION; */
1241         /* BB FIXME END */
1242
1243                 if (pfile_info) {
1244                         pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1245                         pfile_info->LastAccessTime = 0; /* BB fixme */
1246                         pfile_info->LastWriteTime = 0; /* BB fixme */
1247                         pfile_info->ChangeTime = 0;  /* BB fixme */
1248                         pfile_info->Attributes =
1249                                 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1250                         /* the file_info buf is endian converted by caller */
1251                         pfile_info->AllocationSize =
1252                                 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1253                         pfile_info->EndOfFile = pfile_info->AllocationSize;
1254                         pfile_info->NumberOfLinks = cpu_to_le32(1);
1255                         pfile_info->DeletePending = 0;
1256                 }
1257         }
1258
1259         cifs_buf_release(pSMB);
1260         if (rc == -EAGAIN)
1261                 goto OldOpenRetry;
1262         return rc;
1263 }
1264
1265 int
1266 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1267             const char *fileName, const int openDisposition,
1268             const int access_flags, const int create_options, __u16 *netfid,
1269             int *pOplock, FILE_ALL_INFO *pfile_info,
1270             const struct nls_table *nls_codepage, int remap)
1271 {
1272         int rc = -EACCES;
1273         OPEN_REQ *pSMB = NULL;
1274         OPEN_RSP *pSMBr = NULL;
1275         int bytes_returned;
1276         int name_len;
1277         __u16 count;
1278
1279 openRetry:
1280         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1281                       (void **) &pSMBr);
1282         if (rc)
1283                 return rc;
1284
1285         pSMB->AndXCommand = 0xFF;       /* none */
1286
1287         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1288                 count = 1;      /* account for one byte pad to word boundary */
1289                 name_len =
1290                     cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1291                                      fileName, PATH_MAX, nls_codepage, remap);
1292                 name_len++;     /* trailing null */
1293                 name_len *= 2;
1294                 pSMB->NameLength = cpu_to_le16(name_len);
1295         } else {                /* BB improve check for buffer overruns BB */
1296                 count = 0;      /* no pad */
1297                 name_len = strnlen(fileName, PATH_MAX);
1298                 name_len++;     /* trailing null */
1299                 pSMB->NameLength = cpu_to_le16(name_len);
1300                 strncpy(pSMB->fileName, fileName, name_len);
1301         }
1302         if (*pOplock & REQ_OPLOCK)
1303                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1304         else if (*pOplock & REQ_BATCHOPLOCK)
1305                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1306         pSMB->DesiredAccess = cpu_to_le32(access_flags);
1307         pSMB->AllocationSize = 0;
1308         /* set file as system file if special file such
1309            as fifo and server expecting SFU style and
1310            no Unix extensions */
1311         if (create_options & CREATE_OPTION_SPECIAL)
1312                 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1313         else
1314                 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1315
1316         /* XP does not handle ATTR_POSIX_SEMANTICS */
1317         /* but it helps speed up case sensitive checks for other
1318         servers such as Samba */
1319         if (tcon->ses->capabilities & CAP_UNIX)
1320                 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1321
1322         if (create_options & CREATE_OPTION_READONLY)
1323                 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1324
1325         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1326         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1327         pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1328         /* BB Expirement with various impersonation levels and verify */
1329         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1330         pSMB->SecurityFlags =
1331             SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1332
1333         count += name_len;
1334         pSMB->hdr.smb_buf_length += count;
1335
1336         pSMB->ByteCount = cpu_to_le16(count);
1337         /* long_op set to 1 to allow for oplock break timeouts */
1338         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1339                         (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1340         cifs_stats_inc(&tcon->num_opens);
1341         if (rc) {
1342                 cFYI(1, ("Error in Open = %d", rc));
1343         } else {
1344                 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1345                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1346                 /* Let caller know file was created so we can set the mode. */
1347                 /* Do we care about the CreateAction in any other cases? */
1348                 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1349                         *pOplock |= CIFS_CREATE_ACTION;
1350                 if (pfile_info) {
1351                         memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1352                                 36 /* CreationTime to Attributes */);
1353                         /* the file_info buf is endian converted by caller */
1354                         pfile_info->AllocationSize = pSMBr->AllocationSize;
1355                         pfile_info->EndOfFile = pSMBr->EndOfFile;
1356                         pfile_info->NumberOfLinks = cpu_to_le32(1);
1357                         pfile_info->DeletePending = 0;
1358                 }
1359         }
1360
1361         cifs_buf_release(pSMB);
1362         if (rc == -EAGAIN)
1363                 goto openRetry;
1364         return rc;
1365 }
1366
1367 int
1368 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1369             const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1370             char **buf, int *pbuf_type)
1371 {
1372         int rc = -EACCES;
1373         READ_REQ *pSMB = NULL;
1374         READ_RSP *pSMBr = NULL;
1375         char *pReadData = NULL;
1376         int wct;
1377         int resp_buf_type = 0;
1378         struct kvec iov[1];
1379
1380         cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1381         if (tcon->ses->capabilities & CAP_LARGE_FILES)
1382                 wct = 12;
1383         else {
1384                 wct = 10; /* old style read */
1385                 if ((lseek >> 32) > 0)  {
1386                         /* can not handle this big offset for old */
1387                         return -EIO;
1388                 }
1389         }
1390
1391         *nbytes = 0;
1392         rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1393         if (rc)
1394                 return rc;
1395
1396         /* tcon and ses pointer are checked in smb_init */
1397         if (tcon->ses->server == NULL)
1398                 return -ECONNABORTED;
1399
1400         pSMB->AndXCommand = 0xFF;       /* none */
1401         pSMB->Fid = netfid;
1402         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1403         if (wct == 12)
1404                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1405
1406         pSMB->Remaining = 0;
1407         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1408         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1409         if (wct == 12)
1410                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1411         else {
1412                 /* old style read */
1413                 struct smb_com_readx_req *pSMBW =
1414                         (struct smb_com_readx_req *)pSMB;
1415                 pSMBW->ByteCount = 0;
1416         }
1417
1418         iov[0].iov_base = (char *)pSMB;
1419         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1420         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1421                          &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1422         cifs_stats_inc(&tcon->num_reads);
1423         pSMBr = (READ_RSP *)iov[0].iov_base;
1424         if (rc) {
1425                 cERROR(1, ("Send error in read = %d", rc));
1426         } else {
1427                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1428                 data_length = data_length << 16;
1429                 data_length += le16_to_cpu(pSMBr->DataLength);
1430                 *nbytes = data_length;
1431
1432                 /*check that DataLength would not go beyond end of SMB */
1433                 if ((data_length > CIFSMaxBufSize)
1434                                 || (data_length > count)) {
1435                         cFYI(1, ("bad length %d for count %d",
1436                                  data_length, count));
1437                         rc = -EIO;
1438                         *nbytes = 0;
1439                 } else {
1440                         pReadData = (char *) (&pSMBr->hdr.Protocol) +
1441                                         le16_to_cpu(pSMBr->DataOffset);
1442 /*                      if (rc = copy_to_user(buf, pReadData, data_length)) {
1443                                 cERROR(1,("Faulting on read rc = %d",rc));
1444                                 rc = -EFAULT;
1445                         }*/ /* can not use copy_to_user when using page cache*/
1446                         if (*buf)
1447                                 memcpy(*buf, pReadData, data_length);
1448                 }
1449         }
1450
1451 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1452         if (*buf) {
1453                 if (resp_buf_type == CIFS_SMALL_BUFFER)
1454                         cifs_small_buf_release(iov[0].iov_base);
1455                 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1456                         cifs_buf_release(iov[0].iov_base);
1457         } else if (resp_buf_type != CIFS_NO_BUFFER) {
1458                 /* return buffer to caller to free */
1459                 *buf = iov[0].iov_base;
1460                 if (resp_buf_type == CIFS_SMALL_BUFFER)
1461                         *pbuf_type = CIFS_SMALL_BUFFER;
1462                 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1463                         *pbuf_type = CIFS_LARGE_BUFFER;
1464         } /* else no valid buffer on return - leave as null */
1465
1466         /* Note: On -EAGAIN error only caller can retry on handle based calls
1467                 since file handle passed in no longer valid */
1468         return rc;
1469 }
1470
1471
1472 int
1473 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1474              const int netfid, const unsigned int count,
1475              const __u64 offset, unsigned int *nbytes, const char *buf,
1476              const char __user *ubuf, const int long_op)
1477 {
1478         int rc = -EACCES;
1479         WRITE_REQ *pSMB = NULL;
1480         WRITE_RSP *pSMBr = NULL;
1481         int bytes_returned, wct;
1482         __u32 bytes_sent;
1483         __u16 byte_count;
1484
1485         /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1486         if (tcon->ses == NULL)
1487                 return -ECONNABORTED;
1488
1489         if (tcon->ses->capabilities & CAP_LARGE_FILES)
1490                 wct = 14;
1491         else {
1492                 wct = 12;
1493                 if ((offset >> 32) > 0) {
1494                         /* can not handle big offset for old srv */
1495                         return -EIO;
1496                 }
1497         }
1498
1499         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1500                       (void **) &pSMBr);
1501         if (rc)
1502                 return rc;
1503         /* tcon and ses pointer are checked in smb_init */
1504         if (tcon->ses->server == NULL)
1505                 return -ECONNABORTED;
1506
1507         pSMB->AndXCommand = 0xFF;       /* none */
1508         pSMB->Fid = netfid;
1509         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1510         if (wct == 14)
1511                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1512
1513         pSMB->Reserved = 0xFFFFFFFF;
1514         pSMB->WriteMode = 0;
1515         pSMB->Remaining = 0;
1516
1517         /* Can increase buffer size if buffer is big enough in some cases ie we
1518         can send more if LARGE_WRITE_X capability returned by the server and if
1519         our buffer is big enough or if we convert to iovecs on socket writes
1520         and eliminate the copy to the CIFS buffer */
1521         if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1522                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1523         } else {
1524                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1525                          & ~0xFF;
1526         }
1527
1528         if (bytes_sent > count)
1529                 bytes_sent = count;
1530         pSMB->DataOffset =
1531                 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1532         if (buf)
1533                 memcpy(pSMB->Data, buf, bytes_sent);
1534         else if (ubuf) {
1535                 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1536                         cifs_buf_release(pSMB);
1537                         return -EFAULT;
1538                 }
1539         } else if (count != 0) {
1540                 /* No buffer */
1541                 cifs_buf_release(pSMB);
1542                 return -EINVAL;
1543         } /* else setting file size with write of zero bytes */
1544         if (wct == 14)
1545                 byte_count = bytes_sent + 1; /* pad */
1546         else /* wct == 12 */
1547                 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1548
1549         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1550         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1551         pSMB->hdr.smb_buf_length += byte_count;
1552
1553         if (wct == 14)
1554                 pSMB->ByteCount = cpu_to_le16(byte_count);
1555         else { /* old style write has byte count 4 bytes earlier
1556                   so 4 bytes pad  */
1557                 struct smb_com_writex_req *pSMBW =
1558                         (struct smb_com_writex_req *)pSMB;
1559                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1560         }
1561
1562         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1563                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1564         cifs_stats_inc(&tcon->num_writes);
1565         if (rc) {
1566                 cFYI(1, ("Send error in write = %d", rc));
1567                 *nbytes = 0;
1568         } else {
1569                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1570                 *nbytes = (*nbytes) << 16;
1571                 *nbytes += le16_to_cpu(pSMBr->Count);
1572         }
1573
1574         cifs_buf_release(pSMB);
1575
1576         /* Note: On -EAGAIN error only caller can retry on handle based calls
1577                 since file handle passed in no longer valid */
1578
1579         return rc;
1580 }
1581
1582 int
1583 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1584              const int netfid, const unsigned int count,
1585              const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1586              int n_vec, const int long_op)
1587 {
1588         int rc = -EACCES;
1589         WRITE_REQ *pSMB = NULL;
1590         int wct;
1591         int smb_hdr_len;
1592         int resp_buf_type = 0;
1593
1594         *nbytes = 0;
1595
1596         cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1597
1598         if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1599                 wct = 14;
1600         } else {
1601                 wct = 12;
1602                 if ((offset >> 32) > 0) {
1603                         /* can not handle big offset for old srv */
1604                         return -EIO;
1605                 }
1606         }
1607         rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1608         if (rc)
1609                 return rc;
1610         /* tcon and ses pointer are checked in smb_init */
1611         if (tcon->ses->server == NULL)
1612                 return -ECONNABORTED;
1613
1614         pSMB->AndXCommand = 0xFF;       /* none */
1615         pSMB->Fid = netfid;
1616         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1617         if (wct == 14)
1618                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1619         pSMB->Reserved = 0xFFFFFFFF;
1620         pSMB->WriteMode = 0;
1621         pSMB->Remaining = 0;
1622
1623         pSMB->DataOffset =
1624             cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1625
1626         pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1627         pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1628         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1629         if (wct == 14)
1630                 pSMB->hdr.smb_buf_length += count+1;
1631         else /* wct == 12 */
1632                 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1633         if (wct == 14)
1634                 pSMB->ByteCount = cpu_to_le16(count + 1);
1635         else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1636                 struct smb_com_writex_req *pSMBW =
1637                                 (struct smb_com_writex_req *)pSMB;
1638                 pSMBW->ByteCount = cpu_to_le16(count + 5);
1639         }
1640         iov[0].iov_base = pSMB;
1641         if (wct == 14)
1642                 iov[0].iov_len = smb_hdr_len + 4;
1643         else /* wct == 12 pad bigger by four bytes */
1644                 iov[0].iov_len = smb_hdr_len + 8;
1645
1646
1647         rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1648                           long_op);
1649         cifs_stats_inc(&tcon->num_writes);
1650         if (rc) {
1651                 cFYI(1, ("Send error Write2 = %d", rc));
1652         } else if (resp_buf_type == 0) {
1653                 /* presumably this can not happen, but best to be safe */
1654                 rc = -EIO;
1655         } else {
1656                 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1657                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1658                 *nbytes = (*nbytes) << 16;
1659                 *nbytes += le16_to_cpu(pSMBr->Count);
1660         }
1661
1662 /*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1663         if (resp_buf_type == CIFS_SMALL_BUFFER)
1664                 cifs_small_buf_release(iov[0].iov_base);
1665         else if (resp_buf_type == CIFS_LARGE_BUFFER)
1666                 cifs_buf_release(iov[0].iov_base);
1667
1668         /* Note: On -EAGAIN error only caller can retry on handle based calls
1669                 since file handle passed in no longer valid */
1670
1671         return rc;
1672 }
1673
1674
1675 int
1676 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1677             const __u16 smb_file_id, const __u64 len,
1678             const __u64 offset, const __u32 numUnlock,
1679             const __u32 numLock, const __u8 lockType, const bool waitFlag)
1680 {
1681         int rc = 0;
1682         LOCK_REQ *pSMB = NULL;
1683 /*      LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1684         int bytes_returned;
1685         int timeout = 0;
1686         __u16 count;
1687
1688         cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1689         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1690
1691         if (rc)
1692                 return rc;
1693
1694         if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1695                 timeout = CIFS_ASYNC_OP; /* no response expected */
1696                 pSMB->Timeout = 0;
1697         } else if (waitFlag) {
1698                 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1699                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1700         } else {
1701                 pSMB->Timeout = 0;
1702         }
1703
1704         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1705         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1706         pSMB->LockType = lockType;
1707         pSMB->AndXCommand = 0xFF;       /* none */
1708         pSMB->Fid = smb_file_id; /* netfid stays le */
1709
1710         if ((numLock != 0) || (numUnlock != 0)) {
1711                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1712                 /* BB where to store pid high? */
1713                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1714                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1715                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1716                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1717                 count = sizeof(LOCKING_ANDX_RANGE);
1718         } else {
1719                 /* oplock break */
1720                 count = 0;
1721         }
1722         pSMB->hdr.smb_buf_length += count;
1723         pSMB->ByteCount = cpu_to_le16(count);
1724
1725         if (waitFlag) {
1726                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1727                         (struct smb_hdr *) pSMB, &bytes_returned);
1728                 cifs_small_buf_release(pSMB);
1729         } else {
1730                 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1731                                       timeout);
1732                 /* SMB buffer freed by function above */
1733         }
1734         cifs_stats_inc(&tcon->num_locks);
1735         if (rc)
1736                 cFYI(1, ("Send error in Lock = %d", rc));
1737
1738         /* Note: On -EAGAIN error only caller can retry on handle based calls
1739         since file handle passed in no longer valid */
1740         return rc;
1741 }
1742
1743 int
1744 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1745                 const __u16 smb_file_id, const int get_flag, const __u64 len,
1746                 struct file_lock *pLockData, const __u16 lock_type,
1747                 const bool waitFlag)
1748 {
1749         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1750         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1751         struct cifs_posix_lock *parm_data;
1752         int rc = 0;
1753         int timeout = 0;
1754         int bytes_returned = 0;
1755         int resp_buf_type = 0;
1756         __u16 params, param_offset, offset, byte_count, count;
1757         struct kvec iov[1];
1758
1759         cFYI(1, ("Posix Lock"));
1760
1761         if (pLockData == NULL)
1762                 return -EINVAL;
1763
1764         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1765
1766         if (rc)
1767                 return rc;
1768
1769         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1770
1771         params = 6;
1772         pSMB->MaxSetupCount = 0;
1773         pSMB->Reserved = 0;
1774         pSMB->Flags = 0;
1775         pSMB->Reserved2 = 0;
1776         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1777         offset = param_offset + params;
1778
1779         count = sizeof(struct cifs_posix_lock);
1780         pSMB->MaxParameterCount = cpu_to_le16(2);
1781         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1782         pSMB->SetupCount = 1;
1783         pSMB->Reserved3 = 0;
1784         if (get_flag)
1785                 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1786         else
1787                 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1788         byte_count = 3 /* pad */  + params + count;
1789         pSMB->DataCount = cpu_to_le16(count);
1790         pSMB->ParameterCount = cpu_to_le16(params);
1791         pSMB->TotalDataCount = pSMB->DataCount;
1792         pSMB->TotalParameterCount = pSMB->ParameterCount;
1793         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1794         parm_data = (struct cifs_posix_lock *)
1795                         (((char *) &pSMB->hdr.Protocol) + offset);
1796
1797         parm_data->lock_type = cpu_to_le16(lock_type);
1798         if (waitFlag) {
1799                 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1800                 parm_data->lock_flags = cpu_to_le16(1);
1801                 pSMB->Timeout = cpu_to_le32(-1);
1802         } else
1803                 pSMB->Timeout = 0;
1804
1805         parm_data->pid = cpu_to_le32(current->tgid);
1806         parm_data->start = cpu_to_le64(pLockData->fl_start);
1807         parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
1808
1809         pSMB->DataOffset = cpu_to_le16(offset);
1810         pSMB->Fid = smb_file_id;
1811         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1812         pSMB->Reserved4 = 0;
1813         pSMB->hdr.smb_buf_length += byte_count;
1814         pSMB->ByteCount = cpu_to_le16(byte_count);
1815         if (waitFlag) {
1816                 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1817                         (struct smb_hdr *) pSMBr, &bytes_returned);
1818         } else {
1819                 iov[0].iov_base = (char *)pSMB;
1820                 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1821                 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1822                                 &resp_buf_type, timeout);
1823                 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1824                                 not try to free it twice below on exit */
1825                 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1826         }
1827
1828         if (rc) {
1829                 cFYI(1, ("Send error in Posix Lock = %d", rc));
1830         } else if (get_flag) {
1831                 /* lock structure can be returned on get */
1832                 __u16 data_offset;
1833                 __u16 data_count;
1834                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1835
1836                 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1837                         rc = -EIO;      /* bad smb */
1838                         goto plk_err_exit;
1839                 }
1840                 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1841                 data_count  = le16_to_cpu(pSMBr->t2.DataCount);
1842                 if (data_count < sizeof(struct cifs_posix_lock)) {
1843                         rc = -EIO;
1844                         goto plk_err_exit;
1845                 }
1846                 parm_data = (struct cifs_posix_lock *)
1847                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1848                 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1849                         pLockData->fl_type = F_UNLCK;
1850         }
1851
1852 plk_err_exit:
1853         if (pSMB)
1854                 cifs_small_buf_release(pSMB);
1855
1856         if (resp_buf_type == CIFS_SMALL_BUFFER)
1857                 cifs_small_buf_release(iov[0].iov_base);
1858         else if (resp_buf_type == CIFS_LARGE_BUFFER)
1859                 cifs_buf_release(iov[0].iov_base);
1860
1861         /* Note: On -EAGAIN error only caller can retry on handle based calls
1862            since file handle passed in no longer valid */
1863
1864         return rc;
1865 }
1866
1867
1868 int
1869 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1870 {
1871         int rc = 0;
1872         CLOSE_REQ *pSMB = NULL;
1873         cFYI(1, ("In CIFSSMBClose"));
1874
1875 /* do not retry on dead session on close */
1876         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1877         if (rc == -EAGAIN)
1878                 return 0;
1879         if (rc)
1880                 return rc;
1881
1882         pSMB->FileID = (__u16) smb_file_id;
1883         pSMB->LastWriteTime = 0xFFFFFFFF;
1884         pSMB->ByteCount = 0;
1885         rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1886         cifs_stats_inc(&tcon->num_closes);
1887         if (rc) {
1888                 if (rc != -EINTR) {
1889                         /* EINTR is expected when user ctl-c to kill app */
1890                         cERROR(1, ("Send error in Close = %d", rc));
1891                 }
1892         }
1893
1894         /* Since session is dead, file will be closed on server already */
1895         if (rc == -EAGAIN)
1896                 rc = 0;
1897
1898         return rc;
1899 }
1900
1901 int
1902 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1903 {
1904         int rc = 0;
1905         FLUSH_REQ *pSMB = NULL;
1906         cFYI(1, ("In CIFSSMBFlush"));
1907
1908         rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1909         if (rc)
1910                 return rc;
1911
1912         pSMB->FileID = (__u16) smb_file_id;
1913         pSMB->ByteCount = 0;
1914         rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1915         cifs_stats_inc(&tcon->num_flushes);
1916         if (rc)
1917                 cERROR(1, ("Send error in Flush = %d", rc));
1918
1919         return rc;
1920 }
1921
1922 int
1923 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1924               const char *fromName, const char *toName,
1925               const struct nls_table *nls_codepage, int remap)
1926 {
1927         int rc = 0;
1928         RENAME_REQ *pSMB = NULL;
1929         RENAME_RSP *pSMBr = NULL;
1930         int bytes_returned;
1931         int name_len, name_len2;
1932         __u16 count;
1933
1934         cFYI(1, ("In CIFSSMBRename"));
1935 renameRetry:
1936         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1937                       (void **) &pSMBr);
1938         if (rc)
1939                 return rc;
1940
1941         pSMB->BufferFormat = 0x04;
1942         pSMB->SearchAttributes =
1943             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1944                         ATTR_DIRECTORY);
1945
1946         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1947                 name_len =
1948                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1949                                      PATH_MAX, nls_codepage, remap);
1950                 name_len++;     /* trailing null */
1951                 name_len *= 2;
1952                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1953         /* protocol requires ASCII signature byte on Unicode string */
1954                 pSMB->OldFileName[name_len + 1] = 0x00;
1955                 name_len2 =
1956                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1957                                      toName, PATH_MAX, nls_codepage, remap);
1958                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1959                 name_len2 *= 2; /* convert to bytes */
1960         } else {        /* BB improve the check for buffer overruns BB */
1961                 name_len = strnlen(fromName, PATH_MAX);
1962                 name_len++;     /* trailing null */
1963                 strncpy(pSMB->OldFileName, fromName, name_len);
1964                 name_len2 = strnlen(toName, PATH_MAX);
1965                 name_len2++;    /* trailing null */
1966                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1967                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1968                 name_len2++;    /* trailing null */
1969                 name_len2++;    /* signature byte */
1970         }
1971
1972         count = 1 /* 1st signature byte */  + name_len + name_len2;
1973         pSMB->hdr.smb_buf_length += count;
1974         pSMB->ByteCount = cpu_to_le16(count);
1975
1976         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1977                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1978         cifs_stats_inc(&tcon->num_renames);
1979         if (rc)
1980                 cFYI(1, ("Send error in rename = %d", rc));
1981
1982         cifs_buf_release(pSMB);
1983
1984         if (rc == -EAGAIN)
1985                 goto renameRetry;
1986
1987         return rc;
1988 }
1989
1990 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1991                 int netfid, const char *target_name,
1992                 const struct nls_table *nls_codepage, int remap)
1993 {
1994         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1995         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1996         struct set_file_rename *rename_info;
1997         char *data_offset;
1998         char dummy_string[30];
1999         int rc = 0;
2000         int bytes_returned = 0;
2001         int len_of_str;
2002         __u16 params, param_offset, offset, count, byte_count;
2003
2004         cFYI(1, ("Rename to File by handle"));
2005         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2006                         (void **) &pSMBr);
2007         if (rc)
2008                 return rc;
2009
2010         params = 6;
2011         pSMB->MaxSetupCount = 0;
2012         pSMB->Reserved = 0;
2013         pSMB->Flags = 0;
2014         pSMB->Timeout = 0;
2015         pSMB->Reserved2 = 0;
2016         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2017         offset = param_offset + params;
2018
2019         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2020         rename_info = (struct set_file_rename *) data_offset;
2021         pSMB->MaxParameterCount = cpu_to_le16(2);
2022         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2023         pSMB->SetupCount = 1;
2024         pSMB->Reserved3 = 0;
2025         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2026         byte_count = 3 /* pad */  + params;
2027         pSMB->ParameterCount = cpu_to_le16(params);
2028         pSMB->TotalParameterCount = pSMB->ParameterCount;
2029         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2030         pSMB->DataOffset = cpu_to_le16(offset);
2031         /* construct random name ".cifs_tmp<inodenum><mid>" */
2032         rename_info->overwrite = cpu_to_le32(1);
2033         rename_info->root_fid  = 0;
2034         /* unicode only call */
2035         if (target_name == NULL) {
2036                 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2037                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2038                                         dummy_string, 24, nls_codepage, remap);
2039         } else {
2040                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2041                                         target_name, PATH_MAX, nls_codepage,
2042                                         remap);
2043         }
2044         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2045         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2046         byte_count += count;
2047         pSMB->DataCount = cpu_to_le16(count);
2048         pSMB->TotalDataCount = pSMB->DataCount;
2049         pSMB->Fid = netfid;
2050         pSMB->InformationLevel =
2051                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2052         pSMB->Reserved4 = 0;
2053         pSMB->hdr.smb_buf_length += byte_count;
2054         pSMB->ByteCount = cpu_to_le16(byte_count);
2055         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2056                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2057         cifs_stats_inc(&pTcon->num_t2renames);
2058         if (rc)
2059                 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2060
2061         cifs_buf_release(pSMB);
2062
2063         /* Note: On -EAGAIN error only caller can retry on handle based calls
2064                 since file handle passed in no longer valid */
2065
2066         return rc;
2067 }
2068
2069 int
2070 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2071             const __u16 target_tid, const char *toName, const int flags,
2072             const struct nls_table *nls_codepage, int remap)
2073 {
2074         int rc = 0;
2075         COPY_REQ *pSMB = NULL;
2076         COPY_RSP *pSMBr = NULL;
2077         int bytes_returned;
2078         int name_len, name_len2;
2079         __u16 count;
2080
2081         cFYI(1, ("In CIFSSMBCopy"));
2082 copyRetry:
2083         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2084                         (void **) &pSMBr);
2085         if (rc)
2086                 return rc;
2087
2088         pSMB->BufferFormat = 0x04;
2089         pSMB->Tid2 = target_tid;
2090
2091         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2092
2093         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2094                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2095                                             fromName, PATH_MAX, nls_codepage,
2096                                             remap);
2097                 name_len++;     /* trailing null */
2098                 name_len *= 2;
2099                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
2100                 /* protocol requires ASCII signature byte on Unicode string */
2101                 pSMB->OldFileName[name_len + 1] = 0x00;
2102                 name_len2 =
2103                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2104                                 toName, PATH_MAX, nls_codepage, remap);
2105                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2106                 name_len2 *= 2; /* convert to bytes */
2107         } else {        /* BB improve the check for buffer overruns BB */
2108                 name_len = strnlen(fromName, PATH_MAX);
2109                 name_len++;     /* trailing null */
2110                 strncpy(pSMB->OldFileName, fromName, name_len);
2111                 name_len2 = strnlen(toName, PATH_MAX);
2112                 name_len2++;    /* trailing null */
2113                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
2114                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2115                 name_len2++;    /* trailing null */
2116                 name_len2++;    /* signature byte */
2117         }
2118
2119         count = 1 /* 1st signature byte */  + name_len + name_len2;
2120         pSMB->hdr.smb_buf_length += count;
2121         pSMB->ByteCount = cpu_to_le16(count);
2122
2123         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2124                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2125         if (rc) {
2126                 cFYI(1, ("Send error in copy = %d with %d files copied",
2127                         rc, le16_to_cpu(pSMBr->CopyCount)));
2128         }
2129         cifs_buf_release(pSMB);
2130
2131         if (rc == -EAGAIN)
2132                 goto copyRetry;
2133
2134         return rc;
2135 }
2136
2137 int
2138 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2139                       const char *fromName, const char *toName,
2140                       const struct nls_table *nls_codepage)
2141 {
2142         TRANSACTION2_SPI_REQ *pSMB = NULL;
2143         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144         char *data_offset;
2145         int name_len;
2146         int name_len_target;
2147         int rc = 0;
2148         int bytes_returned = 0;
2149         __u16 params, param_offset, offset, byte_count;
2150
2151         cFYI(1, ("In Symlink Unix style"));
2152 createSymLinkRetry:
2153         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154                       (void **) &pSMBr);
2155         if (rc)
2156                 return rc;
2157
2158         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159                 name_len =
2160                     cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2161                                   /* find define for this maxpathcomponent */
2162                                   , nls_codepage);
2163                 name_len++;     /* trailing null */
2164                 name_len *= 2;
2165
2166         } else {        /* BB improve the check for buffer overruns BB */
2167                 name_len = strnlen(fromName, PATH_MAX);
2168                 name_len++;     /* trailing null */
2169                 strncpy(pSMB->FileName, fromName, name_len);
2170         }
2171         params = 6 + name_len;
2172         pSMB->MaxSetupCount = 0;
2173         pSMB->Reserved = 0;
2174         pSMB->Flags = 0;
2175         pSMB->Timeout = 0;
2176         pSMB->Reserved2 = 0;
2177         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2178                                 InformationLevel) - 4;
2179         offset = param_offset + params;
2180
2181         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2182         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2183                 name_len_target =
2184                     cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2185                                   /* find define for this maxpathcomponent */
2186                                   , nls_codepage);
2187                 name_len_target++;      /* trailing null */
2188                 name_len_target *= 2;
2189         } else {        /* BB improve the check for buffer overruns BB */
2190                 name_len_target = strnlen(toName, PATH_MAX);
2191                 name_len_target++;      /* trailing null */
2192                 strncpy(data_offset, toName, name_len_target);
2193         }
2194
2195         pSMB->MaxParameterCount = cpu_to_le16(2);
2196         /* BB find exact max on data count below from sess */
2197         pSMB->MaxDataCount = cpu_to_le16(1000);
2198         pSMB->SetupCount = 1;
2199         pSMB->Reserved3 = 0;
2200         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2201         byte_count = 3 /* pad */  + params + name_len_target;
2202         pSMB->DataCount = cpu_to_le16(name_len_target);
2203         pSMB->ParameterCount = cpu_to_le16(params);
2204         pSMB->TotalDataCount = pSMB->DataCount;
2205         pSMB->TotalParameterCount = pSMB->ParameterCount;
2206         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2207         pSMB->DataOffset = cpu_to_le16(offset);
2208         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2209         pSMB->Reserved4 = 0;
2210         pSMB->hdr.smb_buf_length += byte_count;
2211         pSMB->ByteCount = cpu_to_le16(byte_count);
2212         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2213                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2214         cifs_stats_inc(&tcon->num_symlinks);
2215         if (rc)
2216                 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2217
2218         cifs_buf_release(pSMB);
2219
2220         if (rc == -EAGAIN)
2221                 goto createSymLinkRetry;
2222
2223         return rc;
2224 }
2225
2226 int
2227 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2228                        const char *fromName, const char *toName,
2229                        const struct nls_table *nls_codepage, int remap)
2230 {
2231         TRANSACTION2_SPI_REQ *pSMB = NULL;
2232         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2233         char *data_offset;
2234         int name_len;
2235         int name_len_target;
2236         int rc = 0;
2237         int bytes_returned = 0;
2238         __u16 params, param_offset, offset, byte_count;
2239
2240         cFYI(1, ("In Create Hard link Unix style"));
2241 createHardLinkRetry:
2242         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2243                       (void **) &pSMBr);
2244         if (rc)
2245                 return rc;
2246
2247         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2248                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2249                                             PATH_MAX, nls_codepage, remap);
2250                 name_len++;     /* trailing null */
2251                 name_len *= 2;
2252
2253         } else {        /* BB improve the check for buffer overruns BB */
2254                 name_len = strnlen(toName, PATH_MAX);
2255                 name_len++;     /* trailing null */
2256                 strncpy(pSMB->FileName, toName, name_len);
2257         }
2258         params = 6 + name_len;
2259         pSMB->MaxSetupCount = 0;
2260         pSMB->Reserved = 0;
2261         pSMB->Flags = 0;
2262         pSMB->Timeout = 0;
2263         pSMB->Reserved2 = 0;
2264         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2265                                 InformationLevel) - 4;
2266         offset = param_offset + params;
2267
2268         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2269         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2270                 name_len_target =
2271                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2272                                      nls_codepage, remap);
2273                 name_len_target++;      /* trailing null */
2274                 name_len_target *= 2;
2275         } else {        /* BB improve the check for buffer overruns BB */
2276                 name_len_target = strnlen(fromName, PATH_MAX);
2277                 name_len_target++;      /* trailing null */
2278                 strncpy(data_offset, fromName, name_len_target);
2279         }
2280
2281         pSMB->MaxParameterCount = cpu_to_le16(2);
2282         /* BB find exact max on data count below from sess*/
2283         pSMB->MaxDataCount = cpu_to_le16(1000);
2284         pSMB->SetupCount = 1;
2285         pSMB->Reserved3 = 0;
2286         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2287         byte_count = 3 /* pad */  + params + name_len_target;
2288         pSMB->ParameterCount = cpu_to_le16(params);
2289         pSMB->TotalParameterCount = pSMB->ParameterCount;
2290         pSMB->DataCount = cpu_to_le16(name_len_target);
2291         pSMB->TotalDataCount = pSMB->DataCount;
2292         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2293         pSMB->DataOffset = cpu_to_le16(offset);
2294         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2295         pSMB->Reserved4 = 0;
2296         pSMB->hdr.smb_buf_length += byte_count;
2297         pSMB->ByteCount = cpu_to_le16(byte_count);
2298         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2299                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2300         cifs_stats_inc(&tcon->num_hardlinks);
2301         if (rc)
2302                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2303
2304         cifs_buf_release(pSMB);
2305         if (rc == -EAGAIN)
2306                 goto createHardLinkRetry;
2307
2308         return rc;
2309 }
2310
2311 int
2312 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2313                    const char *fromName, const char *toName,
2314                    const struct nls_table *nls_codepage, int remap)
2315 {
2316         int rc = 0;
2317         NT_RENAME_REQ *pSMB = NULL;
2318         RENAME_RSP *pSMBr = NULL;
2319         int bytes_returned;
2320         int name_len, name_len2;
2321         __u16 count;
2322
2323         cFYI(1, ("In CIFSCreateHardLink"));
2324 winCreateHardLinkRetry:
2325
2326         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2327                       (void **) &pSMBr);
2328         if (rc)
2329                 return rc;
2330
2331         pSMB->SearchAttributes =
2332             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2333                         ATTR_DIRECTORY);
2334         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2335         pSMB->ClusterCount = 0;
2336
2337         pSMB->BufferFormat = 0x04;
2338
2339         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2340                 name_len =
2341                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2342                                      PATH_MAX, nls_codepage, remap);
2343                 name_len++;     /* trailing null */
2344                 name_len *= 2;
2345
2346                 /* protocol specifies ASCII buffer format (0x04) for unicode */
2347                 pSMB->OldFileName[name_len] = 0x04;
2348                 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2349                 name_len2 =
2350                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2351                                      toName, PATH_MAX, nls_codepage, remap);
2352                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2353                 name_len2 *= 2; /* convert to bytes */
2354         } else {        /* BB improve the check for buffer overruns BB */
2355                 name_len = strnlen(fromName, PATH_MAX);
2356                 name_len++;     /* trailing null */
2357                 strncpy(pSMB->OldFileName, fromName, name_len);
2358                 name_len2 = strnlen(toName, PATH_MAX);
2359                 name_len2++;    /* trailing null */
2360                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
2361                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2362                 name_len2++;    /* trailing null */
2363                 name_len2++;    /* signature byte */
2364         }
2365
2366         count = 1 /* string type byte */  + name_len + name_len2;
2367         pSMB->hdr.smb_buf_length += count;
2368         pSMB->ByteCount = cpu_to_le16(count);
2369
2370         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2371                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2372         cifs_stats_inc(&tcon->num_hardlinks);
2373         if (rc)
2374                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2375
2376         cifs_buf_release(pSMB);
2377         if (rc == -EAGAIN)
2378                 goto winCreateHardLinkRetry;
2379
2380         return rc;
2381 }
2382
2383 int
2384 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2385                         const unsigned char *searchName,
2386                         char *symlinkinfo, const int buflen,
2387                         const struct nls_table *nls_codepage)
2388 {
2389 /* SMB_QUERY_FILE_UNIX_LINK */
2390         TRANSACTION2_QPI_REQ *pSMB = NULL;
2391         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2392         int rc = 0;
2393         int bytes_returned;
2394         int name_len;
2395         __u16 params, byte_count;
2396
2397         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2398
2399 querySymLinkRetry:
2400         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2401                       (void **) &pSMBr);
2402         if (rc)
2403                 return rc;
2404
2405         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2406                 name_len =
2407                     cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2408                                   PATH_MAX, nls_codepage);
2409                 name_len++;     /* trailing null */
2410                 name_len *= 2;
2411         } else {        /* BB improve the check for buffer overruns BB */
2412                 name_len = strnlen(searchName, PATH_MAX);
2413                 name_len++;     /* trailing null */
2414                 strncpy(pSMB->FileName, searchName, name_len);
2415         }
2416
2417         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2418         pSMB->TotalDataCount = 0;
2419         pSMB->MaxParameterCount = cpu_to_le16(2);
2420         /* BB find exact max data count below from sess structure BB */
2421         pSMB->MaxDataCount = cpu_to_le16(4000);
2422         pSMB->MaxSetupCount = 0;
2423         pSMB->Reserved = 0;
2424         pSMB->Flags = 0;
2425         pSMB->Timeout = 0;
2426         pSMB->Reserved2 = 0;
2427         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2428         struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2429         pSMB->DataCount = 0;
2430         pSMB->DataOffset = 0;
2431         pSMB->SetupCount = 1;
2432         pSMB->Reserved3 = 0;
2433         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2434         byte_count = params + 1 /* pad */ ;
2435         pSMB->TotalParameterCount = cpu_to_le16(params);
2436         pSMB->ParameterCount = pSMB->TotalParameterCount;
2437         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2438         pSMB->Reserved4 = 0;
2439         pSMB->hdr.smb_buf_length += byte_count;
2440         pSMB->ByteCount = cpu_to_le16(byte_count);
2441
2442         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2443                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2444         if (rc) {
2445                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2446         } else {
2447                 /* decode response */
2448
2449                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2450                 if (rc || (pSMBr->ByteCount < 2))
2451                 /* BB also check enough total bytes returned */
2452                         rc = -EIO;      /* bad smb */
2453                 else {
2454                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2455                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2456
2457                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2458                                 name_len = UniStrnlen((wchar_t *) ((char *)
2459                                         &pSMBr->hdr.Protocol + data_offset),
2460                                         min_t(const int, buflen, count) / 2);
2461                         /* BB FIXME investigate remapping reserved chars here */
2462                                 cifs_strfromUCS_le(symlinkinfo,
2463                                         (__le16 *) ((char *)&pSMBr->hdr.Protocol
2464                                                         + data_offset),
2465                                         name_len, nls_codepage);
2466                         } else {
2467                                 strncpy(symlinkinfo,
2468                                         (char *) &pSMBr->hdr.Protocol +
2469                                                 data_offset,
2470                                         min_t(const int, buflen, count));
2471                         }
2472                         symlinkinfo[buflen] = 0;
2473         /* just in case so calling code does not go off the end of buffer */
2474                 }
2475         }
2476         cifs_buf_release(pSMB);
2477         if (rc == -EAGAIN)
2478                 goto querySymLinkRetry;
2479         return rc;
2480 }
2481
2482 #ifdef CONFIG_CIFS_EXPERIMENTAL
2483 /* Initialize NT TRANSACT SMB into small smb request buffer.
2484    This assumes that all NT TRANSACTS that we init here have
2485    total parm and data under about 400 bytes (to fit in small cifs
2486    buffer size), which is the case so far, it easily fits. NB:
2487         Setup words themselves and ByteCount
2488         MaxSetupCount (size of returned setup area) and
2489         MaxParameterCount (returned parms size) must be set by caller */
2490 static int
2491 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2492                    const int parm_len, struct cifsTconInfo *tcon,
2493                    void **ret_buf)
2494 {
2495         int rc;
2496         __u32 temp_offset;
2497         struct smb_com_ntransact_req *pSMB;
2498
2499         rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2500                                 (void **)&pSMB);
2501         if (rc)
2502                 return rc;
2503         *ret_buf = (void *)pSMB;
2504         pSMB->Reserved = 0;
2505         pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2506         pSMB->TotalDataCount  = 0;
2507         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2508                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2509         pSMB->ParameterCount = pSMB->TotalParameterCount;
2510         pSMB->DataCount  = pSMB->TotalDataCount;
2511         temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2512                         (setup_count * 2) - 4 /* for rfc1001 length itself */;
2513         pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2514         pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2515         pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2516         pSMB->SubCommand = cpu_to_le16(sub_command);
2517         return 0;
2518 }
2519
2520 static int
2521 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2522                    __u32 *pparmlen, __u32 *pdatalen)
2523 {
2524         char *end_of_smb;
2525         __u32 data_count, data_offset, parm_count, parm_offset;
2526         struct smb_com_ntransact_rsp *pSMBr;
2527
2528         *pdatalen = 0;
2529         *pparmlen = 0;
2530
2531         if (buf == NULL)
2532                 return -EINVAL;
2533
2534         pSMBr = (struct smb_com_ntransact_rsp *)buf;
2535
2536         /* ByteCount was converted from little endian in SendReceive */
2537         end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2538                         (char *)&pSMBr->ByteCount;
2539
2540         data_offset = le32_to_cpu(pSMBr->DataOffset);
2541         data_count = le32_to_cpu(pSMBr->DataCount);
2542         parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2543         parm_count = le32_to_cpu(pSMBr->ParameterCount);
2544
2545         *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2546         *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2547
2548         /* should we also check that parm and data areas do not overlap? */
2549         if (*ppparm > end_of_smb) {
2550                 cFYI(1, ("parms start after end of smb"));
2551                 return -EINVAL;
2552         } else if (parm_count + *ppparm > end_of_smb) {
2553                 cFYI(1, ("parm end after end of smb"));
2554                 return -EINVAL;
2555         } else if (*ppdata > end_of_smb) {
2556                 cFYI(1, ("data starts after end of smb"));
2557                 return -EINVAL;
2558         } else if (data_count + *ppdata > end_of_smb) {
2559                 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2560                         *ppdata, data_count, (data_count + *ppdata),
2561                         end_of_smb, pSMBr));
2562                 return -EINVAL;
2563         } else if (parm_count + data_count > pSMBr->ByteCount) {
2564                 cFYI(1, ("parm count and data count larger than SMB"));
2565                 return -EINVAL;
2566         }
2567         *pdatalen = data_count;
2568         *pparmlen = parm_count;
2569         return 0;
2570 }
2571 #endif /* CIFS_EXPERIMENTAL */
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         /* BB find max SMB size from sess */
2938         pSMB->MaxDataCount = cpu_to_le16(1000);
2939         pSMB->MaxSetupCount = 0;
2940         pSMB->Reserved = 0;
2941         pSMB->Flags = 0;
2942         pSMB->Timeout = 0;
2943         pSMB->Reserved2 = 0;
2944         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2945                                 InformationLevel) - 4;
2946         offset = param_offset + params;
2947         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2948         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2949
2950         /* convert to on the wire format for POSIX ACL */
2951         data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2952
2953         if (data_count == 0) {
2954                 rc = -EOPNOTSUPP;
2955                 goto setACLerrorExit;
2956         }
2957         pSMB->DataOffset = cpu_to_le16(offset);
2958         pSMB->SetupCount = 1;
2959         pSMB->Reserved3 = 0;
2960         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2961         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2962         byte_count = 3 /* pad */  + params + data_count;
2963         pSMB->DataCount = cpu_to_le16(data_count);
2964         pSMB->TotalDataCount = pSMB->DataCount;
2965         pSMB->ParameterCount = cpu_to_le16(params);
2966         pSMB->TotalParameterCount = pSMB->ParameterCount;
2967         pSMB->Reserved4 = 0;
2968         pSMB->hdr.smb_buf_length += byte_count;
2969         pSMB->ByteCount = cpu_to_le16(byte_count);
2970         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2971                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2972         if (rc)
2973                 cFYI(1, ("Set POSIX ACL returned %d", rc));
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);