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