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