linux/fs/cifs/cifssmb.c
<<
>>
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(le16_to_cpu(rsp->SrvTime.Date),
 528                                                le16_to_cpu(rsp->SrvTime.Time));
 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 = NTLMSSP;
 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)
 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        cifs_stats_inc(&tcon->num_mkdirs);
1117
1118        if (rc == -EAGAIN)
1119                goto PsxCreat;
1120
1121        return rc;
1122}
1123
1124static __u16 convert_disposition(int disposition)
1125{
1126        __u16 ofun = 0;
1127
1128        switch (disposition) {
1129                case FILE_SUPERSEDE:
1130                        ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1131                        break;
1132                case FILE_OPEN:
1133                        ofun = SMBOPEN_OAPPEND;
1134                        break;
1135                case FILE_CREATE:
1136                        ofun = SMBOPEN_OCREATE;
1137                        break;
1138                case FILE_OPEN_IF:
1139                        ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1140                        break;
1141                case FILE_OVERWRITE:
1142                        ofun = SMBOPEN_OTRUNC;
1143                        break;
1144                case FILE_OVERWRITE_IF:
1145                        ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146                        break;
1147                default:
1148                        cFYI(1, ("unknown disposition %d", disposition));
1149                        ofun =  SMBOPEN_OAPPEND; /* regular open */
1150        }
1151        return ofun;
1152}
1153
1154static int
1155access_flags_to_smbopen_mode(const int access_flags)
1156{
1157        int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1158
1159        if (masked_flags == GENERIC_READ)
1160                return SMBOPEN_READ;
1161        else if (masked_flags == GENERIC_WRITE)
1162                return SMBOPEN_WRITE;
1163
1164        /* just go for read/write */
1165        return SMBOPEN_READWRITE;
1166}
1167
1168int
1169SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1170            const char *fileName, const int openDisposition,
1171            const int access_flags, const int create_options, __u16 *netfid,
1172            int *pOplock, FILE_ALL_INFO *pfile_info,
1173            const struct nls_table *nls_codepage, int remap)
1174{
1175        int rc = -EACCES;
1176        OPENX_REQ *pSMB = NULL;
1177        OPENX_RSP *pSMBr = NULL;
1178        int bytes_returned;
1179        int name_len;
1180        __u16 count;
1181
1182OldOpenRetry:
1183        rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1184                      (void **) &pSMBr);
1185        if (rc)
1186                return rc;
1187
1188        pSMB->AndXCommand = 0xFF;       /* none */
1189
1190        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1191                count = 1;      /* account for one byte pad to word boundary */
1192                name_len =
1193                   cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1194                                    fileName, PATH_MAX, nls_codepage, remap);
1195                name_len++;     /* trailing null */
1196                name_len *= 2;
1197        } else {                /* BB improve check for buffer overruns BB */
1198                count = 0;      /* no pad */
1199                name_len = strnlen(fileName, PATH_MAX);
1200                name_len++;     /* trailing null */
1201                strncpy(pSMB->fileName, fileName, name_len);
1202        }
1203        if (*pOplock & REQ_OPLOCK)
1204                pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1205        else if (*pOplock & REQ_BATCHOPLOCK)
1206                pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1207
1208        pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1209        pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1210        pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1211        /* set file as system file if special file such
1212           as fifo and server expecting SFU style and
1213           no Unix extensions */
1214
1215        if (create_options & CREATE_OPTION_SPECIAL)
1216                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1217        else /* BB FIXME BB */
1218                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1219
1220        if (create_options & CREATE_OPTION_READONLY)
1221                pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1222
1223        /* BB FIXME BB */
1224/*      pSMB->CreateOptions = cpu_to_le32(create_options &
1225                                                 CREATE_OPTIONS_MASK); */
1226        /* BB FIXME END BB */
1227
1228        pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1229        pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1230        count += name_len;
1231        pSMB->hdr.smb_buf_length += count;
1232
1233        pSMB->ByteCount = cpu_to_le16(count);
1234        /* long_op set to 1 to allow for oplock break timeouts */
1235        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1236                        (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1237        cifs_stats_inc(&tcon->num_opens);
1238        if (rc) {
1239                cFYI(1, ("Error in Open = %d", rc));
1240        } else {
1241        /* BB verify if wct == 15 */
1242
1243/*              *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1244
1245                *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1246                /* Let caller know file was created so we can set the mode. */
1247                /* Do we care about the CreateAction in any other cases? */
1248        /* BB FIXME BB */
1249/*              if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1250                        *pOplock |= CIFS_CREATE_ACTION; */
1251        /* BB FIXME END */
1252
1253                if (pfile_info) {
1254                        pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255                        pfile_info->LastAccessTime = 0; /* BB fixme */
1256                        pfile_info->LastWriteTime = 0; /* BB fixme */
1257                        pfile_info->ChangeTime = 0;  /* BB fixme */
1258                        pfile_info->Attributes =
1259                                cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1260                        /* the file_info buf is endian converted by caller */
1261                        pfile_info->AllocationSize =
1262                                cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263                        pfile_info->EndOfFile = pfile_info->AllocationSize;
1264                        pfile_info->NumberOfLinks = cpu_to_le32(1);
1265                        pfile_info->DeletePending = 0;
1266                }
1267        }
1268
1269        cifs_buf_release(pSMB);
1270        if (rc == -EAGAIN)
1271                goto OldOpenRetry;
1272        return rc;
1273}
1274
1275int
1276CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1277            const char *fileName, const int openDisposition,
1278            const int access_flags, const int create_options, __u16 *netfid,
1279            int *pOplock, FILE_ALL_INFO *pfile_info,
1280            const struct nls_table *nls_codepage, int remap)
1281{
1282        int rc = -EACCES;
1283        OPEN_REQ *pSMB = NULL;
1284        OPEN_RSP *pSMBr = NULL;
1285        int bytes_returned;
1286        int name_len;
1287        __u16 count;
1288
1289openRetry:
1290        rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1291                      (void **) &pSMBr);
1292        if (rc)
1293                return rc;
1294
1295        pSMB->AndXCommand = 0xFF;       /* none */
1296
1297        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1298                count = 1;      /* account for one byte pad to word boundary */
1299                name_len =
1300                    cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1301                                     fileName, PATH_MAX, nls_codepage, remap);
1302                name_len++;     /* trailing null */
1303                name_len *= 2;
1304                pSMB->NameLength = cpu_to_le16(name_len);
1305        } else {                /* BB improve check for buffer overruns BB */
1306                count = 0;      /* no pad */
1307                name_len = strnlen(fileName, PATH_MAX);
1308                name_len++;     /* trailing null */
1309                pSMB->NameLength = cpu_to_le16(name_len);
1310                strncpy(pSMB->fileName, fileName, name_len);
1311        }
1312        if (*pOplock & REQ_OPLOCK)
1313                pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1314        else if (*pOplock & REQ_BATCHOPLOCK)
1315                pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1316        pSMB->DesiredAccess = cpu_to_le32(access_flags);
1317        pSMB->AllocationSize = 0;
1318        /* set file as system file if special file such
1319           as fifo and server expecting SFU style and
1320           no Unix extensions */
1321        if (create_options & CREATE_OPTION_SPECIAL)
1322                pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1323        else
1324                pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1325
1326        /* XP does not handle ATTR_POSIX_SEMANTICS */
1327        /* but it helps speed up case sensitive checks for other
1328        servers such as Samba */
1329        if (tcon->ses->capabilities & CAP_UNIX)
1330                pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1331
1332        if (create_options & CREATE_OPTION_READONLY)
1333                pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1334
1335        pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1336        pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1337        pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1338        /* BB Expirement with various impersonation levels and verify */
1339        pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1340        pSMB->SecurityFlags =
1341            SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1342
1343        count += name_len;
1344        pSMB->hdr.smb_buf_length += count;
1345
1346        pSMB->ByteCount = cpu_to_le16(count);
1347        /* long_op set to 1 to allow for oplock break timeouts */
1348        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1349                        (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1350        cifs_stats_inc(&tcon->num_opens);
1351        if (rc) {
1352                cFYI(1, ("Error in Open = %d", rc));
1353        } else {
1354                *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1355                *netfid = pSMBr->Fid;   /* cifs fid stays in le */
1356                /* Let caller know file was created so we can set the mode. */
1357                /* Do we care about the CreateAction in any other cases? */
1358                if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1359                        *pOplock |= CIFS_CREATE_ACTION;
1360                if (pfile_info) {
1361                        memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1362                                36 /* CreationTime to Attributes */);
1363                        /* the file_info buf is endian converted by caller */
1364                        pfile_info->AllocationSize = pSMBr->AllocationSize;
1365                        pfile_info->EndOfFile = pSMBr->EndOfFile;
1366                        pfile_info->NumberOfLinks = cpu_to_le32(1);
1367                        pfile_info->DeletePending = 0;
1368                }
1369        }
1370
1371        cifs_buf_release(pSMB);
1372        if (rc == -EAGAIN)
1373                goto openRetry;
1374        return rc;
1375}
1376
1377int
1378CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1379            const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1380            char **buf, int *pbuf_type)
1381{
1382        int rc = -EACCES;
1383        READ_REQ *pSMB = NULL;
1384        READ_RSP *pSMBr = NULL;
1385        char *pReadData = NULL;
1386        int wct;
1387        int resp_buf_type = 0;
1388        struct kvec iov[1];
1389
1390        cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1391        if (tcon->ses->capabilities & CAP_LARGE_FILES)
1392                wct = 12;
1393        else {
1394                wct = 10; /* old style read */
1395                if ((lseek >> 32) > 0)  {
1396                        /* can not handle this big offset for old */
1397                        return -EIO;
1398                }
1399        }
1400
1401        *nbytes = 0;
1402        rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1403        if (rc)
1404                return rc;
1405
1406        /* tcon and ses pointer are checked in smb_init */
1407        if (tcon->ses->server == NULL)
1408                return -ECONNABORTED;
1409
1410        pSMB->AndXCommand = 0xFF;       /* none */
1411        pSMB->Fid = netfid;
1412        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1413        if (wct == 12)
1414                pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1415
1416        pSMB->Remaining = 0;
1417        pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1418        pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1419        if (wct == 12)
1420                pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
1421        else {
1422                /* old style read */
1423                struct smb_com_readx_req *pSMBW =
1424                        (struct smb_com_readx_req *)pSMB;
1425                pSMBW->ByteCount = 0;
1426        }
1427
1428        iov[0].iov_base = (char *)pSMB;
1429        iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1430        rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1431                         &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1432        cifs_stats_inc(&tcon->num_reads);
1433        pSMBr = (READ_RSP *)iov[0].iov_base;
1434        if (rc) {
1435                cERROR(1, ("Send error in read = %d", rc));
1436        } else {
1437                int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1438                data_length = data_length << 16;
1439                data_length += le16_to_cpu(pSMBr->DataLength);
1440                *nbytes = data_length;
1441
1442                /*check that DataLength would not go beyond end of SMB */
1443                if ((data_length > CIFSMaxBufSize)
1444                                || (data_length > count)) {
1445                        cFYI(1, ("bad length %d for count %d",
1446                                 data_length, count));
1447                        rc = -EIO;
1448                        *nbytes = 0;
1449                } else {
1450                        pReadData = (char *) (&pSMBr->hdr.Protocol) +
1451                                        le16_to_cpu(pSMBr->DataOffset);
1452/*                      if (rc = copy_to_user(buf, pReadData, data_length)) {
1453                                cERROR(1,("Faulting on read rc = %d",rc));
1454                                rc = -EFAULT;
1455                        }*/ /* can not use copy_to_user when using page cache*/
1456                        if (*buf)
1457                                memcpy(*buf, pReadData, data_length);
1458                }
1459        }
1460
1461/*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1462        if (*buf) {
1463                if (resp_buf_type == CIFS_SMALL_BUFFER)
1464                        cifs_small_buf_release(iov[0].iov_base);
1465                else if (resp_buf_type == CIFS_LARGE_BUFFER)
1466                        cifs_buf_release(iov[0].iov_base);
1467        } else if (resp_buf_type != CIFS_NO_BUFFER) {
1468                /* return buffer to caller to free */
1469                *buf = iov[0].iov_base;
1470                if (resp_buf_type == CIFS_SMALL_BUFFER)
1471                        *pbuf_type = CIFS_SMALL_BUFFER;
1472                else if (resp_buf_type == CIFS_LARGE_BUFFER)
1473                        *pbuf_type = CIFS_LARGE_BUFFER;
1474        } /* else no valid buffer on return - leave as null */
1475
1476        /* Note: On -EAGAIN error only caller can retry on handle based calls
1477                since file handle passed in no longer valid */
1478        return rc;
1479}
1480
1481
1482int
1483CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1484             const int netfid, const unsigned int count,
1485             const __u64 offset, unsigned int *nbytes, const char *buf,
1486             const char __user *ubuf, const int long_op)
1487{
1488        int rc = -EACCES;
1489        WRITE_REQ *pSMB = NULL;
1490        WRITE_RSP *pSMBr = NULL;
1491        int bytes_returned, wct;
1492        __u32 bytes_sent;
1493        __u16 byte_count;
1494
1495        /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1496        if (tcon->ses == NULL)
1497                return -ECONNABORTED;
1498
1499        if (tcon->ses->capabilities & CAP_LARGE_FILES)
1500                wct = 14;
1501        else {
1502                wct = 12;
1503                if ((offset >> 32) > 0) {
1504                        /* can not handle big offset for old srv */
1505                        return -EIO;
1506                }
1507        }
1508
1509        rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1510                      (void **) &pSMBr);
1511        if (rc)
1512                return rc;
1513        /* tcon and ses pointer are checked in smb_init */
1514        if (tcon->ses->server == NULL)
1515                return -ECONNABORTED;
1516
1517        pSMB->AndXCommand = 0xFF;       /* none */
1518        pSMB->Fid = netfid;
1519        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1520        if (wct == 14)
1521                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1522
1523        pSMB->Reserved = 0xFFFFFFFF;
1524        pSMB->WriteMode = 0;
1525        pSMB->Remaining = 0;
1526
1527        /* Can increase buffer size if buffer is big enough in some cases ie we
1528        can send more if LARGE_WRITE_X capability returned by the server and if
1529        our buffer is big enough or if we convert to iovecs on socket writes
1530        and eliminate the copy to the CIFS buffer */
1531        if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1532                bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1533        } else {
1534                bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1535                         & ~0xFF;
1536        }
1537
1538        if (bytes_sent > count)
1539                bytes_sent = count;
1540        pSMB->DataOffset =
1541                cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1542        if (buf)
1543                memcpy(pSMB->Data, buf, bytes_sent);
1544        else if (ubuf) {
1545                if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1546                        cifs_buf_release(pSMB);
1547                        return -EFAULT;
1548                }
1549        } else if (count != 0) {
1550                /* No buffer */
1551                cifs_buf_release(pSMB);
1552                return -EINVAL;
1553        } /* else setting file size with write of zero bytes */
1554        if (wct == 14)
1555                byte_count = bytes_sent + 1; /* pad */
1556        else /* wct == 12 */
1557                byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1558
1559        pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1560        pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1561        pSMB->hdr.smb_buf_length += byte_count;
1562
1563        if (wct == 14)
1564                pSMB->ByteCount = cpu_to_le16(byte_count);
1565        else { /* old style write has byte count 4 bytes earlier
1566                  so 4 bytes pad  */
1567                struct smb_com_writex_req *pSMBW =
1568                        (struct smb_com_writex_req *)pSMB;
1569                pSMBW->ByteCount = cpu_to_le16(byte_count);
1570        }
1571
1572        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1573                         (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1574        cifs_stats_inc(&tcon->num_writes);
1575        if (rc) {
1576                cFYI(1, ("Send error in write = %d", rc));
1577                *nbytes = 0;
1578        } else {
1579                *nbytes = le16_to_cpu(pSMBr->CountHigh);
1580                *nbytes = (*nbytes) << 16;
1581                *nbytes += le16_to_cpu(pSMBr->Count);
1582        }
1583
1584        cifs_buf_release(pSMB);
1585
1586        /* Note: On -EAGAIN error only caller can retry on handle based calls
1587                since file handle passed in no longer valid */
1588
1589        return rc;
1590}
1591
1592int
1593CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1594             const int netfid, const unsigned int count,
1595             const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1596             int n_vec, const int long_op)
1597{
1598        int rc = -EACCES;
1599        WRITE_REQ *pSMB = NULL;
1600        int wct;
1601        int smb_hdr_len;
1602        int resp_buf_type = 0;
1603
1604        *nbytes = 0;
1605
1606        cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1607
1608        if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1609                wct = 14;
1610        } else {
1611                wct = 12;
1612                if ((offset >> 32) > 0) {
1613                        /* can not handle big offset for old srv */
1614                        return -EIO;
1615                }
1616        }
1617        rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1618        if (rc)
1619                return rc;
1620        /* tcon and ses pointer are checked in smb_init */
1621        if (tcon->ses->server == NULL)
1622                return -ECONNABORTED;
1623
1624        pSMB->AndXCommand = 0xFF;       /* none */
1625        pSMB->Fid = netfid;
1626        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1627        if (wct == 14)
1628                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1629        pSMB->Reserved = 0xFFFFFFFF;
1630        pSMB->WriteMode = 0;
1631        pSMB->Remaining = 0;
1632
1633        pSMB->DataOffset =
1634            cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1635
1636        pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1637        pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1638        smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1639        if (wct == 14)
1640                pSMB->hdr.smb_buf_length += count+1;
1641        else /* wct == 12 */
1642                pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1643        if (wct == 14)
1644                pSMB->ByteCount = cpu_to_le16(count + 1);
1645        else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1646                struct smb_com_writex_req *pSMBW =
1647                                (struct smb_com_writex_req *)pSMB;
1648                pSMBW->ByteCount = cpu_to_le16(count + 5);
1649        }
1650        iov[0].iov_base = pSMB;
1651        if (wct == 14)
1652                iov[0].iov_len = smb_hdr_len + 4;
1653        else /* wct == 12 pad bigger by four bytes */
1654                iov[0].iov_len = smb_hdr_len + 8;
1655
1656
1657        rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1658                          long_op);
1659        cifs_stats_inc(&tcon->num_writes);
1660        if (rc) {
1661                cFYI(1, ("Send error Write2 = %d", rc));
1662        } else if (resp_buf_type == 0) {
1663                /* presumably this can not happen, but best to be safe */
1664                rc = -EIO;
1665        } else {
1666                WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1667                *nbytes = le16_to_cpu(pSMBr->CountHigh);
1668                *nbytes = (*nbytes) << 16;
1669                *nbytes += le16_to_cpu(pSMBr->Count);
1670        }
1671
1672/*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1673        if (resp_buf_type == CIFS_SMALL_BUFFER)
1674                cifs_small_buf_release(iov[0].iov_base);
1675        else if (resp_buf_type == CIFS_LARGE_BUFFER)
1676                cifs_buf_release(iov[0].iov_base);
1677
1678        /* Note: On -EAGAIN error only caller can retry on handle based calls
1679                since file handle passed in no longer valid */
1680
1681        return rc;
1682}
1683
1684
1685int
1686CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1687            const __u16 smb_file_id, const __u64 len,
1688            const __u64 offset, const __u32 numUnlock,
1689            const __u32 numLock, const __u8 lockType, const bool waitFlag)
1690{
1691        int rc = 0;
1692        LOCK_REQ *pSMB = NULL;
1693/*      LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1694        int bytes_returned;
1695        int timeout = 0;
1696        __u16 count;
1697
1698        cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1699        rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1700
1701        if (rc)
1702                return rc;
1703
1704        if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1705                timeout = CIFS_ASYNC_OP; /* no response expected */
1706                pSMB->Timeout = 0;
1707        } else if (waitFlag) {
1708                timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1709                pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1710        } else {
1711                pSMB->Timeout = 0;
1712        }
1713
1714        pSMB->NumberOfLocks = cpu_to_le16(numLock);
1715        pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1716        pSMB->LockType = lockType;
1717        pSMB->AndXCommand = 0xFF;       /* none */
1718        pSMB->Fid = smb_file_id; /* netfid stays le */
1719
1720        if ((numLock != 0) || (numUnlock != 0)) {
1721                pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1722                /* BB where to store pid high? */
1723                pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1724                pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1725                pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1726                pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1727                count = sizeof(LOCKING_ANDX_RANGE);
1728        } else {
1729                /* oplock break */
1730                count = 0;
1731        }
1732        pSMB->hdr.smb_buf_length += count;
1733        pSMB->ByteCount = cpu_to_le16(count);
1734
1735        if (waitFlag) {
1736                rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1737                        (struct smb_hdr *) pSMB, &bytes_returned);
1738                cifs_small_buf_release(pSMB);
1739        } else {
1740                rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1741                                      timeout);
1742                /* SMB buffer freed by function above */
1743        }
1744        cifs_stats_inc(&tcon->num_locks);
1745        if (rc)
1746                cFYI(1, ("Send error in Lock = %d", rc));
1747
1748        /* Note: On -EAGAIN error only caller can retry on handle based calls
1749        since file handle passed in no longer valid */
1750        return rc;
1751}
1752
1753int
1754CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1755                const __u16 smb_file_id, const int get_flag, const __u64 len,
1756                struct file_lock *pLockData, const __u16 lock_type,
1757                const bool waitFlag)
1758{
1759        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1760        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1761        struct cifs_posix_lock *parm_data;
1762        int rc = 0;
1763        int timeout = 0;
1764        int bytes_returned = 0;
1765        int resp_buf_type = 0;
1766        __u16 params, param_offset, offset, byte_count, count;
1767        struct kvec iov[1];
1768
1769        cFYI(1, ("Posix Lock"));
1770
1771        if (pLockData == NULL)
1772                return -EINVAL;
1773
1774        rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1775
1776        if (rc)
1777                return rc;
1778
1779        pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1780
1781        params = 6;
1782        pSMB->MaxSetupCount = 0;
1783        pSMB->Reserved = 0;
1784        pSMB->Flags = 0;
1785        pSMB->Reserved2 = 0;
1786        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1787        offset = param_offset + params;
1788
1789        count = sizeof(struct cifs_posix_lock);
1790        pSMB->MaxParameterCount = cpu_to_le16(2);
1791        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1792        pSMB->SetupCount = 1;
1793        pSMB->Reserved3 = 0;
1794        if (get_flag)
1795                pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1796        else
1797                pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1798        byte_count = 3 /* pad */  + params + count;
1799        pSMB->DataCount = cpu_to_le16(count);
1800        pSMB->ParameterCount = cpu_to_le16(params);
1801        pSMB->TotalDataCount = pSMB->DataCount;
1802        pSMB->TotalParameterCount = pSMB->ParameterCount;
1803        pSMB->ParameterOffset = cpu_to_le16(param_offset);
1804        parm_data = (struct cifs_posix_lock *)
1805                        (((char *) &pSMB->hdr.Protocol) + offset);
1806
1807        parm_data->lock_type = cpu_to_le16(lock_type);
1808        if (waitFlag) {
1809                timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1810                parm_data->lock_flags = cpu_to_le16(1);
1811                pSMB->Timeout = cpu_to_le32(-1);
1812        } else
1813                pSMB->Timeout = 0;
1814
1815        parm_data->pid = cpu_to_le32(current->tgid);
1816        parm_data->start = cpu_to_le64(pLockData->fl_start);
1817        parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
1818
1819        pSMB->DataOffset = cpu_to_le16(offset);
1820        pSMB->Fid = smb_file_id;
1821        pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1822        pSMB->Reserved4 = 0;
1823        pSMB->hdr.smb_buf_length += byte_count;
1824        pSMB->ByteCount = cpu_to_le16(byte_count);
1825        if (waitFlag) {
1826                rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1827                        (struct smb_hdr *) pSMBr, &bytes_returned);
1828        } else {
1829                iov[0].iov_base = (char *)pSMB;
1830                iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1831                rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1832                                &resp_buf_type, timeout);
1833                pSMB = NULL; /* request buf already freed by SendReceive2. Do
1834                                not try to free it twice below on exit */
1835                pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1836        }
1837
1838        if (rc) {
1839                cFYI(1, ("Send error in Posix Lock = %d", rc));
1840        } else if (get_flag) {
1841                /* lock structure can be returned on get */
1842                __u16 data_offset;
1843                __u16 data_count;
1844                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1845
1846                if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1847                        rc = -EIO;      /* bad smb */
1848                        goto plk_err_exit;
1849                }
1850                data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1851                data_count  = le16_to_cpu(pSMBr->t2.DataCount);
1852                if (data_count < sizeof(struct cifs_posix_lock)) {
1853                        rc = -EIO;
1854                        goto plk_err_exit;
1855                }
1856                parm_data = (struct cifs_posix_lock *)
1857                        ((char *)&pSMBr->hdr.Protocol + data_offset);
1858                if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1859                        pLockData->fl_type = F_UNLCK;
1860        }
1861
1862plk_err_exit:
1863        if (pSMB)
1864                cifs_small_buf_release(pSMB);
1865
1866        if (resp_buf_type == CIFS_SMALL_BUFFER)
1867                cifs_small_buf_release(iov[0].iov_base);
1868        else if (resp_buf_type == CIFS_LARGE_BUFFER)
1869                cifs_buf_release(iov[0].iov_base);
1870
1871        /* Note: On -EAGAIN error only caller can retry on handle based calls
1872           since file handle passed in no longer valid */
1873
1874        return rc;
1875}
1876
1877
1878int
1879CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1880{
1881        int rc = 0;
1882        CLOSE_REQ *pSMB = NULL;
1883        cFYI(1, ("In CIFSSMBClose"));
1884
1885/* do not retry on dead session on close */
1886        rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1887        if (rc == -EAGAIN)
1888                return 0;
1889        if (rc)
1890                return rc;
1891
1892        pSMB->FileID = (__u16) smb_file_id;
1893        pSMB->LastWriteTime = 0xFFFFFFFF;
1894        pSMB->ByteCount = 0;
1895        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1896        cifs_stats_inc(&tcon->num_closes);
1897        if (rc) {
1898                if (rc != -EINTR) {
1899                        /* EINTR is expected when user ctl-c to kill app */
1900                        cERROR(1, ("Send error in Close = %d", rc));
1901                }
1902        }
1903
1904        /* Since session is dead, file will be closed on server already */
1905        if (rc == -EAGAIN)
1906                rc = 0;
1907
1908        return rc;
1909}
1910
1911int
1912CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1913{
1914        int rc = 0;
1915        FLUSH_REQ *pSMB = NULL;
1916        cFYI(1, ("In CIFSSMBFlush"));
1917
1918        rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1919        if (rc)
1920                return rc;
1921
1922        pSMB->FileID = (__u16) smb_file_id;
1923        pSMB->ByteCount = 0;
1924        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1925        cifs_stats_inc(&tcon->num_flushes);
1926        if (rc)
1927                cERROR(1, ("Send error in Flush = %d", rc));
1928
1929        return rc;
1930}
1931
1932int
1933CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1934              const char *fromName, const char *toName,
1935              const struct nls_table *nls_codepage, int remap)
1936{
1937        int rc = 0;
1938        RENAME_REQ *pSMB = NULL;
1939        RENAME_RSP *pSMBr = NULL;
1940        int bytes_returned;
1941        int name_len, name_len2;
1942        __u16 count;
1943
1944        cFYI(1, ("In CIFSSMBRename"));
1945renameRetry:
1946        rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1947                      (void **) &pSMBr);
1948        if (rc)
1949                return rc;
1950
1951        pSMB->BufferFormat = 0x04;
1952        pSMB->SearchAttributes =
1953            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1954                        ATTR_DIRECTORY);
1955
1956        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1957                name_len =
1958                    cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1959                                     PATH_MAX, nls_codepage, remap);
1960                name_len++;     /* trailing null */
1961                name_len *= 2;
1962                pSMB->OldFileName[name_len] = 0x04;     /* pad */
1963        /* protocol requires ASCII signature byte on Unicode string */
1964                pSMB->OldFileName[name_len + 1] = 0x00;
1965                name_len2 =
1966                    cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1967                                     toName, PATH_MAX, nls_codepage, remap);
1968                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1969                name_len2 *= 2; /* convert to bytes */
1970        } else {        /* BB improve the check for buffer overruns BB */
1971                name_len = strnlen(fromName, PATH_MAX);
1972                name_len++;     /* trailing null */
1973                strncpy(pSMB->OldFileName, fromName, name_len);
1974                name_len2 = strnlen(toName, PATH_MAX);
1975                name_len2++;    /* trailing null */
1976                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1977                strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1978                name_len2++;    /* trailing null */
1979                name_len2++;    /* signature byte */
1980        }
1981
1982        count = 1 /* 1st signature byte */  + name_len + name_len2;
1983        pSMB->hdr.smb_buf_length += count;
1984        pSMB->ByteCount = cpu_to_le16(count);
1985
1986        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1987                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1988        cifs_stats_inc(&tcon->num_renames);
1989        if (rc)
1990                cFYI(1, ("Send error in rename = %d", rc));
1991
1992        cifs_buf_release(pSMB);
1993
1994        if (rc == -EAGAIN)
1995                goto renameRetry;
1996
1997        return rc;
1998}
1999
2000int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2001                int netfid, const char *target_name,
2002                const struct nls_table *nls_codepage, int remap)
2003{
2004        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
2005        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2006        struct set_file_rename *rename_info;
2007        char *data_offset;
2008        char dummy_string[30];
2009        int rc = 0;
2010        int bytes_returned = 0;
2011        int len_of_str;
2012        __u16 params, param_offset, offset, count, byte_count;
2013
2014        cFYI(1, ("Rename to File by handle"));
2015        rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2016                        (void **) &pSMBr);
2017        if (rc)
2018                return rc;
2019
2020        params = 6;
2021        pSMB->MaxSetupCount = 0;
2022        pSMB->Reserved = 0;
2023        pSMB->Flags = 0;
2024        pSMB->Timeout = 0;
2025        pSMB->Reserved2 = 0;
2026        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2027        offset = param_offset + params;
2028
2029        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2030        rename_info = (struct set_file_rename *) data_offset;
2031        pSMB->MaxParameterCount = cpu_to_le16(2);
2032        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2033        pSMB->SetupCount = 1;
2034        pSMB->Reserved3 = 0;
2035        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2036        byte_count = 3 /* pad */  + params;
2037        pSMB->ParameterCount = cpu_to_le16(params);
2038        pSMB->TotalParameterCount = pSMB->ParameterCount;
2039        pSMB->ParameterOffset = cpu_to_le16(param_offset);
2040        pSMB->DataOffset = cpu_to_le16(offset);
2041        /* construct random name ".cifs_tmp<inodenum><mid>" */
2042        rename_info->overwrite = cpu_to_le32(1);
2043        rename_info->root_fid  = 0;
2044        /* unicode only call */
2045        if (target_name == NULL) {
2046                sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2047                len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2048                                        dummy_string, 24, nls_codepage, remap);
2049        } else {
2050                len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2051                                        target_name, PATH_MAX, nls_codepage,
2052                                        remap);
2053        }
2054        rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2055        count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2056        byte_count += count;
2057        pSMB->DataCount = cpu_to_le16(count);
2058        pSMB->TotalDataCount = pSMB->DataCount;
2059        pSMB->Fid = netfid;
2060        pSMB->InformationLevel =
2061                cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2062        pSMB->Reserved4 = 0;
2063        pSMB->hdr.smb_buf_length += byte_count;
2064        pSMB->ByteCount = cpu_to_le16(byte_count);
2065        rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2066                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2067        cifs_stats_inc(&pTcon->num_t2renames);
2068        if (rc)
2069                cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2070
2071        cifs_buf_release(pSMB);
2072
2073        /* Note: On -EAGAIN error only caller can retry on handle based calls
2074                since file handle passed in no longer valid */
2075
2076        return rc;
2077}
2078
2079int
2080CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2081            const __u16 target_tid, const char *toName, const int flags,
2082            const struct nls_table *nls_codepage, int remap)
2083{
2084        int rc = 0;
2085        COPY_REQ *pSMB = NULL;
2086        COPY_RSP *pSMBr = NULL;
2087        int bytes_returned;
2088        int name_len, name_len2;
2089        __u16 count;
2090
2091        cFYI(1, ("In CIFSSMBCopy"));
2092copyRetry:
2093        rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2094                        (void **) &pSMBr);
2095        if (rc)
2096                return rc;
2097
2098        pSMB->BufferFormat = 0x04;
2099        pSMB->Tid2 = target_tid;
2100
2101        pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2102
2103        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2104                name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2105                                            fromName, PATH_MAX, nls_codepage,
2106                                            remap);
2107                name_len++;     /* trailing null */
2108                name_len *= 2;
2109                pSMB->OldFileName[name_len] = 0x04;     /* pad */
2110                /* protocol requires ASCII signature byte on Unicode string */
2111                pSMB->OldFileName[name_len + 1] = 0x00;
2112                name_len2 =
2113                    cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2114                                toName, PATH_MAX, nls_codepage, remap);
2115                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2116                name_len2 *= 2; /* convert to bytes */
2117        } else {        /* BB improve the check for buffer overruns BB */
2118                name_len = strnlen(fromName, PATH_MAX);
2119                name_len++;     /* trailing null */
2120                strncpy(pSMB->OldFileName, fromName, name_len);
2121                name_len2 = strnlen(toName, PATH_MAX);
2122                name_len2++;    /* trailing null */
2123                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
2124                strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2125                name_len2++;    /* trailing null */
2126                name_len2++;    /* signature byte */
2127        }
2128
2129        count = 1 /* 1st signature byte */  + name_len + name_len2;
2130        pSMB->hdr.smb_buf_length += count;
2131        pSMB->ByteCount = cpu_to_le16(count);
2132
2133        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2134                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2135        if (rc) {
2136                cFYI(1, ("Send error in copy = %d with %d files copied",
2137                        rc, le16_to_cpu(pSMBr->CopyCount)));
2138        }
2139        cifs_buf_release(pSMB);
2140
2141        if (rc == -EAGAIN)
2142                goto copyRetry;
2143
2144        return rc;
2145}
2146
2147int
2148CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2149                      const char *fromName, const char *toName,
2150                      const struct nls_table *nls_codepage)
2151{
2152        TRANSACTION2_SPI_REQ *pSMB = NULL;
2153        TRANSACTION2_SPI_RSP *pSMBr = NULL;
2154        char *data_offset;
2155        int name_len;
2156        int name_len_target;
2157        int rc = 0;
2158        int bytes_returned = 0;
2159        __u16 params, param_offset, offset, byte_count;
2160
2161        cFYI(1, ("In Symlink Unix style"));
2162createSymLinkRetry:
2163        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2164                      (void **) &pSMBr);
2165        if (rc)
2166                return rc;
2167
2168        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2169                name_len =
2170                    cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2171                                  /* find define for this maxpathcomponent */
2172                                  , nls_codepage);
2173                name_len++;     /* trailing null */
2174                name_len *= 2;
2175
2176        } else {        /* BB improve the check for buffer overruns BB */
2177                name_len = strnlen(fromName, PATH_MAX);
2178                name_len++;     /* trailing null */
2179                strncpy(pSMB->FileName, fromName, name_len);
2180        }
2181        params = 6 + name_len;
2182        pSMB->MaxSetupCount = 0;
2183        pSMB->Reserved = 0;
2184        pSMB->Flags = 0;
2185        pSMB->Timeout = 0;
2186        pSMB->Reserved2 = 0;
2187        param_offset = offsetof(struct smb_com_transaction2_spi_req,
2188                                InformationLevel) - 4;
2189        offset = param_offset + params;
2190
2191        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2192        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2193                name_len_target =
2194                    cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2195                                  /* find define for this maxpathcomponent */
2196                                  , nls_codepage);
2197                name_len_target++;      /* trailing null */
2198                name_len_target *= 2;
2199        } else {        /* BB improve the check for buffer overruns BB */
2200                name_len_target = strnlen(toName, PATH_MAX);
2201                name_len_target++;      /* trailing null */
2202                strncpy(data_offset, toName, name_len_target);
2203        }
2204
2205        pSMB->MaxParameterCount = cpu_to_le16(2);
2206        /* BB find exact max on data count below from sess */
2207        pSMB->MaxDataCount = cpu_to_le16(1000);
2208        pSMB->SetupCount = 1;
2209        pSMB->Reserved3 = 0;
2210        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2211        byte_count = 3 /* pad */  + params + name_len_target;
2212        pSMB->DataCount = cpu_to_le16(name_len_target);
2213        pSMB->ParameterCount = cpu_to_le16(params);
2214        pSMB->TotalDataCount = pSMB->DataCount;
2215        pSMB->TotalParameterCount = pSMB->ParameterCount;
2216        pSMB->ParameterOffset = cpu_to_le16(param_offset);
2217        pSMB->DataOffset = cpu_to_le16(offset);
2218        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2219        pSMB->Reserved4 = 0;
2220        pSMB->hdr.smb_buf_length += byte_count;
2221        pSMB->ByteCount = cpu_to_le16(byte_count);
2222        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2223                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2224        cifs_stats_inc(&tcon->num_symlinks);
2225        if (rc)
2226                cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2227
2228        cifs_buf_release(pSMB);
2229
2230        if (rc == -EAGAIN)
2231                goto createSymLinkRetry;
2232
2233        return rc;
2234}
2235
2236int
2237CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2238                       const char *fromName, const char *toName,
2239                       const struct nls_table *nls_codepage, int remap)
2240{
2241        TRANSACTION2_SPI_REQ *pSMB = NULL;
2242        TRANSACTION2_SPI_RSP *pSMBr = NULL;
2243        char *data_offset;
2244        int name_len;
2245        int name_len_target;
2246        int rc = 0;
2247        int bytes_returned = 0;
2248        __u16 params, param_offset, offset, byte_count;
2249
2250        cFYI(1, ("In Create Hard link Unix style"));
2251createHardLinkRetry:
2252        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2253                      (void **) &pSMBr);
2254        if (rc)
2255                return rc;
2256
2257        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2258                name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2259                                            PATH_MAX, nls_codepage, remap);
2260                name_len++;     /* trailing null */
2261                name_len *= 2;
2262
2263        } else {        /* BB improve the check for buffer overruns BB */
2264                name_len = strnlen(toName, PATH_MAX);
2265                name_len++;     /* trailing null */
2266                strncpy(pSMB->FileName, toName, name_len);
2267        }
2268        params = 6 + name_len;
2269        pSMB->MaxSetupCount = 0;
2270        pSMB->Reserved = 0;
2271        pSMB->Flags = 0;
2272        pSMB->Timeout = 0;
2273        pSMB->Reserved2 = 0;
2274        param_offset = offsetof(struct smb_com_transaction2_spi_req,
2275                                InformationLevel) - 4;
2276        offset = param_offset + params;
2277
2278        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2279        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2280                name_len_target =
2281                    cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2282                                     nls_codepage, remap);
2283                name_len_target++;      /* trailing null */
2284                name_len_target *= 2;
2285        } else {        /* BB improve the check for buffer overruns BB */
2286                name_len_target = strnlen(fromName, PATH_MAX);
2287                name_len_target++;      /* trailing null */
2288                strncpy(data_offset, fromName, name_len_target);
2289        }
2290
2291        pSMB->MaxParameterCount = cpu_to_le16(2);
2292        /* BB find exact max on data count below from sess*/
2293        pSMB->MaxDataCount = cpu_to_le16(1000);
2294        pSMB->SetupCount = 1;
2295        pSMB->Reserved3 = 0;
2296        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2297        byte_count = 3 /* pad */  + params + name_len_target;
2298        pSMB->ParameterCount = cpu_to_le16(params);
2299        pSMB->TotalParameterCount = pSMB->ParameterCount;
2300        pSMB->DataCount = cpu_to_le16(name_len_target);
2301        pSMB->TotalDataCount = pSMB->DataCount;
2302        pSMB->ParameterOffset = cpu_to_le16(param_offset);
2303        pSMB->DataOffset = cpu_to_le16(offset);
2304        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2305        pSMB->Reserved4 = 0;
2306        pSMB->hdr.smb_buf_length += byte_count;
2307        pSMB->ByteCount = cpu_to_le16(byte_count);
2308        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2309                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2310        cifs_stats_inc(&tcon->num_hardlinks);
2311        if (rc)
2312                cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2313
2314        cifs_buf_release(pSMB);
2315        if (rc == -EAGAIN)
2316                goto createHardLinkRetry;
2317
2318        return rc;
2319}
2320
2321int
2322CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2323                   const char *fromName, const char *toName,
2324                   const struct nls_table *nls_codepage, int remap)
2325{
2326        int rc = 0;
2327        NT_RENAME_REQ *pSMB = NULL;
2328        RENAME_RSP *pSMBr = NULL;
2329        int bytes_returned;
2330        int name_len, name_len2;
2331        __u16 count;
2332
2333        cFYI(1, ("In CIFSCreateHardLink"));
2334winCreateHardLinkRetry:
2335
2336        rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2337                      (void **) &pSMBr);
2338        if (rc)
2339                return rc;
2340
2341        pSMB->SearchAttributes =
2342            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2343                        ATTR_DIRECTORY);
2344        pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2345        pSMB->ClusterCount = 0;
2346
2347        pSMB->BufferFormat = 0x04;
2348
2349        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2350                name_len =
2351                    cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2352                                     PATH_MAX, nls_codepage, remap);
2353                name_len++;     /* trailing null */
2354                name_len *= 2;
2355
2356                /* protocol specifies ASCII buffer format (0x04) for unicode */
2357                pSMB->OldFileName[name_len] = 0x04;
2358                pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2359                name_len2 =
2360                    cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2361                                     toName, PATH_MAX, nls_codepage, remap);
2362                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
2363                name_len2 *= 2; /* convert to bytes */
2364        } else {        /* BB improve the check for buffer overruns BB */
2365                name_len = strnlen(fromName, PATH_MAX);
2366                name_len++;     /* trailing null */
2367                strncpy(pSMB->OldFileName, fromName, name_len);
2368                name_len2 = strnlen(toName, PATH_MAX);
2369                name_len2++;    /* trailing null */
2370                pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
2371                strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2372                name_len2++;    /* trailing null */
2373                name_len2++;    /* signature byte */
2374        }
2375
2376        count = 1 /* string type byte */  + name_len + name_len2;
2377        pSMB->hdr.smb_buf_length += count;
2378        pSMB->ByteCount = cpu_to_le16(count);
2379
2380        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2381                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2382        cifs_stats_inc(&tcon->num_hardlinks);
2383        if (rc)
2384                cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2385
2386        cifs_buf_release(pSMB);
2387        if (rc == -EAGAIN)
2388                goto winCreateHardLinkRetry;
2389
2390        return rc;
2391}
2392
2393int
2394CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2395                        const unsigned char *searchName, char **symlinkinfo,
2396                        const struct nls_table *nls_codepage)
2397{
2398/* SMB_QUERY_FILE_UNIX_LINK */
2399        TRANSACTION2_QPI_REQ *pSMB = NULL;
2400        TRANSACTION2_QPI_RSP *pSMBr = NULL;
2401        int rc = 0;
2402        int bytes_returned;
2403        int name_len;
2404        __u16 params, byte_count;
2405        char *data_start;
2406
2407        cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2408
2409querySymLinkRetry:
2410        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2411                      (void **) &pSMBr);
2412        if (rc)
2413                return rc;
2414
2415        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2416                name_len =
2417                    cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2418                                  PATH_MAX, nls_codepage);
2419                name_len++;     /* trailing null */
2420                name_len *= 2;
2421        } else {        /* BB improve the check for buffer overruns BB */
2422                name_len = strnlen(searchName, PATH_MAX);
2423                name_len++;     /* trailing null */
2424                strncpy(pSMB->FileName, searchName, name_len);
2425        }
2426
2427        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2428        pSMB->TotalDataCount = 0;
2429        pSMB->MaxParameterCount = cpu_to_le16(2);
2430        /* BB find exact max data count below from sess structure BB */
2431        pSMB->MaxDataCount = cpu_to_le16(4000);
2432        pSMB->MaxSetupCount = 0;
2433        pSMB->Reserved = 0;
2434        pSMB->Flags = 0;
2435        pSMB->Timeout = 0;
2436        pSMB->Reserved2 = 0;
2437        pSMB->ParameterOffset = cpu_to_le16(offsetof(
2438        struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2439        pSMB->DataCount = 0;
2440        pSMB->DataOffset = 0;
2441        pSMB->SetupCount = 1;
2442        pSMB->Reserved3 = 0;
2443        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2444        byte_count = params + 1 /* pad */ ;
2445        pSMB->TotalParameterCount = cpu_to_le16(params);
2446        pSMB->ParameterCount = pSMB->TotalParameterCount;
2447        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2448        pSMB->Reserved4 = 0;
2449        pSMB->hdr.smb_buf_length += byte_count;
2450        pSMB->ByteCount = cpu_to_le16(byte_count);
2451
2452        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2453                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2454        if (rc) {
2455                cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2456        } else {
2457                /* decode response */
2458
2459                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2460                /* BB also check enough total bytes returned */
2461                if (rc || (pSMBr->ByteCount < 2))
2462                        rc = -EIO;
2463                else {
2464                        bool is_unicode;
2465                        u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2466
2467                        data_start = ((char *) &pSMBr->hdr.Protocol) +
2468                                           le16_to_cpu(pSMBr->t2.DataOffset);
2469
2470                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2471                                is_unicode = true;
2472                        else
2473                                is_unicode = false;
2474
2475                        /* BB FIXME investigate remapping reserved chars here */
2476                        *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2477                                                    is_unicode, nls_codepage);
2478                        if (!*symlinkinfo)
2479                                rc = -ENOMEM;
2480                }
2481        }
2482        cifs_buf_release(pSMB);
2483        if (rc == -EAGAIN)
2484                goto querySymLinkRetry;
2485        return rc;
2486}
2487
2488#ifdef CONFIG_CIFS_EXPERIMENTAL
2489/* Initialize NT TRANSACT SMB into small smb request buffer.
2490   This assumes that all NT TRANSACTS that we init here have
2491   total parm and data under about 400 bytes (to fit in small cifs
2492   buffer size), which is the case so far, it easily fits. NB:
2493        Setup words themselves and ByteCount
2494        MaxSetupCount (size of returned setup area) and
2495        MaxParameterCount (returned parms size) must be set by caller */
2496static int
2497smb_init_nttransact(const __u16 sub_command, const int setup_count,
2498                   const int parm_len, struct cifsTconInfo *tcon,
2499                   void **ret_buf)
2500{
2501        int rc;
2502        __u32 temp_offset;
2503        struct smb_com_ntransact_req *pSMB;
2504
2505        rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2506                                (void **)&pSMB);
2507        if (rc)
2508                return rc;
2509        *ret_buf = (void *)pSMB;
2510        pSMB->Reserved = 0;
2511        pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2512        pSMB->TotalDataCount  = 0;
2513        pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2514                                          MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2515        pSMB->ParameterCount = pSMB->TotalParameterCount;
2516        pSMB->DataCount  = pSMB->TotalDataCount;
2517        temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2518                        (setup_count * 2) - 4 /* for rfc1001 length itself */;
2519        pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2520        pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2521        pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2522        pSMB->SubCommand = cpu_to_le16(sub_command);
2523        return 0;
2524}
2525
2526static int
2527validate_ntransact(char *buf, char **ppparm, char **ppdata,
2528                   __u32 *pparmlen, __u32 *pdatalen)
2529{
2530        char *end_of_smb;
2531        __u32 data_count, data_offset, parm_count, parm_offset;
2532        struct smb_com_ntransact_rsp *pSMBr;
2533
2534        *pdatalen = 0;
2535        *pparmlen = 0;
2536
2537        if (buf == NULL)
2538                return -EINVAL;
2539
2540        pSMBr = (struct smb_com_ntransact_rsp *)buf;
2541
2542        /* ByteCount was converted from little endian in SendReceive */
2543        end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2544                        (char *)&pSMBr->ByteCount;
2545
2546        data_offset = le32_to_cpu(pSMBr->DataOffset);
2547        data_count = le32_to_cpu(pSMBr->DataCount);
2548        parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2549        parm_count = le32_to_cpu(pSMBr->ParameterCount);
2550
2551        *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2552        *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2553
2554        /* should we also check that parm and data areas do not overlap? */
2555        if (*ppparm > end_of_smb) {
2556                cFYI(1, ("parms start after end of smb"));
2557                return -EINVAL;
2558        } else if (parm_count + *ppparm > end_of_smb) {
2559                cFYI(1, ("parm end after end of smb"));
2560                return -EINVAL;
2561        } else if (*ppdata > end_of_smb) {
2562                cFYI(1, ("data starts after end of smb"));
2563                return -EINVAL;
2564        } else if (data_count + *ppdata > end_of_smb) {
2565                cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2566                        *ppdata, data_count, (data_count + *ppdata),
2567                        end_of_smb, pSMBr));
2568                return -EINVAL;
2569        } else if (parm_count + data_count > pSMBr->ByteCount) {
2570                cFYI(1, ("parm count and data count larger than SMB"));
2571                return -EINVAL;
2572        }
2573        *pdatalen = data_count;
2574        *pparmlen = parm_count;
2575        return 0;
2576}
2577
2578int
2579CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2580                        const unsigned char *searchName,
2581                        char *symlinkinfo, const int buflen, __u16 fid,
2582                        const struct nls_table *nls_codepage)
2583{
2584        int rc = 0;
2585        int bytes_returned;
2586        struct smb_com_transaction_ioctl_req *pSMB;
2587        struct smb_com_transaction_ioctl_rsp *pSMBr;
2588
2589        cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2590        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2591                      (void **) &pSMBr);
2592        if (rc)
2593                return rc;
2594
2595        pSMB->TotalParameterCount = 0 ;
2596        pSMB->TotalDataCount = 0;
2597        pSMB->MaxParameterCount = cpu_to_le32(2);
2598        /* BB find exact data count max from sess structure BB */
2599        pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2600                                          MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2601        pSMB->MaxSetupCount = 4;
2602        pSMB->Reserved = 0;
2603        pSMB->ParameterOffset = 0;
2604        pSMB->DataCount = 0;
2605        pSMB->DataOffset = 0;
2606        pSMB->SetupCount = 4;
2607        pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2608        pSMB->ParameterCount = pSMB->TotalParameterCount;
2609        pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2610        pSMB->IsFsctl = 1; /* FSCTL */
2611        pSMB->IsRootFlag = 0;
2612        pSMB->Fid = fid; /* file handle always le */
2613        pSMB->ByteCount = 0;
2614
2615        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2616                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2617        if (rc) {
2618                cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2619        } else {                /* decode response */
2620                __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2621                __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2622                if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2623                /* BB also check enough total bytes returned */
2624                        rc = -EIO;      /* bad smb */
2625                        goto qreparse_out;
2626                }
2627                if (data_count && (data_count < 2048)) {
2628                        char *end_of_smb = 2 /* sizeof byte count */ +
2629                                pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2630
2631                        struct reparse_data *reparse_buf =
2632                                                (struct reparse_data *)
2633                                                ((char *)&pSMBr->hdr.Protocol
2634                                                                 + data_offset);
2635                        if ((char *)reparse_buf >= end_of_smb) {
2636                                rc = -EIO;
2637                                goto qreparse_out;
2638                        }
2639                        if ((reparse_buf->LinkNamesBuf +
2640                                reparse_buf->TargetNameOffset +
2641                                reparse_buf->TargetNameLen) > end_of_smb) {
2642                                cFYI(1, ("reparse buf beyond SMB"));
2643                                rc = -EIO;
2644                                goto qreparse_out;
2645                        }
2646
2647                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2648                                cifs_from_ucs2(symlinkinfo, (__le16 *)
2649                                                (reparse_buf->LinkNamesBuf +
2650                                                reparse_buf->TargetNameOffset),
2651                                                buflen,
2652                                                reparse_buf->TargetNameLen,
2653                                                nls_codepage, 0);
2654                        } else { /* ASCII names */
2655                                strncpy(symlinkinfo,
2656                                        reparse_buf->LinkNamesBuf +
2657                                        reparse_buf->TargetNameOffset,
2658                                        min_t(const int, buflen,
2659                                           reparse_buf->TargetNameLen));
2660                        }
2661                } else {
2662                        rc = -EIO;
2663                        cFYI(1, ("Invalid return data count on "
2664                                 "get reparse info ioctl"));
2665                }
2666                symlinkinfo[buflen] = 0; /* just in case so the caller
2667                                        does not go off the end of the buffer */
2668                cFYI(1, ("readlink result - %s", symlinkinfo));
2669        }
2670
2671qreparse_out:
2672        cifs_buf_release(pSMB);
2673
2674        /* Note: On -EAGAIN error only caller can retry on handle based calls
2675                since file handle passed in no longer valid */
2676
2677        return rc;
2678}
2679#endif /* CIFS_EXPERIMENTAL */
2680
2681#ifdef CONFIG_CIFS_POSIX
2682
2683/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2684static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2685                             struct cifs_posix_ace *cifs_ace)
2686{
2687        /* u8 cifs fields do not need le conversion */
2688        ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2689        ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2690        ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2691        /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2692
2693        return;
2694}
2695
2696/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2697static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2698                               const int acl_type, const int size_of_data_area)
2699{
2700        int size =  0;
2701        int i;
2702        __u16 count;
2703        struct cifs_posix_ace *pACE;
2704        struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2705        posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2706
2707        if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2708                return -EOPNOTSUPP;
2709
2710        if (acl_type & ACL_TYPE_ACCESS) {
2711                count = le16_to_cpu(cifs_acl->access_entry_count);
2712                pACE = &cifs_acl->ace_array[0];
2713                size = sizeof(struct cifs_posix_acl);
2714                size += sizeof(struct cifs_posix_ace) * count;
2715                /* check if we would go beyond end of SMB */
2716                if (size_of_data_area < size) {
2717                        cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2718                                size_of_data_area, size));
2719                        return -EINVAL;
2720                }
2721        } else if (acl_type & ACL_TYPE_DEFAULT) {
2722                count = le16_to_cpu(cifs_acl->access_entry_count);
2723                size = sizeof(struct cifs_posix_acl);
2724                size += sizeof(struct cifs_posix_ace) * count;
2725/* skip past access ACEs to get to default ACEs */
2726                pACE = &cifs_acl->ace_array[count];
2727                count = le16_to_cpu(cifs_acl->default_entry_count);
2728                size += sizeof(struct cifs_posix_ace) * count;
2729                /* check if we would go beyond end of SMB */
2730                if (size_of_data_area < size)
2731                        return -EINVAL;
2732        } else {
2733                /* illegal type */
2734                return -EINVAL;
2735        }
2736
2737        size = posix_acl_xattr_size(count);
2738        if ((buflen == 0) || (local_acl == NULL)) {
2739                /* used to query ACL EA size */
2740        } else if (size > buflen) {
2741                return -ERANGE;
2742        } else /* buffer big enough */ {
2743                local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2744                for (i = 0; i < count ; i++) {
2745                        cifs_convert_ace(&local_acl->a_entries[i], pACE);
2746                        pACE++;
2747                }
2748        }
2749        return size;
2750}
2751
2752static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2753                                     const posix_acl_xattr_entry *local_ace)
2754{
2755        __u16 rc = 0; /* 0 = ACL converted ok */
2756
2757        cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2758        cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2759        /* BB is there a better way to handle the large uid? */
2760        if (local_ace->e_id == cpu_to_le32(-1)) {
2761        /* Probably no need to le convert -1 on any arch but can not hurt */
2762                cifs_ace->cifs_uid = cpu_to_le64(-1);
2763        } else
2764                cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2765        /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2766        return rc;
2767}
2768
2769/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2770static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2771                               const int buflen, const int acl_type)
2772{
2773        __u16 rc = 0;
2774        struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2775        posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2776        int count;
2777        int i;
2778
2779        if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2780                return 0;
2781
2782        count = posix_acl_xattr_count((size_t)buflen);
2783        cFYI(1, ("setting acl with %d entries from buf of length %d and "
2784                "version of %d",
2785                count, buflen, le32_to_cpu(local_acl->a_version)));
2786        if (le32_to_cpu(local_acl->a_version) != 2) {
2787                cFYI(1, ("unknown POSIX ACL version %d",
2788                     le32_to_cpu(local_acl->a_version)));
2789                return 0;
2790        }
2791        cifs_acl->version = cpu_to_le16(1);
2792        if (acl_type == ACL_TYPE_ACCESS)
2793                cifs_acl->access_entry_count = cpu_to_le16(count);
2794        else if (acl_type == ACL_TYPE_DEFAULT)
2795                cifs_acl->default_entry_count = cpu_to_le16(count);
2796        else {
2797                cFYI(1, ("unknown ACL type %d", acl_type));
2798                return 0;
2799        }
2800        for (i = 0; i < count; i++) {
2801                rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2802                                        &local_acl->a_entries[i]);
2803                if (rc != 0) {
2804                        /* ACE not converted */
2805                        break;
2806                }
2807        }
2808        if (rc == 0) {
2809                rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2810                rc += sizeof(struct cifs_posix_acl);
2811                /* BB add check to make sure ACL does not overflow SMB */
2812        }
2813        return rc;
2814}
2815
2816int
2817CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2818                   const unsigned char *searchName,
2819                   char *acl_inf, const int buflen, const int acl_type,
2820                   const struct nls_table *nls_codepage, int remap)
2821{
2822/* SMB_QUERY_POSIX_ACL */
2823        TRANSACTION2_QPI_REQ *pSMB = NULL;
2824        TRANSACTION2_QPI_RSP *pSMBr = NULL;
2825        int rc = 0;
2826        int bytes_returned;
2827        int name_len;
2828        __u16 params, byte_count;
2829
2830        cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2831
2832queryAclRetry:
2833        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2834                (void **) &pSMBr);
2835        if (rc)
2836                return rc;
2837
2838        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2839                name_len =
2840                        cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2841                                         PATH_MAX, nls_codepage, remap);
2842                name_len++;     /* trailing null */
2843                name_len *= 2;
2844                pSMB->FileName[name_len] = 0;
2845                pSMB->FileName[name_len+1] = 0;
2846        } else {        /* BB improve the check for buffer overruns BB */
2847                name_len = strnlen(searchName, PATH_MAX);
2848                name_len++;     /* trailing null */
2849                strncpy(pSMB->FileName, searchName, name_len);
2850        }
2851
2852        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2853        pSMB->TotalDataCount = 0;
2854        pSMB->MaxParameterCount = cpu_to_le16(2);
2855        /* BB find exact max data count below from sess structure BB */
2856        pSMB->MaxDataCount = cpu_to_le16(4000);
2857        pSMB->MaxSetupCount = 0;
2858        pSMB->Reserved = 0;
2859        pSMB->Flags = 0;
2860        pSMB->Timeout = 0;
2861        pSMB->Reserved2 = 0;
2862        pSMB->ParameterOffset = cpu_to_le16(
2863                offsetof(struct smb_com_transaction2_qpi_req,
2864                         InformationLevel) - 4);
2865        pSMB->DataCount = 0;
2866        pSMB->DataOffset = 0;
2867        pSMB->SetupCount = 1;
2868        pSMB->Reserved3 = 0;
2869        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2870        byte_count = params + 1 /* pad */ ;
2871        pSMB->TotalParameterCount = cpu_to_le16(params);
2872        pSMB->ParameterCount = pSMB->TotalParameterCount;
2873        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2874        pSMB->Reserved4 = 0;
2875        pSMB->hdr.smb_buf_length += byte_count;
2876        pSMB->ByteCount = cpu_to_le16(byte_count);
2877
2878        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2879                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2880        cifs_stats_inc(&tcon->num_acl_get);
2881        if (rc) {
2882                cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2883        } else {
2884                /* decode response */
2885
2886                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2887                if (rc || (pSMBr->ByteCount < 2))
2888                /* BB also check enough total bytes returned */
2889                        rc = -EIO;      /* bad smb */
2890                else {
2891                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2892                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2893                        rc = cifs_copy_posix_acl(acl_inf,
2894                                (char *)&pSMBr->hdr.Protocol+data_offset,
2895                                buflen, acl_type, count);
2896                }
2897        }
2898        cifs_buf_release(pSMB);
2899        if (rc == -EAGAIN)
2900                goto queryAclRetry;
2901        return rc;
2902}
2903
2904int
2905CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2906                   const unsigned char *fileName,
2907                   const char *local_acl, const int buflen,
2908                   const int acl_type,
2909                   const struct nls_table *nls_codepage, int remap)
2910{
2911        struct smb_com_transaction2_spi_req *pSMB = NULL;
2912        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2913        char *parm_data;
2914        int name_len;
2915        int rc = 0;
2916        int bytes_returned = 0;
2917        __u16 params, byte_count, data_count, param_offset, offset;
2918
2919        cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2920setAclRetry:
2921        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2922                      (void **) &pSMBr);
2923        if (rc)
2924                return rc;
2925        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2926                name_len =
2927                        cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2928                                      PATH_MAX, nls_codepage, remap);
2929                name_len++;     /* trailing null */
2930                name_len *= 2;
2931        } else {        /* BB improve the check for buffer overruns BB */
2932                name_len = strnlen(fileName, PATH_MAX);
2933                name_len++;     /* trailing null */
2934                strncpy(pSMB->FileName, fileName, name_len);
2935        }
2936        params = 6 + name_len;
2937        pSMB->MaxParameterCount = cpu_to_le16(2);
2938        /* BB find max SMB size from sess */
2939        pSMB->MaxDataCount = cpu_to_le16(1000);
2940        pSMB->MaxSetupCount = 0;
2941        pSMB->Reserved = 0;
2942        pSMB->Flags = 0;
2943        pSMB->Timeout = 0;
2944        pSMB->Reserved2 = 0;
2945        param_offset = offsetof(struct smb_com_transaction2_spi_req,
2946                                InformationLevel) - 4;
2947        offset = param_offset + params;
2948        parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2949        pSMB->ParameterOffset = cpu_to_le16(param_offset);
2950
2951        /* convert to on the wire format for POSIX ACL */
2952        data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2953
2954        if (data_count == 0) {
2955                rc = -EOPNOTSUPP;
2956                goto setACLerrorExit;
2957        }
2958        pSMB->DataOffset = cpu_to_le16(offset);
2959        pSMB->SetupCount = 1;
2960        pSMB->Reserved3 = 0;
2961        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2962        pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2963        byte_count = 3 /* pad */  + params + data_count;
2964        pSMB->DataCount = cpu_to_le16(data_count);
2965        pSMB->TotalDataCount = pSMB->DataCount;
2966        pSMB->ParameterCount = cpu_to_le16(params);
2967        pSMB->TotalParameterCount = pSMB->ParameterCount;
2968        pSMB->Reserved4 = 0;
2969        pSMB->hdr.smb_buf_length += byte_count;
2970        pSMB->ByteCount = cpu_to_le16(byte_count);
2971        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2972                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2973        if (rc)
2974                cFYI(1, ("Set POSIX ACL returned %d", rc));
2975
2976setACLerrorExit:
2977        cifs_buf_release(pSMB);
2978        if (rc == -EAGAIN)
2979                goto setAclRetry;
2980        return rc;
2981}
2982
2983/* BB fix tabs in this function FIXME BB */
2984int
2985CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2986               const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2987{
2988        int rc = 0;
2989        struct smb_t2_qfi_req *pSMB = NULL;
2990        struct smb_t2_qfi_rsp *pSMBr = NULL;
2991        int bytes_returned;
2992        __u16 params, byte_count;
2993
2994        cFYI(1, ("In GetExtAttr"));
2995        if (tcon == NULL)
2996                return -ENODEV;
2997
2998GetExtAttrRetry:
2999        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3000                        (void **) &pSMBr);
3001        if (rc)
3002                return rc;
3003
3004        params = 2 /* level */ + 2 /* fid */;
3005        pSMB->t2.TotalDataCount = 0;
3006        pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3007        /* BB find exact max data count below from sess structure BB */
3008        pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3009        pSMB->t2.MaxSetupCount = 0;
3010        pSMB->t2.Reserved = 0;
3011        pSMB->t2.Flags = 0;
3012        pSMB->t2.Timeout = 0;
3013        pSMB->t2.Reserved2 = 0;
3014        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3015                                               Fid) - 4);
3016        pSMB->t2.DataCount = 0;
3017        pSMB->t2.DataOffset = 0;
3018        pSMB->t2.SetupCount = 1;
3019        pSMB->t2.Reserved3 = 0;
3020        pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3021        byte_count = params + 1 /* pad */ ;
3022        pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3023        pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3024        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3025        pSMB->Pad = 0;
3026        pSMB->Fid = netfid;
3027        pSMB->hdr.smb_buf_length += byte_count;
3028        pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3029
3030        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3031                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3032        if (rc) {
3033                cFYI(1, ("error %d in GetExtAttr", rc));
3034        } else {
3035                /* decode response */
3036                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3037                if (rc || (pSMBr->ByteCount < 2))
3038                /* BB also check enough total bytes returned */
3039                        /* If rc should we check for EOPNOSUPP and
3040                           disable the srvino flag? or in caller? */
3041                        rc = -EIO;      /* bad smb */
3042                else {
3043                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3044                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3045                        struct file_chattr_info *pfinfo;
3046                        /* BB Do we need a cast or hash here ? */
3047                        if (count != 16) {
3048                                cFYI(1, ("Illegal size ret in GetExtAttr"));
3049                                rc = -EIO;
3050                                goto GetExtAttrOut;
3051                        }
3052                        pfinfo = (struct file_chattr_info *)
3053                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3054                        *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3055                        *pMask = le64_to_cpu(pfinfo->mask);
3056                }
3057        }
3058GetExtAttrOut:
3059        cifs_buf_release(pSMB);
3060        if (rc == -EAGAIN)
3061                goto GetExtAttrRetry;
3062        return rc;
3063}
3064
3065#endif /* CONFIG_POSIX */
3066
3067#ifdef CONFIG_CIFS_EXPERIMENTAL
3068/* Get Security Descriptor (by handle) from remote server for a file or dir */
3069int
3070CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3071                  struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3072{
3073        int rc = 0;
3074        int buf_type = 0;
3075        QUERY_SEC_DESC_REQ *pSMB;
3076        struct kvec iov[1];
3077
3078        cFYI(1, ("GetCifsACL"));
3079
3080        *pbuflen = 0;
3081        *acl_inf = NULL;
3082
3083        rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3084                        8 /* parm len */, tcon, (void **) &pSMB);
3085        if (rc)
3086                return rc;
3087
3088        pSMB->MaxParameterCount = cpu_to_le32(4);
3089        /* BB TEST with big acls that might need to be e.g. larger than 16K */
3090        pSMB->MaxSetupCount = 0;
3091        pSMB->Fid = fid; /* file handle always le */
3092        pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3093                                     CIFS_ACL_DACL);
3094        pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3095        pSMB->hdr.smb_buf_length += 11;
3096        iov[0].iov_base = (char *)pSMB;
3097        iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3098
3099        rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3100                         CIFS_STD_OP);
3101        cifs_stats_inc(&tcon->num_acl_get);
3102        if (rc) {
3103                cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3104        } else {                /* decode response */
3105                __le32 *parm;
3106                __u32 parm_len;
3107                __u32 acl_len;
3108                struct smb_com_ntransact_rsp *pSMBr;
3109                char *pdata;
3110
3111/* validate_nttransact */
3112                rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3113                                        &pdata, &parm_len, pbuflen);
3114                if (rc)
3115                        goto qsec_out;
3116                pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3117
3118                cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3119
3120                if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3121                        rc = -EIO;      /* bad smb */
3122                        *pbuflen = 0;
3123                        goto qsec_out;
3124                }
3125
3126/* BB check that data area is minimum length and as big as acl_len */
3127
3128                acl_len = le32_to_cpu(*parm);
3129                if (acl_len != *pbuflen) {
3130                        cERROR(1, ("acl length %d does not match %d",
3131                                   acl_len, *pbuflen));
3132                        if (*pbuflen > acl_len)
3133                                *pbuflen = acl_len;
3134                }
3135
3136                /* check if buffer is big enough for the acl
3137                   header followed by the smallest SID */
3138                if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3139                    (*pbuflen >= 64 * 1024)) {
3140                        cERROR(1, ("bad acl length %d", *pbuflen));
3141                        rc = -EINVAL;
3142                        *pbuflen = 0;
3143                } else {
3144                        *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3145                        if (*acl_inf == NULL) {
3146                                *pbuflen = 0;
3147                                rc = -ENOMEM;
3148                        }
3149                        memcpy(*acl_inf, pdata, *pbuflen);
3150                }
3151        }
3152qsec_out:
3153        if (buf_type == CIFS_SMALL_BUFFER)
3154                cifs_small_buf_release(iov[0].iov_base);
3155        else if (buf_type == CIFS_LARGE_BUFFER)
3156                cifs_buf_release(iov[0].iov_base);
3157/*      cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3158        return rc;
3159}
3160
3161int
3162CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3163                        struct cifs_ntsd *pntsd, __u32 acllen)
3164{
3165        __u16 byte_count, param_count, data_count, param_offset, data_offset;
3166        int rc = 0;
3167        int bytes_returned = 0;
3168        SET_SEC_DESC_REQ *pSMB = NULL;
3169        NTRANSACT_RSP *pSMBr = NULL;
3170
3171setCifsAclRetry:
3172        rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3173                        (void **) &pSMBr);
3174        if (rc)
3175                        return (rc);
3176
3177        pSMB->MaxSetupCount = 0;
3178        pSMB->Reserved = 0;
3179
3180        param_count = 8;
3181        param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3182        data_count = acllen;
3183        data_offset = param_offset + param_count;
3184        byte_count = 3 /* pad */  + param_count;
3185
3186        pSMB->DataCount = cpu_to_le32(data_count);
3187        pSMB->TotalDataCount = pSMB->DataCount;
3188        pSMB->MaxParameterCount = cpu_to_le32(4);
3189        pSMB->MaxDataCount = cpu_to_le32(16384);
3190        pSMB->ParameterCount = cpu_to_le32(param_count);
3191        pSMB->ParameterOffset = cpu_to_le32(param_offset);
3192        pSMB->TotalParameterCount = pSMB->ParameterCount;
3193        pSMB->DataOffset = cpu_to_le32(data_offset);
3194        pSMB->SetupCount = 0;
3195        pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3196        pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3197
3198        pSMB->Fid = fid; /* file handle always le */
3199        pSMB->Reserved2 = 0;
3200        pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3201
3202        if (pntsd && acllen) {
3203                memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3204                        (char *) pntsd,
3205                        acllen);
3206                pSMB->hdr.smb_buf_length += (byte_count + data_count);
3207
3208        } else
3209                pSMB->hdr.smb_buf_length += byte_count;
3210
3211        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3212                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3213
3214        cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3215        if (rc)
3216                cFYI(1, ("Set CIFS ACL returned %d", rc));
3217        cifs_buf_release(pSMB);
3218
3219        if (rc == -EAGAIN)
3220                goto setCifsAclRetry;
3221
3222        return (rc);
3223}
3224
3225#endif /* CONFIG_CIFS_EXPERIMENTAL */
3226
3227/* Legacy Query Path Information call for lookup to old servers such
3228   as Win9x/WinME */
3229int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3230                        const unsigned char *searchName,
3231                        FILE_ALL_INFO *pFinfo,
3232                        const struct nls_table *nls_codepage, int remap)
3233{
3234        QUERY_INFORMATION_REQ *pSMB;
3235        QUERY_INFORMATION_RSP *pSMBr;
3236        int rc = 0;
3237        int bytes_returned;
3238        int name_len;
3239
3240        cFYI(1, ("In SMBQPath path %s", searchName));
3241QInfRetry:
3242        rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3243                      (void **) &pSMBr);
3244        if (rc)
3245                return rc;
3246
3247        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3248                name_len =
3249                        cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3250                                        PATH_MAX, nls_codepage, remap);
3251                name_len++;     /* trailing null */
3252                name_len *= 2;
3253        } else {
3254                name_len = strnlen(searchName, PATH_MAX);
3255                name_len++;     /* trailing null */
3256                strncpy(pSMB->FileName, searchName, name_len);
3257        }
3258        pSMB->BufferFormat = 0x04;
3259        name_len++; /* account for buffer type byte */
3260        pSMB->hdr.smb_buf_length += (__u16) name_len;
3261        pSMB->ByteCount = cpu_to_le16(name_len);
3262
3263        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3264                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3265        if (rc) {
3266                cFYI(1, ("Send error in QueryInfo = %d", rc));
3267        } else if (pFinfo) {
3268                struct timespec ts;
3269                __u32 time = le32_to_cpu(pSMBr->last_write_time);
3270
3271                /* decode response */
3272                /* BB FIXME - add time zone adjustment BB */
3273                memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3274                ts.tv_nsec = 0;
3275                ts.tv_sec = time;
3276                /* decode time fields */
3277                pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3278                pFinfo->LastWriteTime = pFinfo->ChangeTime;
3279                pFinfo->LastAccessTime = 0;
3280                pFinfo->AllocationSize =
3281                        cpu_to_le64(le32_to_cpu(pSMBr->size));
3282                pFinfo->EndOfFile = pFinfo->AllocationSize;
3283                pFinfo->Attributes =
3284                        cpu_to_le32(le16_to_cpu(pSMBr->attr));
3285        } else
3286                rc = -EIO; /* bad buffer passed in */
3287
3288        cifs_buf_release(pSMB);
3289
3290        if (rc == -EAGAIN)
3291                goto QInfRetry;
3292
3293        return rc;
3294}
3295
3296
3297
3298
3299int
3300CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3301                 const unsigned char *searchName,
3302                 FILE_ALL_INFO *pFindData,
3303                 int legacy /* old style infolevel */,
3304                 const struct nls_table *nls_codepage, int remap)
3305{
3306/* level 263 SMB_QUERY_FILE_ALL_INFO */
3307        TRANSACTION2_QPI_REQ *pSMB = NULL;
3308        TRANSACTION2_QPI_RSP *pSMBr = NULL;
3309        int rc = 0;
3310        int bytes_returned;
3311        int name_len;
3312        __u16 params, byte_count;
3313
3314/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3315QPathInfoRetry:
3316        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3317                      (void **) &pSMBr);
3318        if (rc)
3319                return rc;
3320
3321        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3322                name_len =
3323                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3324                                     PATH_MAX, nls_codepage, remap);
3325                name_len++;     /* trailing null */
3326                name_len *= 2;
3327        } else {        /* BB improve the check for buffer overruns BB */
3328                name_len = strnlen(searchName, PATH_MAX);
3329                name_len++;     /* trailing null */
3330                strncpy(pSMB->FileName, searchName, name_len);
3331        }
3332
3333        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3334        pSMB->TotalDataCount = 0;
3335        pSMB->MaxParameterCount = cpu_to_le16(2);
3336        /* BB find exact max SMB PDU from sess structure BB */
3337        pSMB->MaxDataCount = cpu_to_le16(4000);
3338        pSMB->MaxSetupCount = 0;
3339        pSMB->Reserved = 0;
3340        pSMB->Flags = 0;
3341        pSMB->Timeout = 0;
3342        pSMB->Reserved2 = 0;
3343        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3344        struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3345        pSMB->DataCount = 0;
3346        pSMB->DataOffset = 0;
3347        pSMB->SetupCount = 1;
3348        pSMB->Reserved3 = 0;
3349        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3350        byte_count = params + 1 /* pad */ ;
3351        pSMB->TotalParameterCount = cpu_to_le16(params);
3352        pSMB->ParameterCount = pSMB->TotalParameterCount;
3353        if (legacy)
3354                pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3355        else
3356                pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3357        pSMB->Reserved4 = 0;
3358        pSMB->hdr.smb_buf_length += byte_count;
3359        pSMB->ByteCount = cpu_to_le16(byte_count);
3360
3361        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3362                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3363        if (rc) {
3364                cFYI(1, ("Send error in QPathInfo = %d", rc));
3365        } else {                /* decode response */
3366                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3367
3368                if (rc) /* BB add auto retry on EOPNOTSUPP? */
3369                        rc = -EIO;
3370                else if (!legacy && (pSMBr->ByteCount < 40))
3371                        rc = -EIO;      /* bad smb */
3372                else if (legacy && (pSMBr->ByteCount < 24))
3373                        rc = -EIO;  /* 24 or 26 expected but we do not read
3374                                        last field */
3375                else if (pFindData) {
3376                        int size;
3377                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3378
3379                        /* On legacy responses we do not read the last field,
3380                        EAsize, fortunately since it varies by subdialect and
3381                        also note it differs on Set vs. Get, ie two bytes or 4
3382                        bytes depending but we don't care here */
3383                        if (legacy)
3384                                size = sizeof(FILE_INFO_STANDARD);
3385                        else
3386                                size = sizeof(FILE_ALL_INFO);
3387                        memcpy((char *) pFindData,
3388                               (char *) &pSMBr->hdr.Protocol +
3389                               data_offset, size);
3390                } else
3391                    rc = -ENOMEM;
3392        }
3393        cifs_buf_release(pSMB);
3394        if (rc == -EAGAIN)
3395                goto QPathInfoRetry;
3396
3397        return rc;
3398}
3399
3400int
3401CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3402                     const unsigned char *searchName,
3403                     FILE_UNIX_BASIC_INFO *pFindData,
3404                     const struct nls_table *nls_codepage, int remap)
3405{
3406/* SMB_QUERY_FILE_UNIX_BASIC */
3407        TRANSACTION2_QPI_REQ *pSMB = NULL;
3408        TRANSACTION2_QPI_RSP *pSMBr = NULL;
3409        int rc = 0;
3410        int bytes_returned = 0;
3411        int name_len;
3412        __u16 params, byte_count;
3413
3414        cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3415UnixQPathInfoRetry:
3416        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3417                      (void **) &pSMBr);
3418        if (rc)
3419                return rc;
3420
3421        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3422                name_len =
3423                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3424                                  PATH_MAX, nls_codepage, remap);
3425                name_len++;     /* trailing null */
3426                name_len *= 2;
3427        } else {        /* BB improve the check for buffer overruns BB */
3428                name_len = strnlen(searchName, PATH_MAX);
3429                name_len++;     /* trailing null */
3430                strncpy(pSMB->FileName, searchName, name_len);
3431        }
3432
3433        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3434        pSMB->TotalDataCount = 0;
3435        pSMB->MaxParameterCount = cpu_to_le16(2);
3436        /* BB find exact max SMB PDU from sess structure BB */
3437        pSMB->MaxDataCount = cpu_to_le16(4000);
3438        pSMB->MaxSetupCount = 0;
3439        pSMB->Reserved = 0;
3440        pSMB->Flags = 0;
3441        pSMB->Timeout = 0;
3442        pSMB->Reserved2 = 0;
3443        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3444        struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3445        pSMB->DataCount = 0;
3446        pSMB->DataOffset = 0;
3447        pSMB->SetupCount = 1;
3448        pSMB->Reserved3 = 0;
3449        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3450        byte_count = params + 1 /* pad */ ;
3451        pSMB->TotalParameterCount = cpu_to_le16(params);
3452        pSMB->ParameterCount = pSMB->TotalParameterCount;
3453        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3454        pSMB->Reserved4 = 0;
3455        pSMB->hdr.smb_buf_length += byte_count;
3456        pSMB->ByteCount = cpu_to_le16(byte_count);
3457
3458        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3459                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3460        if (rc) {
3461                cFYI(1, ("Send error in QPathInfo = %d", rc));
3462        } else {                /* decode response */
3463                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3464
3465                if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3466                        cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3467                                   "Unix Extensions can be disabled on mount "
3468                                   "by specifying the nosfu mount option."));
3469                        rc = -EIO;      /* bad smb */
3470                } else {
3471                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3472                        memcpy((char *) pFindData,
3473                               (char *) &pSMBr->hdr.Protocol +
3474                               data_offset,
3475                               sizeof(FILE_UNIX_BASIC_INFO));
3476                }
3477        }
3478        cifs_buf_release(pSMB);
3479        if (rc == -EAGAIN)
3480                goto UnixQPathInfoRetry;
3481
3482        return rc;
3483}
3484
3485/* xid, tcon, searchName and codepage are input parms, rest are returned */
3486int
3487CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3488              const char *searchName,
3489              const struct nls_table *nls_codepage,
3490              __u16 *pnetfid,
3491              struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3492{
3493/* level 257 SMB_ */
3494        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3495        TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3496        T2_FFIRST_RSP_PARMS *parms;
3497        int rc = 0;
3498        int bytes_returned = 0;
3499        int name_len;
3500        __u16 params, byte_count;
3501
3502        cFYI(1, ("In FindFirst for %s", searchName));
3503
3504findFirstRetry:
3505        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3506                      (void **) &pSMBr);
3507        if (rc)
3508                return rc;
3509
3510        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3511                name_len =
3512                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3513                                 PATH_MAX, nls_codepage, remap);
3514                /* We can not add the asterik earlier in case
3515                it got remapped to 0xF03A as if it were part of the
3516                directory name instead of a wildcard */
3517                name_len *= 2;
3518                pSMB->FileName[name_len] = dirsep;
3519                pSMB->FileName[name_len+1] = 0;
3520                pSMB->FileName[name_len+2] = '*';
3521                pSMB->FileName[name_len+3] = 0;
3522                name_len += 4; /* now the trailing null */
3523                pSMB->FileName[name_len] = 0; /* null terminate just in case */
3524                pSMB->FileName[name_len+1] = 0;
3525                name_len += 2;
3526        } else {        /* BB add check for overrun of SMB buf BB */
3527                name_len = strnlen(searchName, PATH_MAX);
3528/* BB fix here and in unicode clause above ie
3529                if (name_len > buffersize-header)
3530                        free buffer exit; BB */
3531                strncpy(pSMB->FileName, searchName, name_len);
3532                pSMB->FileName[name_len] = dirsep;
3533                pSMB->FileName[name_len+1] = '*';
3534                pSMB->FileName[name_len+2] = 0;
3535                name_len += 3;
3536        }
3537
3538        params = 12 + name_len /* includes null */ ;
3539        pSMB->TotalDataCount = 0;       /* no EAs */
3540        pSMB->MaxParameterCount = cpu_to_le16(10);
3541        pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3542                                          MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3543        pSMB->MaxSetupCount = 0;
3544        pSMB->Reserved = 0;
3545        pSMB->Flags = 0;
3546        pSMB->Timeout = 0;
3547        pSMB->Reserved2 = 0;
3548        byte_count = params + 1 /* pad */ ;
3549        pSMB->TotalParameterCount = cpu_to_le16(params);
3550        pSMB->ParameterCount = pSMB->TotalParameterCount;
3551        pSMB->ParameterOffset = cpu_to_le16(
3552              offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3553                - 4);
3554        pSMB->DataCount = 0;
3555        pSMB->DataOffset = 0;
3556        pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
3557        pSMB->Reserved3 = 0;
3558        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3559        pSMB->SearchAttributes =
3560            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3561                        ATTR_DIRECTORY);
3562        pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3563        pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3564                CIFS_SEARCH_RETURN_RESUME);
3565        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3566
3567        /* BB what should we set StorageType to? Does it matter? BB */
3568        pSMB->SearchStorageType = 0;
3569        pSMB->hdr.smb_buf_length += byte_count;
3570        pSMB->ByteCount = cpu_to_le16(byte_count);
3571
3572        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3573                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3574        cifs_stats_inc(&tcon->num_ffirst);
3575
3576        if (rc) {/* BB add logic to retry regular search if Unix search
3577                        rejected unexpectedly by server */
3578                /* BB Add code to handle unsupported level rc */
3579                cFYI(1, ("Error in FindFirst = %d", rc));
3580
3581                cifs_buf_release(pSMB);
3582
3583                /* BB eventually could optimize out free and realloc of buf */
3584                /*    for this case */
3585                if (rc == -EAGAIN)
3586                        goto findFirstRetry;
3587        } else { /* decode response */
3588                /* BB remember to free buffer if error BB */
3589                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3590                if (rc == 0) {
3591                        unsigned int lnoff;
3592
3593                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3594                                psrch_inf->unicode = true;
3595                        else
3596                                psrch_inf->unicode = false;
3597
3598                        psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3599                        psrch_inf->smallBuf = 0;
3600                        psrch_inf->srch_entries_start =
3601                                (char *) &pSMBr->hdr.Protocol +
3602                                        le16_to_cpu(pSMBr->t2.DataOffset);
3603                        parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3604                               le16_to_cpu(pSMBr->t2.ParameterOffset));
3605
3606                        if (parms->EndofSearch)
3607                                psrch_inf->endOfSearch = true;
3608                        else
3609                                psrch_inf->endOfSearch = false;
3610
3611                        psrch_inf->entries_in_buffer =
3612                                        le16_to_cpu(parms->SearchCount);
3613                        psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3614                                psrch_inf->entries_in_buffer;
3615                        lnoff = le16_to_cpu(parms->LastNameOffset);
3616                        if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3617                              lnoff) {
3618                                cERROR(1, ("ignoring corrupt resume name"));
3619                                psrch_inf->last_entry = NULL;
3620                                return rc;
3621                        }
3622
3623                        psrch_inf->last_entry = psrch_inf->srch_entries_start +
3624                                                        lnoff;
3625
3626                        *pnetfid = parms->SearchHandle;
3627                } else {
3628                        cifs_buf_release(pSMB);
3629                }
3630        }
3631
3632        return rc;
3633}
3634
3635int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3636                 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3637{
3638        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3639        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3640        T2_FNEXT_RSP_PARMS *parms;
3641        char *response_data;
3642        int rc = 0;
3643        int bytes_returned, name_len;
3644        __u16 params, byte_count;
3645
3646        cFYI(1, ("In FindNext"));
3647
3648        if (psrch_inf->endOfSearch)
3649                return -ENOENT;
3650
3651        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3652                (void **) &pSMBr);
3653        if (rc)
3654                return rc;
3655
3656        params = 14; /* includes 2 bytes of null string, converted to LE below*/
3657        byte_count = 0;
3658        pSMB->TotalDataCount = 0;       /* no EAs */
3659        pSMB->MaxParameterCount = cpu_to_le16(8);
3660        pSMB->MaxDataCount =
3661                cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3662                                0xFFFFFF00);
3663        pSMB->MaxSetupCount = 0;
3664        pSMB->Reserved = 0;
3665        pSMB->Flags = 0;
3666        pSMB->Timeout = 0;
3667        pSMB->Reserved2 = 0;
3668        pSMB->ParameterOffset =  cpu_to_le16(
3669              offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3670        pSMB->DataCount = 0;
3671        pSMB->DataOffset = 0;
3672        pSMB->SetupCount = 1;
3673        pSMB->Reserved3 = 0;
3674        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3675        pSMB->SearchHandle = searchHandle;      /* always kept as le */
3676        pSMB->SearchCount =
3677                cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3678        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3679        pSMB->ResumeKey = psrch_inf->resume_key;
3680        pSMB->SearchFlags =
3681              cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3682
3683        name_len = psrch_inf->resume_name_len;
3684        params += name_len;
3685        if (name_len < PATH_MAX) {
3686                memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3687                byte_count += name_len;
3688                /* 14 byte parm len above enough for 2 byte null terminator */
3689                pSMB->ResumeFileName[name_len] = 0;
3690                pSMB->ResumeFileName[name_len+1] = 0;
3691        } else {
3692                rc = -EINVAL;
3693                goto FNext2_err_exit;
3694        }
3695        byte_count = params + 1 /* pad */ ;
3696        pSMB->TotalParameterCount = cpu_to_le16(params);
3697        pSMB->ParameterCount = pSMB->TotalParameterCount;
3698        pSMB->hdr.smb_buf_length += byte_count;
3699        pSMB->ByteCount = cpu_to_le16(byte_count);
3700
3701        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3702                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3703        cifs_stats_inc(&tcon->num_fnext);
3704        if (rc) {
3705                if (rc == -EBADF) {
3706                        psrch_inf->endOfSearch = true;
3707                        cifs_buf_release(pSMB);
3708                        rc = 0; /* search probably was closed at end of search*/
3709                } else
3710                        cFYI(1, ("FindNext returned = %d", rc));
3711        } else {                /* decode response */
3712                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3713
3714                if (rc == 0) {
3715                        unsigned int lnoff;
3716
3717                        /* BB fixme add lock for file (srch_info) struct here */
3718                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3719                                psrch_inf->unicode = true;
3720                        else
3721                                psrch_inf->unicode = false;
3722                        response_data = (char *) &pSMBr->hdr.Protocol +
3723                               le16_to_cpu(pSMBr->t2.ParameterOffset);
3724                        parms = (T2_FNEXT_RSP_PARMS *)response_data;
3725                        response_data = (char *)&pSMBr->hdr.Protocol +
3726                                le16_to_cpu(pSMBr->t2.DataOffset);
3727                        if (psrch_inf->smallBuf)
3728                                cifs_small_buf_release(
3729                                        psrch_inf->ntwrk_buf_start);
3730                        else
3731                                cifs_buf_release(psrch_inf->ntwrk_buf_start);
3732                        psrch_inf->srch_entries_start = response_data;
3733                        psrch_inf->ntwrk_buf_start = (char *)pSMB;
3734                        psrch_inf->smallBuf = 0;
3735                        if (parms->EndofSearch)
3736                                psrch_inf->endOfSearch = true;
3737                        else
3738                                psrch_inf->endOfSearch = false;
3739                        psrch_inf->entries_in_buffer =
3740                                                le16_to_cpu(parms->SearchCount);
3741                        psrch_inf->index_of_last_entry +=
3742                                psrch_inf->entries_in_buffer;
3743                        lnoff = le16_to_cpu(parms->LastNameOffset);
3744                        if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3745                              lnoff) {
3746                                cERROR(1, ("ignoring corrupt resume name"));
3747                                psrch_inf->last_entry = NULL;
3748                                return rc;
3749                        } else
3750                                psrch_inf->last_entry =
3751                                        psrch_inf->srch_entries_start + lnoff;
3752
3753/*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3754            psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3755
3756                        /* BB fixme add unlock here */
3757                }
3758
3759        }
3760
3761        /* BB On error, should we leave previous search buf (and count and
3762        last entry fields) intact or free the previous one? */
3763
3764        /* Note: On -EAGAIN error only caller can retry on handle based calls
3765        since file handle passed in no longer valid */
3766FNext2_err_exit:
3767        if (rc != 0)
3768                cifs_buf_release(pSMB);
3769        return rc;
3770}
3771
3772int
3773CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3774              const __u16 searchHandle)
3775{
3776        int rc = 0;
3777        FINDCLOSE_REQ *pSMB = NULL;
3778
3779        cFYI(1, ("In CIFSSMBFindClose"));
3780        rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3781
3782        /* no sense returning error if session restarted
3783                as file handle has been closed */
3784        if (rc == -EAGAIN)
3785                return 0;
3786        if (rc)
3787                return rc;
3788
3789        pSMB->FileID = searchHandle;
3790        pSMB->ByteCount = 0;
3791        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3792        if (rc)
3793                cERROR(1, ("Send error in FindClose = %d", rc));
3794
3795        cifs_stats_inc(&tcon->num_fclose);
3796
3797        /* Since session is dead, search handle closed on server already */
3798        if (rc == -EAGAIN)
3799                rc = 0;
3800
3801        return rc;
3802}
3803
3804int
3805CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3806                      const unsigned char *searchName,
3807                      __u64 *inode_number,
3808                      const struct nls_table *nls_codepage, int remap)
3809{
3810        int rc = 0;
3811        TRANSACTION2_QPI_REQ *pSMB = NULL;
3812        TRANSACTION2_QPI_RSP *pSMBr = NULL;
3813        int name_len, bytes_returned;
3814        __u16 params, byte_count;
3815
3816        cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3817        if (tcon == NULL)
3818                return -ENODEV;
3819
3820GetInodeNumberRetry:
3821        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3822                      (void **) &pSMBr);
3823        if (rc)
3824                return rc;
3825
3826        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3827                name_len =
3828                        cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3829                                         PATH_MAX, nls_codepage, remap);
3830                name_len++;     /* trailing null */
3831                name_len *= 2;
3832        } else {        /* BB improve the check for buffer overruns BB */
3833                name_len = strnlen(searchName, PATH_MAX);
3834                name_len++;     /* trailing null */
3835                strncpy(pSMB->FileName, searchName, name_len);
3836        }
3837
3838        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3839        pSMB->TotalDataCount = 0;
3840        pSMB->MaxParameterCount = cpu_to_le16(2);
3841        /* BB find exact max data count below from sess structure BB */
3842        pSMB->MaxDataCount = cpu_to_le16(4000);
3843        pSMB->MaxSetupCount = 0;
3844        pSMB->Reserved = 0;
3845        pSMB->Flags = 0;
3846        pSMB->Timeout = 0;
3847        pSMB->Reserved2 = 0;
3848        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3849                struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3850        pSMB->DataCount = 0;
3851        pSMB->DataOffset = 0;
3852        pSMB->SetupCount = 1;
3853        pSMB->Reserved3 = 0;
3854        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3855        byte_count = params + 1 /* pad */ ;
3856        pSMB->TotalParameterCount = cpu_to_le16(params);
3857        pSMB->ParameterCount = pSMB->TotalParameterCount;
3858        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3859        pSMB->Reserved4 = 0;
3860        pSMB->hdr.smb_buf_length += byte_count;
3861        pSMB->ByteCount = cpu_to_le16(byte_count);
3862
3863        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3864                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3865        if (rc) {
3866                cFYI(1, ("error %d in QueryInternalInfo", rc));
3867        } else {
3868                /* decode response */
3869                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3870                if (rc || (pSMBr->ByteCount < 2))
3871                /* BB also check enough total bytes returned */
3872                        /* If rc should we check for EOPNOSUPP and
3873                        disable the srvino flag? or in caller? */
3874                        rc = -EIO;      /* bad smb */
3875                else {
3876                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3877                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3878                        struct file_internal_info *pfinfo;
3879                        /* BB Do we need a cast or hash here ? */
3880                        if (count < 8) {
3881                                cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3882                                rc = -EIO;
3883                                goto GetInodeNumOut;
3884                        }
3885                        pfinfo = (struct file_internal_info *)
3886                                (data_offset + (char *) &pSMBr->hdr.Protocol);
3887                        *inode_number = le64_to_cpu(pfinfo->UniqueId);
3888                }
3889        }
3890GetInodeNumOut:
3891        cifs_buf_release(pSMB);
3892        if (rc == -EAGAIN)
3893                goto GetInodeNumberRetry;
3894        return rc;
3895}
3896
3897/* parses DFS refferal V3 structure
3898 * caller is responsible for freeing target_nodes
3899 * returns:
3900 *      on success - 0
3901 *      on failure - errno
3902 */
3903static int
3904parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3905                unsigned int *num_of_nodes,
3906                struct dfs_info3_param **target_nodes,
3907                const struct nls_table *nls_codepage, int remap,
3908                const char *searchName)
3909{
3910        int i, rc = 0;
3911        char *data_end;
3912        bool is_unicode;
3913        struct dfs_referral_level_3 *ref;
3914
3915        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3916                is_unicode = true;
3917        else
3918                is_unicode = false;
3919        *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3920
3921        if (*num_of_nodes < 1) {
3922                cERROR(1, ("num_referrals: must be at least > 0,"
3923                        "but we get num_referrals = %d\n", *num_of_nodes));
3924                rc = -EINVAL;
3925                goto parse_DFS_referrals_exit;
3926        }
3927
3928        ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3929        if (ref->VersionNumber != cpu_to_le16(3)) {
3930                cERROR(1, ("Referrals of V%d version are not supported,"
3931                        "should be V3", le16_to_cpu(ref->VersionNumber)));
3932                rc = -EINVAL;
3933                goto parse_DFS_referrals_exit;
3934        }
3935
3936        /* get the upper boundary of the resp buffer */
3937        data_end = (char *)(&(pSMBr->PathConsumed)) +
3938                                le16_to_cpu(pSMBr->t2.DataCount);
3939
3940        cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3941                        *num_of_nodes,
3942                        le32_to_cpu(pSMBr->DFSFlags)));
3943
3944        *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3945                        *num_of_nodes, GFP_KERNEL);
3946        if (*target_nodes == NULL) {
3947                cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3948                rc = -ENOMEM;
3949                goto parse_DFS_referrals_exit;
3950        }
3951
3952        /* collect neccessary data from referrals */
3953        for (i = 0; i < *num_of_nodes; i++) {
3954                char *temp;
3955                int max_len;
3956                struct dfs_info3_param *node = (*target_nodes)+i;
3957
3958                node->flags = le32_to_cpu(pSMBr->DFSFlags);
3959                if (is_unicode) {
3960                        __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3961                                                GFP_KERNEL);
3962                        cifsConvertToUCS((__le16 *) tmp, searchName,
3963                                        PATH_MAX, nls_codepage, remap);
3964                        node->path_consumed = cifs_ucs2_bytes(tmp,
3965                                        le16_to_cpu(pSMBr->PathConsumed),
3966                                        nls_codepage);
3967                        kfree(tmp);
3968                } else
3969                        node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3970
3971                node->server_type = le16_to_cpu(ref->ServerType);
3972                node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3973
3974                /* copy DfsPath */
3975                temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3976                max_len = data_end - temp;
3977                node->path_name = cifs_strndup_from_ucs(temp, max_len,
3978                                                      is_unicode, nls_codepage);
3979                if (!node->path_name) {
3980                        rc = -ENOMEM;
3981                        goto parse_DFS_referrals_exit;
3982                }
3983
3984                /* copy link target UNC */
3985                temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3986                max_len = data_end - temp;
3987                node->node_name = cifs_strndup_from_ucs(temp, max_len,
3988                                                      is_unicode, nls_codepage);
3989                if (!node->node_name)
3990                        rc = -ENOMEM;
3991        }
3992
3993parse_DFS_referrals_exit:
3994        if (rc) {
3995                free_dfs_info_array(*target_nodes, *num_of_nodes);
3996                *target_nodes = NULL;
3997                *num_of_nodes = 0;
3998        }
3999        return rc;
4000}
4001
4002int
4003CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4004                const unsigned char *searchName,
4005                struct dfs_info3_param **target_nodes,
4006                unsigned int *num_of_nodes,
4007                const struct nls_table *nls_codepage, int remap)
4008{
4009/* TRANS2_GET_DFS_REFERRAL */
4010        TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4011        TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4012        int rc = 0;
4013        int bytes_returned;
4014        int name_len;
4015        __u16 params, byte_count;
4016        *num_of_nodes = 0;
4017        *target_nodes = NULL;
4018
4019        cFYI(1, ("In GetDFSRefer the path %s", searchName));
4020        if (ses == NULL)
4021                return -ENODEV;
4022getDFSRetry:
4023        rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4024                      (void **) &pSMBr);
4025        if (rc)
4026                return rc;
4027
4028        /* server pointer checked in called function,
4029        but should never be null here anyway */
4030        pSMB->hdr.Mid = GetNextMid(ses->server);
4031        pSMB->hdr.Tid = ses->ipc_tid;
4032        pSMB->hdr.Uid = ses->Suid;
4033        if (ses->capabilities & CAP_STATUS32)
4034                pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4035        if (ses->capabilities & CAP_DFS)
4036                pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4037
4038        if (ses->capabilities & CAP_UNICODE) {
4039                pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4040                name_len =
4041                    cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4042                                     searchName, PATH_MAX, nls_codepage, remap);
4043                name_len++;     /* trailing null */
4044                name_len *= 2;
4045        } else {        /* BB improve the check for buffer overruns BB */
4046                name_len = strnlen(searchName, PATH_MAX);
4047                name_len++;     /* trailing null */
4048                strncpy(pSMB->RequestFileName, searchName, name_len);
4049        }
4050
4051        if (ses->server) {
4052                if (ses->server->secMode &
4053                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4054                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4055        }
4056
4057        pSMB->hdr.Uid = ses->Suid;
4058
4059        params = 2 /* level */  + name_len /*includes null */ ;
4060        pSMB->TotalDataCount = 0;
4061        pSMB->DataCount = 0;
4062        pSMB->DataOffset = 0;
4063        pSMB->MaxParameterCount = 0;
4064        /* BB find exact max SMB PDU from sess structure BB */
4065        pSMB->MaxDataCount = cpu_to_le16(4000);
4066        pSMB->MaxSetupCount = 0;
4067        pSMB->Reserved = 0;
4068        pSMB->Flags = 0;
4069        pSMB->Timeout = 0;
4070        pSMB->Reserved2 = 0;
4071        pSMB->ParameterOffset = cpu_to_le16(offsetof(
4072          struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4073        pSMB->SetupCount = 1;
4074        pSMB->Reserved3 = 0;
4075        pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4076        byte_count = params + 3 /* pad */ ;
4077        pSMB->ParameterCount = cpu_to_le16(params);
4078        pSMB->TotalParameterCount = pSMB->ParameterCount;
4079        pSMB->MaxReferralLevel = cpu_to_le16(3);
4080        pSMB->hdr.smb_buf_length += byte_count;
4081        pSMB->ByteCount = cpu_to_le16(byte_count);
4082
4083        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4084                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4085        if (rc) {
4086                cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4087                goto GetDFSRefExit;
4088        }
4089        rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4090
4091        /* BB Also check if enough total bytes returned? */
4092        if (rc || (pSMBr->ByteCount < 17)) {
4093                rc = -EIO;      /* bad smb */
4094                goto GetDFSRefExit;
4095        }
4096
4097        cFYI(1, ("Decoding GetDFSRefer response BCC: %d  Offset %d",
4098                                pSMBr->ByteCount,
4099                                le16_to_cpu(pSMBr->t2.DataOffset)));
4100
4101        /* parse returned result into more usable form */
4102        rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4103                                 target_nodes, nls_codepage, remap,
4104                                 searchName);
4105
4106GetDFSRefExit:
4107        cifs_buf_release(pSMB);
4108
4109        if (rc == -EAGAIN)
4110                goto getDFSRetry;
4111
4112        return rc;
4113}
4114
4115/* Query File System Info such as free space to old servers such as Win 9x */
4116int
4117SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4118{
4119/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4120        TRANSACTION2_QFSI_REQ *pSMB = NULL;
4121        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4122        FILE_SYSTEM_ALLOC_INFO *response_data;
4123        int rc = 0;
4124        int bytes_returned = 0;
4125        __u16 params, byte_count;
4126
4127        cFYI(1, ("OldQFSInfo"));
4128oldQFSInfoRetry:
4129        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4130                (void **) &pSMBr);
4131        if (rc)
4132                return rc;
4133
4134        params = 2;     /* level */
4135        pSMB->TotalDataCount = 0;
4136        pSMB->MaxParameterCount = cpu_to_le16(2);
4137        pSMB->MaxDataCount = cpu_to_le16(1000);
4138        pSMB->MaxSetupCount = 0;
4139        pSMB->Reserved = 0;
4140        pSMB->Flags = 0;
4141        pSMB->Timeout = 0;
4142        pSMB->Reserved2 = 0;
4143        byte_count = params + 1 /* pad */ ;
4144        pSMB->TotalParameterCount = cpu_to_le16(params);
4145        pSMB->ParameterCount = pSMB->TotalParameterCount;
4146        pSMB->ParameterOffset = cpu_to_le16(offsetof(
4147        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4148        pSMB->DataCount = 0;
4149        pSMB->DataOffset = 0;
4150        pSMB->SetupCount = 1;
4151        pSMB->Reserved3 = 0;
4152        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4153        pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4154        pSMB->hdr.smb_buf_length += byte_count;
4155        pSMB->ByteCount = cpu_to_le16(byte_count);
4156
4157        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4158                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4159        if (rc) {
4160                cFYI(1, ("Send error in QFSInfo = %d", rc));
4161        } else {                /* decode response */
4162                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4163
4164                if (rc || (pSMBr->ByteCount < 18))
4165                        rc = -EIO;      /* bad smb */
4166                else {
4167                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4168                        cFYI(1, ("qfsinf resp BCC: %d  Offset %d",
4169                                 pSMBr->ByteCount, data_offset));
4170
4171                        response_data = (FILE_SYSTEM_ALLOC_INFO *)
4172                                (((char *) &pSMBr->hdr.Protocol) + data_offset);
4173                        FSData->f_bsize =
4174                                le16_to_cpu(response_data->BytesPerSector) *
4175                                le32_to_cpu(response_data->
4176                                        SectorsPerAllocationUnit);
4177                        FSData->f_blocks =
4178                               le32_to_cpu(response_data->TotalAllocationUnits);
4179                        FSData->f_bfree = FSData->f_bavail =
4180                                le32_to_cpu(response_data->FreeAllocationUnits);
4181                        cFYI(1,
4182                             ("Blocks: %lld  Free: %lld Block size %ld",
4183                              (unsigned long long)FSData->f_blocks,
4184                              (unsigned long long)FSData->f_bfree,
4185                              FSData->f_bsize));
4186                }
4187        }
4188        cifs_buf_release(pSMB);
4189
4190        if (rc == -EAGAIN)
4191                goto oldQFSInfoRetry;
4192
4193        return rc;
4194}
4195
4196int
4197CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4198{
4199/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4200        TRANSACTION2_QFSI_REQ *pSMB = NULL;
4201        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4202        FILE_SYSTEM_INFO *response_data;
4203        int rc = 0;
4204        int bytes_returned = 0;
4205        __u16 params, byte_count;
4206
4207        cFYI(1, ("In QFSInfo"));
4208QFSInfoRetry:
4209        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4210                      (void **) &pSMBr);
4211        if (rc)
4212                return rc;
4213
4214        params = 2;     /* level */
4215        pSMB->TotalDataCount = 0;
4216        pSMB->MaxParameterCount = cpu_to_le16(2);
4217        pSMB->MaxDataCount = cpu_to_le16(1000);
4218        pSMB->MaxSetupCount = 0;
4219        pSMB->Reserved = 0;
4220        pSMB->Flags = 0;
4221        pSMB->Timeout = 0;
4222        pSMB->Reserved2 = 0;
4223        byte_count = params + 1 /* pad */ ;
4224        pSMB->TotalParameterCount = cpu_to_le16(params);
4225        pSMB->ParameterCount = pSMB->TotalParameterCount;
4226        pSMB->ParameterOffset = cpu_to_le16(offsetof(
4227                struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4228        pSMB->DataCount = 0;
4229        pSMB->DataOffset = 0;
4230        pSMB->SetupCount = 1;
4231        pSMB->Reserved3 = 0;
4232        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4233        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4234        pSMB->hdr.smb_buf_length += byte_count;
4235        pSMB->ByteCount = cpu_to_le16(byte_count);
4236
4237        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4238                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4239        if (rc) {
4240                cFYI(1, ("Send error in QFSInfo = %d", rc));
4241        } else {                /* decode response */
4242                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4243
4244                if (rc || (pSMBr->ByteCount < 24))
4245                        rc = -EIO;      /* bad smb */
4246                else {
4247                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4248
4249                        response_data =
4250                            (FILE_SYSTEM_INFO
4251                             *) (((char *) &pSMBr->hdr.Protocol) +
4252                                 data_offset);
4253                        FSData->f_bsize =
4254                            le32_to_cpu(response_data->BytesPerSector) *
4255                            le32_to_cpu(response_data->
4256                                        SectorsPerAllocationUnit);
4257                        FSData->f_blocks =
4258                            le64_to_cpu(response_data->TotalAllocationUnits);
4259                        FSData->f_bfree = FSData->f_bavail =
4260                            le64_to_cpu(response_data->FreeAllocationUnits);
4261                        cFYI(1,
4262                             ("Blocks: %lld  Free: %lld Block size %ld",
4263                              (unsigned long long)FSData->f_blocks,
4264                              (unsigned long long)FSData->f_bfree,
4265                              FSData->f_bsize));
4266                }
4267        }
4268        cifs_buf_release(pSMB);
4269
4270        if (rc == -EAGAIN)
4271                goto QFSInfoRetry;
4272
4273        return rc;
4274}
4275
4276int
4277CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4278{
4279/* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
4280        TRANSACTION2_QFSI_REQ *pSMB = NULL;
4281        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4282        FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4283        int rc = 0;
4284        int bytes_returned = 0;
4285        __u16 params, byte_count;
4286
4287        cFYI(1, ("In QFSAttributeInfo"));
4288QFSAttributeRetry:
4289        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4290                      (void **) &pSMBr);
4291        if (rc)
4292                return rc;
4293
4294        params = 2;     /* level */
4295        pSMB->TotalDataCount = 0;
4296        pSMB->MaxParameterCount = cpu_to_le16(2);
4297        /* BB find exact max SMB PDU from sess structure BB */
4298        pSMB->MaxDataCount = cpu_to_le16(1000);
4299        pSMB->MaxSetupCount = 0;
4300        pSMB->Reserved = 0;
4301        pSMB->Flags = 0;
4302        pSMB->Timeout = 0;
4303        pSMB->Reserved2 = 0;
4304        byte_count = params + 1 /* pad */ ;
4305        pSMB->TotalParameterCount = cpu_to_le16(params);
4306        pSMB->ParameterCount = pSMB->TotalParameterCount;
4307        pSMB->ParameterOffset = cpu_to_le16(offsetof(
4308                struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4309        pSMB->DataCount = 0;
4310        pSMB->DataOffset = 0;
4311        pSMB->SetupCount = 1;
4312        pSMB->Reserved3 = 0;
4313        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4314        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4315        pSMB->hdr.smb_buf_length += byte_count;
4316        pSMB->ByteCount = cpu_to_le16(byte_count);
4317
4318        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4319                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4320        if (rc) {
4321                cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4322        } else {                /* decode response */
4323                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4324
4325                if (rc || (pSMBr->ByteCount < 13)) {
4326                        /* BB also check if enough bytes returned */
4327                        rc = -EIO;      /* bad smb */
4328                } else {
4329                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4330                        response_data =
4331                            (FILE_SYSTEM_ATTRIBUTE_INFO
4332                             *) (((char *) &pSMBr->hdr.Protocol) +
4333                                 data_offset);
4334                        memcpy(&tcon->fsAttrInfo, response_data,
4335                               sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4336                }
4337        }
4338        cifs_buf_release(pSMB);
4339
4340        if (rc == -EAGAIN)
4341                goto QFSAttributeRetry;
4342
4343        return rc;
4344}
4345
4346int
4347CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4348{
4349/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4350        TRANSACTION2_QFSI_REQ *pSMB = NULL;
4351        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4352        FILE_SYSTEM_DEVICE_INFO *response_data;
4353        int rc = 0;
4354        int bytes_returned = 0;
4355        __u16 params, byte_count;
4356
4357        cFYI(1, ("In QFSDeviceInfo"));
4358QFSDeviceRetry:
4359        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360                      (void **) &pSMBr);
4361        if (rc)
4362                return rc;
4363
4364        params = 2;     /* level */
4365        pSMB->TotalDataCount = 0;
4366        pSMB->MaxParameterCount = cpu_to_le16(2);
4367        /* BB find exact max SMB PDU from sess structure BB */
4368        pSMB->MaxDataCount = cpu_to_le16(1000);
4369        pSMB->MaxSetupCount = 0;
4370        pSMB->Reserved = 0;
4371        pSMB->Flags = 0;
4372        pSMB->Timeout = 0;
4373        pSMB->Reserved2 = 0;
4374        byte_count = params + 1 /* pad */ ;
4375        pSMB->TotalParameterCount = cpu_to_le16(params);
4376        pSMB->ParameterCount = pSMB->TotalParameterCount;
4377        pSMB->ParameterOffset = cpu_to_le16(offsetof(
4378                struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4379
4380        pSMB->DataCount = 0;
4381        pSMB->DataOffset = 0;
4382        pSMB->SetupCount = 1;
4383        pSMB->Reserved3 = 0;
4384        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4385        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4386        pSMB->hdr.smb_buf_length += byte_count;
4387        pSMB->ByteCount = cpu_to_le16(byte_count);
4388
4389        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4390                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4391        if (rc) {
4392                cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4393        } else {                /* decode response */
4394                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4395
4396                if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4397                        rc = -EIO;      /* bad smb */
4398                else {
4399                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4400                        response_data =
4401                            (FILE_SYSTEM_DEVICE_INFO *)
4402                                (((char *) &pSMBr->hdr.Protocol) +
4403                                 data_offset);
4404                        memcpy(&tcon->fsDevInfo, response_data,
4405                               sizeof(FILE_SYSTEM_DEVICE_INFO));
4406                }
4407        }
4408        cifs_buf_release(pSMB);
4409
4410        if (rc == -EAGAIN)
4411                goto QFSDeviceRetry;
4412
4413        return rc;
4414}
4415
4416int
4417CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4418{
4419/* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
4420        TRANSACTION2_QFSI_REQ *pSMB = NULL;
4421        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4422        FILE_SYSTEM_UNIX_INFO *response_data;
4423        int rc = 0;
4424        int bytes_returned = 0;
4425        __u16 params, byte_count;
4426
4427        cFYI(1, ("In QFSUnixInfo"));
4428QFSUnixRetry:
4429        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4430                      (void **) &pSMBr);
4431        if (rc)
4432                return rc;
4433
4434        params = 2;     /* level */
4435        pSMB->TotalDataCount = 0;
4436        pSMB->DataCount = 0;
4437        pSMB->DataOffset = 0;
4438        pSMB->MaxParameterCount = cpu_to_le16(2);
4439        /* BB find exact max SMB PDU from sess structure BB */
4440        pSMB->MaxDataCount = cpu_to_le16(100);
4441        pSMB->MaxSetupCount = 0;
4442        pSMB->Reserved = 0;
4443        pSMB->Flags = 0;
4444        pSMB->Timeout = 0;
4445        pSMB->Reserved2 = 0;
4446        byte_count = params + 1 /* pad */ ;
4447        pSMB->ParameterCount = cpu_to_le16(params);
4448        pSMB->TotalParameterCount = pSMB->ParameterCount;
4449        pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4450                        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4451        pSMB->SetupCount = 1;
4452        pSMB->Reserved3 = 0;
4453        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4454        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4455        pSMB->hdr.smb_buf_length += byte_count;
4456        pSMB->ByteCount = cpu_to_le16(byte_count);
4457
4458        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4459                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4460        if (rc) {
4461                cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4462        } else {                /* decode response */
4463                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4464
4465                if (rc || (pSMBr->ByteCount < 13)) {
4466                        rc = -EIO;      /* bad smb */
4467                } else {
4468                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4469                        response_data =
4470                            (FILE_SYSTEM_UNIX_INFO
4471                             *) (((char *) &pSMBr->hdr.Protocol) +
4472                                 data_offset);
4473                        memcpy(&tcon->fsUnixInfo, response_data,
4474                               sizeof(FILE_SYSTEM_UNIX_INFO));
4475                }
4476        }
4477        cifs_buf_release(pSMB);
4478
4479        if (rc == -EAGAIN)
4480                goto QFSUnixRetry;
4481
4482
4483        return rc;
4484}
4485
4486int
4487CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4488{
4489/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
4490        TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4491        TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4492        int rc = 0;
4493        int bytes_returned = 0;
4494        __u16 params, param_offset, offset, byte_count;
4495
4496        cFYI(1, ("In SETFSUnixInfo"));
4497SETFSUnixRetry:
4498        /* BB switch to small buf init to save memory */
4499        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4500                      (void **) &pSMBr);
4501        if (rc)
4502                return rc;
4503
4504        params = 4;     /* 2 bytes zero followed by info level. */
4505        pSMB->MaxSetupCount = 0;
4506        pSMB->Reserved = 0;
4507        pSMB->Flags = 0;
4508        pSMB->Timeout = 0;
4509        pSMB->Reserved2 = 0;
4510        param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4511                                - 4;
4512        offset = param_offset + params;
4513
4514        pSMB->MaxParameterCount = cpu_to_le16(4);
4515        /* BB find exact max SMB PDU from sess structure BB */
4516        pSMB->MaxDataCount = cpu_to_le16(100);
4517        pSMB->SetupCount = 1;
4518        pSMB->Reserved3 = 0;
4519        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4520        byte_count = 1 /* pad */ + params + 12;
4521
4522        pSMB->DataCount = cpu_to_le16(12);
4523        pSMB->ParameterCount = cpu_to_le16(params);
4524        pSMB->TotalDataCount = pSMB->DataCount;
4525        pSMB->TotalParameterCount = pSMB->ParameterCount;
4526        pSMB->ParameterOffset = cpu_to_le16(param_offset);
4527        pSMB->DataOffset = cpu_to_le16(offset);
4528
4529        /* Params. */
4530        pSMB->FileNum = 0;
4531        pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4532
4533        /* Data. */
4534        pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4535        pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4536        pSMB->ClientUnixCap = cpu_to_le64(cap);
4537
4538        pSMB->hdr.smb_buf_length += byte_count;
4539        pSMB->ByteCount = cpu_to_le16(byte_count);
4540
4541        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4542                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4543        if (rc) {
4544                cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4545        } else {                /* decode response */
4546                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4547                if (rc)
4548                        rc = -EIO;      /* bad smb */
4549        }
4550        cifs_buf_release(pSMB);
4551
4552        if (rc == -EAGAIN)
4553                goto SETFSUnixRetry;
4554
4555        return rc;
4556}
4557
4558
4559
4560int
4561CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4562                   struct kstatfs *FSData)
4563{
4564/* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
4565        TRANSACTION2_QFSI_REQ *pSMB = NULL;
4566        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4567        FILE_SYSTEM_POSIX_INFO *response_data;
4568        int rc = 0;
4569        int bytes_returned = 0;
4570        __u16 params, byte_count;
4571
4572        cFYI(1, ("In QFSPosixInfo"));
4573QFSPosixRetry:
4574        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4575                      (void **) &pSMBr);
4576        if (rc)
4577                return rc;
4578
4579        params = 2;     /* level */
4580        pSMB->TotalDataCount = 0;
4581        pSMB->DataCount = 0;
4582        pSMB->DataOffset = 0;
4583        pSMB->MaxParameterCount = cpu_to_le16(2);
4584        /* BB find exact max SMB PDU from sess structure BB */
4585        pSMB->MaxDataCount = cpu_to_le16(100);
4586        pSMB->MaxSetupCount = 0;
4587        pSMB->Reserved = 0;
4588        pSMB->Flags = 0;
4589        pSMB->Timeout = 0;
4590        pSMB->Reserved2 = 0;
4591        byte_count = params + 1 /* pad */ ;
4592        pSMB->ParameterCount = cpu_to_le16(params);
4593        pSMB->TotalParameterCount = pSMB->ParameterCount;
4594        pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4595                        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4596        pSMB->SetupCount = 1;
4597        pSMB->Reserved3 = 0;
4598        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4599        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4600        pSMB->hdr.smb_buf_length += byte_count;
4601        pSMB->ByteCount = cpu_to_le16(byte_count);
4602
4603        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4604                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4605        if (rc) {
4606                cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4607        } else {                /* decode response */
4608                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4609
4610                if (rc || (pSMBr->ByteCount < 13)) {
4611                        rc = -EIO;      /* bad smb */
4612                } else {
4613                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4614                        response_data =
4615                            (FILE_SYSTEM_POSIX_INFO
4616                             *) (((char *) &pSMBr->hdr.Protocol) +
4617                                 data_offset);
4618                        FSData->f_bsize =
4619                                        le32_to_cpu(response_data->BlockSize);
4620                        FSData->f_blocks =
4621                                        le64_to_cpu(response_data->TotalBlocks);
4622                        FSData->f_bfree =
4623                            le64_to_cpu(response_data->BlocksAvail);
4624                        if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4625                                FSData->f_bavail = FSData->f_bfree;
4626                        } else {
4627                                FSData->f_bavail =
4628                                    le64_to_cpu(response_data->UserBlocksAvail);
4629                        }
4630                        if (response_data->TotalFileNodes != cpu_to_le64(-1))
4631                                FSData->f_files =
4632                                     le64_to_cpu(response_data->TotalFileNodes);
4633                        if (response_data->FreeFileNodes != cpu_to_le64(-1))
4634                                FSData->f_ffree =
4635                                      le64_to_cpu(response_data->FreeFileNodes);
4636                }
4637        }
4638        cifs_buf_release(pSMB);
4639
4640        if (rc == -EAGAIN)
4641                goto QFSPosixRetry;
4642
4643        return rc;
4644}
4645
4646
4647/* We can not use write of zero bytes trick to
4648   set file size due to need for large file support.  Also note that
4649   this SetPathInfo is preferred to SetFileInfo based method in next
4650   routine which is only needed to work around a sharing violation bug
4651   in Samba which this routine can run into */
4652
4653int
4654CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4655              __u64 size, bool SetAllocation,
4656              const struct nls_table *nls_codepage, int remap)
4657{
4658        struct smb_com_transaction2_spi_req *pSMB = NULL;
4659        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4660        struct file_end_of_file_info *parm_data;
4661        int name_len;
4662        int rc = 0;
4663        int bytes_returned = 0;
4664        __u16 params, byte_count, data_count, param_offset, offset;
4665
4666        cFYI(1, ("In SetEOF"));
4667SetEOFRetry:
4668        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4669                      (void **) &pSMBr);
4670        if (rc)
4671                return rc;
4672
4673        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4674                name_len =
4675                    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4676                                     PATH_MAX, nls_codepage, remap);
4677                name_len++;     /* trailing null */
4678                name_len *= 2;
4679        } else {        /* BB improve the check for buffer overruns BB */
4680                name_len = strnlen(fileName, PATH_MAX);
4681                name_len++;     /* trailing null */
4682                strncpy(pSMB->FileName, fileName, name_len);
4683        }
4684        params = 6 + name_len;
4685        data_count = sizeof(struct file_end_of_file_info);
4686        pSMB->MaxParameterCount = cpu_to_le16(2);
4687        pSMB->MaxDataCount = cpu_to_le16(4100);
4688        pSMB->MaxSetupCount = 0;
4689        pSMB->Reserved = 0;
4690        pSMB->Flags = 0;
4691        pSMB->Timeout = 0;
4692        pSMB->Reserved2 = 0;
4693        param_offset = offsetof(struct smb_com_transaction2_spi_req,
4694                                InformationLevel) - 4;
4695        offset = param_offset + params;
4696        if (SetAllocation) {
4697                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4698                        pSMB->InformationLevel =
4699                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4700                else
4701                        pSMB->InformationLevel =
4702                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4703        } else /* Set File Size */  {
4704            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4705                    pSMB->InformationLevel =
4706                                cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4707            else
4708                    pSMB->InformationLevel =
4709                                cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4710        }
4711
4712        parm_data =
4713            (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4714                                       offset);
4715        pSMB->ParameterOffset = cpu_to_le16(param_offset);
4716        pSMB->DataOffset = cpu_to_le16(offset);
4717        pSMB->SetupCount = 1;
4718        pSMB->Reserved3 = 0;
4719        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4720        byte_count = 3 /* pad */  + params + data_count;
4721        pSMB->DataCount = cpu_to_le16(data_count);
4722        pSMB->TotalDataCount = pSMB->DataCount;
4723        pSMB->ParameterCount = cpu_to_le16(params);
4724        pSMB->TotalParameterCount = pSMB->ParameterCount;
4725        pSMB->Reserved4 = 0;
4726        pSMB->hdr.smb_buf_length += byte_count;
4727        parm_data->FileSize = cpu_to_le64(size);
4728        pSMB->ByteCount = cpu_to_le16(byte_count);
4729        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4730                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4731        if (rc)
4732                cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4733
4734        cifs_buf_release(pSMB);
4735
4736        if (rc == -EAGAIN)
4737                goto SetEOFRetry;
4738
4739        return rc;
4740}
4741
4742int
4743CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4744                   __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4745{
4746        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4747        char *data_offset;
4748        struct file_end_of_file_info *parm_data;
4749        int rc = 0;
4750        __u16 params, param_offset, offset, byte_count, count;
4751
4752        cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4753                        (long long)size));
4754        rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4755
4756        if (rc)
4757                return rc;
4758
4759        pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4760        pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4761
4762        params = 6;
4763        pSMB->MaxSetupCount = 0;
4764        pSMB->Reserved = 0;
4765        pSMB->Flags = 0;
4766        pSMB->Timeout = 0;
4767        pSMB->Reserved2 = 0;
4768        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4769        offset = param_offset + params;
4770
4771        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4772
4773        count = sizeof(struct file_end_of_file_info);
4774        pSMB->MaxParameterCount = cpu_to_le16(2);
4775        /* BB find exact max SMB PDU from sess structure BB */
4776        pSMB->MaxDataCount = cpu_to_le16(1000);
4777        pSMB->SetupCount = 1;
4778        pSMB->Reserved3 = 0;
4779        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4780        byte_count = 3 /* pad */  + params + count;
4781        pSMB->DataCount = cpu_to_le16(count);
4782        pSMB->ParameterCount = cpu_to_le16(params);
4783        pSMB->TotalDataCount = pSMB->DataCount;
4784        pSMB->TotalParameterCount = pSMB->ParameterCount;
4785        pSMB->ParameterOffset = cpu_to_le16(param_offset);
4786        parm_data =
4787                (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4788                                + offset);
4789        pSMB->DataOffset = cpu_to_le16(offset);
4790        parm_data->FileSize = cpu_to_le64(size);
4791        pSMB->Fid = fid;
4792        if (SetAllocation) {
4793                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4794                        pSMB->InformationLevel =
4795                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4796                else
4797                        pSMB->InformationLevel =
4798                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4799        } else /* Set File Size */  {
4800            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4801                    pSMB->InformationLevel =
4802                                cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4803            else
4804                    pSMB->InformationLevel =
4805                                cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4806        }
4807        pSMB->Reserved4 = 0;
4808        pSMB->hdr.smb_buf_length += byte_count;
4809        pSMB->ByteCount = cpu_to_le16(byte_count);
4810        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4811        if (rc) {
4812                cFYI(1,
4813                     ("Send error in SetFileInfo (SetFileSize) = %d",
4814                      rc));
4815        }
4816
4817        /* Note: On -EAGAIN error only caller can retry on handle based calls
4818                since file handle passed in no longer valid */
4819
4820        return rc;
4821}
4822
4823/* Some legacy servers such as NT4 require that the file times be set on
4824   an open handle, rather than by pathname - this is awkward due to
4825   potential access conflicts on the open, but it is unavoidable for these
4826   old servers since the only other choice is to go from 100 nanosecond DCE
4827   time and resort to the original setpathinfo level which takes the ancient
4828   DOS time format with 2 second granularity */
4829int
4830CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4831                    const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4832{
4833        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4834        char *data_offset;
4835        int rc = 0;
4836        __u16 params, param_offset, offset, byte_count, count;
4837
4838        cFYI(1, ("Set Times (via SetFileInfo)"));
4839        rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4840
4841        if (rc)
4842                return rc;
4843
4844        pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4845        pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4846
4847        params = 6;
4848        pSMB->MaxSetupCount = 0;
4849        pSMB->Reserved = 0;
4850        pSMB->Flags = 0;
4851        pSMB->Timeout = 0;
4852        pSMB->Reserved2 = 0;
4853        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4854        offset = param_offset + params;
4855
4856        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4857
4858        count = sizeof(FILE_BASIC_INFO);
4859        pSMB->MaxParameterCount = cpu_to_le16(2);
4860        /* BB find max SMB PDU from sess */
4861        pSMB->MaxDataCount = cpu_to_le16(1000);
4862        pSMB->SetupCount = 1;
4863        pSMB->Reserved3 = 0;
4864        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4865        byte_count = 3 /* pad */  + params + count;
4866        pSMB->DataCount = cpu_to_le16(count);
4867        pSMB->ParameterCount = cpu_to_le16(params);
4868        pSMB->TotalDataCount = pSMB->DataCount;
4869        pSMB->TotalParameterCount = pSMB->ParameterCount;
4870        pSMB->ParameterOffset = cpu_to_le16(param_offset);
4871        pSMB->DataOffset = cpu_to_le16(offset);
4872        pSMB->Fid = fid;
4873        if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4874                pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4875        else
4876                pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4877        pSMB->Reserved4 = 0;
4878        pSMB->hdr.smb_buf_length += byte_count;
4879        pSMB->ByteCount = cpu_to_le16(byte_count);
4880        memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4881        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4882        if (rc)
4883                cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4884
4885        /* Note: On -EAGAIN error only caller can retry on handle based calls
4886                since file handle passed in no longer valid */
4887
4888        return rc;
4889}
4890
4891int
4892CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4893                          bool delete_file, __u16 fid, __u32 pid_of_opener)
4894{
4895        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4896        char *data_offset;
4897        int rc = 0;
4898        __u16 params, param_offset, offset, byte_count, count;
4899
4900        cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4901        rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4902
4903        if (rc)
4904                return rc;
4905
4906        pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4907        pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4908
4909        params = 6;
4910        pSMB->MaxSetupCount = 0;
4911        pSMB->Reserved = 0;
4912        pSMB->Flags = 0;
4913        pSMB->Timeout = 0;
4914        pSMB->Reserved2 = 0;
4915        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4916        offset = param_offset + params;
4917
4918        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4919
4920        count = 1;
4921        pSMB->MaxParameterCount = cpu_to_le16(2);
4922        /* BB find max SMB PDU from sess */
4923        pSMB->MaxDataCount = cpu_to_le16(1000);
4924        pSMB->SetupCount = 1;
4925        pSMB->Reserved3 = 0;
4926        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4927        byte_count = 3 /* pad */  + params + count;
4928        pSMB->DataCount = cpu_to_le16(count);
4929        pSMB->ParameterCount = cpu_to_le16(params);
4930        pSMB->TotalDataCount = pSMB->DataCount;
4931        pSMB->TotalParameterCount = pSMB->ParameterCount;
4932        pSMB->ParameterOffset = cpu_to_le16(param_offset);
4933        pSMB->DataOffset = cpu_to_le16(offset);
4934        pSMB->Fid = fid;
4935        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4936        pSMB->Reserved4 = 0;
4937        pSMB->hdr.smb_buf_length += byte_count;
4938        pSMB->ByteCount = cpu_to_le16(byte_count);
4939        *data_offset = delete_file ? 1 : 0;
4940        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4941        if (rc)
4942                cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4943
4944        return rc;
4945}
4946
4947int
4948CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4949                   const char *fileName, const FILE_BASIC_INFO *data,
4950                   const struct nls_table *nls_codepage, int remap)
4951{
4952        TRANSACTION2_SPI_REQ *pSMB = NULL;
4953        TRANSACTION2_SPI_RSP *pSMBr = NULL;
4954        int name_len;
4955        int rc = 0;
4956        int bytes_returned = 0;
4957        char *data_offset;
4958        __u16 params, param_offset, offset, byte_count, count;
4959
4960        cFYI(1, ("In SetTimes"));
4961
4962SetTimesRetry:
4963        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4964                      (void **) &pSMBr);
4965        if (rc)
4966                return rc;
4967
4968        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4969                name_len =
4970                    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4971                                     PATH_MAX, nls_codepage, remap);
4972                name_len++;     /* trailing null */
4973                name_len *= 2;
4974        } else {        /* BB improve the check for buffer overruns BB */
4975                name_len = strnlen(fileName, PATH_MAX);
4976                name_len++;     /* trailing null */
4977                strncpy(pSMB->FileName, fileName, name_len);
4978        }
4979
4980        params = 6 + name_len;
4981        count = sizeof(FILE_BASIC_INFO);
4982        pSMB->MaxParameterCount = cpu_to_le16(2);
4983        /* BB find max SMB PDU from sess structure BB */
4984        pSMB->MaxDataCount = cpu_to_le16(1000);
4985        pSMB->MaxSetupCount = 0;
4986        pSMB->Reserved = 0;
4987        pSMB->Flags = 0;
4988        pSMB->Timeout = 0;
4989        pSMB->Reserved2 = 0;
4990        param_offset = offsetof(struct smb_com_transaction2_spi_req,
4991                                InformationLevel) - 4;
4992        offset = param_offset + params;
4993        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4994        pSMB->ParameterOffset = cpu_to_le16(param_offset);
4995        pSMB->DataOffset = cpu_to_le16(offset);
4996        pSMB->SetupCount = 1;
4997        pSMB->Reserved3 = 0;
4998        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4999        byte_count = 3 /* pad */  + params + count;
5000
5001        pSMB->DataCount = cpu_to_le16(count);
5002        pSMB->ParameterCount = cpu_to_le16(params);
5003        pSMB->TotalDataCount = pSMB->DataCount;
5004        pSMB->TotalParameterCount = pSMB->ParameterCount;
5005        if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5006                pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5007        else
5008                pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5009        pSMB->Reserved4 = 0;
5010        pSMB->hdr.smb_buf_length += byte_count;
5011        memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5012        pSMB->ByteCount = cpu_to_le16(byte_count);
5013        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5014                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5015        if (rc)
5016                cFYI(1, ("SetPathInfo (times) returned %d", rc));
5017
5018        cifs_buf_release(pSMB);
5019
5020        if (rc == -EAGAIN)
5021                goto SetTimesRetry;
5022
5023        return rc;
5024}
5025
5026/* Can not be used to set time stamps yet (due to old DOS time format) */
5027/* Can be used to set attributes */
5028#if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
5029          handling it anyway and NT4 was what we thought it would be needed for
5030          Do not delete it until we prove whether needed for Win9x though */
5031int
5032CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5033                __u16 dos_attrs, const struct nls_table *nls_codepage)
5034{
5035        SETATTR_REQ *pSMB = NULL;
5036        SETATTR_RSP *pSMBr = NULL;
5037        int rc = 0;
5038        int bytes_returned;
5039        int name_len;
5040
5041        cFYI(1, ("In SetAttrLegacy"));
5042
5043SetAttrLgcyRetry:
5044        rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5045                      (void **) &pSMBr);
5046        if (rc)
5047                return rc;
5048
5049        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5050                name_len =
5051                        ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5052                                PATH_MAX, nls_codepage);
5053                name_len++;     /* trailing null */
5054                name_len *= 2;
5055        } else {        /* BB improve the check for buffer overruns BB */
5056                name_len = strnlen(fileName, PATH_MAX);
5057                name_len++;     /* trailing null */
5058                strncpy(pSMB->fileName, fileName, name_len);
5059        }
5060        pSMB->attr = cpu_to_le16(dos_attrs);
5061        pSMB->BufferFormat = 0x04;
5062        pSMB->hdr.smb_buf_length += name_len + 1;
5063        pSMB->ByteCount = cpu_to_le16(name_len + 1);
5064        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5065                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5066        if (rc)
5067                cFYI(1, ("Error in LegacySetAttr = %d", rc));
5068
5069        cifs_buf_release(pSMB);
5070
5071        if (rc == -EAGAIN)
5072                goto SetAttrLgcyRetry;
5073
5074        return rc;
5075}
5076#endif /* temporarily unneeded SetAttr legacy function */
5077
5078int
5079CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5080                   const struct cifs_unix_set_info_args *args,
5081                   const struct nls_table *nls_codepage, int remap)
5082{
5083        TRANSACTION2_SPI_REQ *pSMB = NULL;
5084        TRANSACTION2_SPI_RSP *pSMBr = NULL;
5085        int name_len;
5086        int rc = 0;
5087        int bytes_returned = 0;
5088        FILE_UNIX_BASIC_INFO *data_offset;
5089        __u16 params, param_offset, offset, count, byte_count;
5090        __u64 mode = args->mode;
5091
5092        cFYI(1, ("In SetUID/GID/Mode"));
5093setPermsRetry:
5094        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5095                      (void **) &pSMBr);
5096        if (rc)
5097                return rc;
5098
5099        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5100                name_len =
5101                    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5102                                     PATH_MAX, nls_codepage, remap);
5103                name_len++;     /* trailing null */
5104                name_len *= 2;
5105        } else {        /* BB improve the check for buffer overruns BB */
5106                name_len = strnlen(fileName, PATH_MAX);
5107                name_len++;     /* trailing null */
5108                strncpy(pSMB->FileName, fileName, name_len);
5109        }
5110
5111        params = 6 + name_len;
5112        count = sizeof(FILE_UNIX_BASIC_INFO);
5113        pSMB->MaxParameterCount = cpu_to_le16(2);
5114        /* BB find max SMB PDU from sess structure BB */
5115        pSMB->MaxDataCount = cpu_to_le16(1000);
5116        pSMB->MaxSetupCount = 0;
5117        pSMB->Reserved = 0;
5118        pSMB->Flags = 0;
5119        pSMB->Timeout = 0;
5120        pSMB->Reserved2 = 0;
5121        param_offset = offsetof(struct smb_com_transaction2_spi_req,
5122                                InformationLevel) - 4;
5123        offset = param_offset + params;
5124        data_offset =
5125            (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5126                                      offset);
5127        memset(data_offset, 0, count);
5128        pSMB->DataOffset = cpu_to_le16(offset);
5129        pSMB->ParameterOffset = cpu_to_le16(param_offset);
5130        pSMB->SetupCount = 1;
5131        pSMB->Reserved3 = 0;
5132        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5133        byte_count = 3 /* pad */  + params + count;
5134        pSMB->ParameterCount = cpu_to_le16(params);
5135        pSMB->DataCount = cpu_to_le16(count);
5136        pSMB->TotalParameterCount = pSMB->ParameterCount;
5137        pSMB->TotalDataCount = pSMB->DataCount;
5138        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5139        pSMB->Reserved4 = 0;
5140        pSMB->hdr.smb_buf_length += byte_count;
5141        /* Samba server ignores set of file size to zero due to bugs in some
5142        older clients, but we should be precise - we use SetFileSize to
5143        set file size and do not want to truncate file size to zero
5144        accidently as happened on one Samba server beta by putting
5145        zero instead of -1 here */
5146        data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5147        data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5148        data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5149        data_offset->LastAccessTime = cpu_to_le64(args->atime);
5150        data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5151        data_offset->Uid = cpu_to_le64(args->uid);
5152        data_offset->Gid = cpu_to_le64(args->gid);
5153        /* better to leave device as zero when it is  */
5154        data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5155        data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5156        data_offset->Permissions = cpu_to_le64(mode);
5157
5158        if (S_ISREG(mode))
5159                data_offset->Type = cpu_to_le32(UNIX_FILE);
5160        else if (S_ISDIR(mode))
5161                data_offset->Type = cpu_to_le32(UNIX_DIR);
5162        else if (S_ISLNK(mode))
5163                data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5164        else if (S_ISCHR(mode))
5165                data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5166        else if (S_ISBLK(mode))
5167                data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5168        else if (S_ISFIFO(mode))
5169                data_offset->Type = cpu_to_le32(UNIX_FIFO);
5170        else if (S_ISSOCK(mode))
5171                data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5172
5173
5174        pSMB->ByteCount = cpu_to_le16(byte_count);
5175        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5176                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5177        if (rc)
5178                cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5179
5180        cifs_buf_release(pSMB);
5181        if (rc == -EAGAIN)
5182                goto setPermsRetry;
5183        return rc;
5184}
5185
5186int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5187                  const int notify_subdirs, const __u16 netfid,
5188                  __u32 filter, struct file *pfile, int multishot,
5189                  const struct nls_table *nls_codepage)
5190{
5191        int rc = 0;
5192        struct smb_com_transaction_change_notify_req *pSMB = NULL;
5193        struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5194        struct dir_notify_req *dnotify_req;
5195        int bytes_returned;
5196
5197        cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5198        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5199                      (void **) &pSMBr);
5200        if (rc)
5201                return rc;
5202
5203        pSMB->TotalParameterCount = 0 ;
5204        pSMB->TotalDataCount = 0;
5205        pSMB->MaxParameterCount = cpu_to_le32(2);
5206        /* BB find exact data count max from sess structure BB */
5207        pSMB->MaxDataCount = 0; /* same in little endian or be */
5208/* BB VERIFY verify which is correct for above BB */
5209        pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5210                                             MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5211
5212        pSMB->MaxSetupCount = 4;
5213        pSMB->Reserved = 0;
5214        pSMB->ParameterOffset = 0;
5215        pSMB->DataCount = 0;
5216        pSMB->DataOffset = 0;
5217        pSMB->SetupCount = 4; /* single byte does not need le conversion */
5218        pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5219        pSMB->ParameterCount = pSMB->TotalParameterCount;
5220        if (notify_subdirs)
5221                pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5222        pSMB->Reserved2 = 0;
5223        pSMB->CompletionFilter = cpu_to_le32(filter);
5224        pSMB->Fid = netfid; /* file handle always le */
5225        pSMB->ByteCount = 0;
5226
5227        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5228                         (struct smb_hdr *)pSMBr, &bytes_returned,
5229                         CIFS_ASYNC_OP);
5230        if (rc) {
5231                cFYI(1, ("Error in Notify = %d", rc));
5232        } else {
5233                /* Add file to outstanding requests */
5234                /* BB change to kmem cache alloc */
5235                dnotify_req = kmalloc(
5236                                                sizeof(struct dir_notify_req),
5237                                                 GFP_KERNEL);
5238                if (dnotify_req) {
5239                        dnotify_req->Pid = pSMB->hdr.Pid;
5240                        dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5241                        dnotify_req->Mid = pSMB->hdr.Mid;
5242                        dnotify_req->Tid = pSMB->hdr.Tid;
5243                        dnotify_req->Uid = pSMB->hdr.Uid;
5244                        dnotify_req->netfid = netfid;
5245                        dnotify_req->pfile = pfile;
5246                        dnotify_req->filter = filter;
5247                        dnotify_req->multishot = multishot;
5248                        spin_lock(&GlobalMid_Lock);
5249                        list_add_tail(&dnotify_req->lhead,
5250                                        &GlobalDnotifyReqList);
5251                        spin_unlock(&GlobalMid_Lock);
5252                } else
5253                        rc = -ENOMEM;
5254        }
5255        cifs_buf_release(pSMB);
5256        return rc;
5257}
5258#ifdef CONFIG_CIFS_XATTR
5259ssize_t
5260CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5261                 const unsigned char *searchName,
5262                 char *EAData, size_t buf_size,
5263                 const struct nls_table *nls_codepage, int remap)
5264{
5265                /* BB assumes one setup word */
5266        TRANSACTION2_QPI_REQ *pSMB = NULL;
5267        TRANSACTION2_QPI_RSP *pSMBr = NULL;
5268        int rc = 0;
5269        int bytes_returned;
5270        int name_len;
5271        struct fea *temp_fea;
5272        char *temp_ptr;
5273        __u16 params, byte_count;
5274
5275        cFYI(1, ("In Query All EAs path %s", searchName));
5276QAllEAsRetry:
5277        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5278                      (void **) &pSMBr);
5279        if (rc)
5280                return rc;
5281
5282        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5283                name_len =
5284                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5285                                     PATH_MAX, nls_codepage, remap);
5286                name_len++;     /* trailing null */
5287                name_len *= 2;
5288        } else {        /* BB improve the check for buffer overruns BB */
5289                name_len = strnlen(searchName, PATH_MAX);
5290                name_len++;     /* trailing null */
5291                strncpy(pSMB->FileName, searchName, name_len);
5292        }
5293
5294        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5295        pSMB->TotalDataCount = 0;
5296        pSMB->MaxParameterCount = cpu_to_le16(2);
5297        /* BB find exact max SMB PDU from sess structure BB */
5298        pSMB->MaxDataCount = cpu_to_le16(4000);
5299        pSMB->MaxSetupCount = 0;
5300        pSMB->Reserved = 0;
5301        pSMB->Flags = 0;
5302        pSMB->Timeout = 0;
5303        pSMB->Reserved2 = 0;
5304        pSMB->ParameterOffset = cpu_to_le16(offsetof(
5305        struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5306        pSMB->DataCount = 0;
5307        pSMB->DataOffset = 0;
5308        pSMB->SetupCount = 1;
5309        pSMB->Reserved3 = 0;
5310        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5311        byte_count = params + 1 /* pad */ ;
5312        pSMB->TotalParameterCount = cpu_to_le16(params);
5313        pSMB->ParameterCount = pSMB->TotalParameterCount;
5314        pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5315        pSMB->Reserved4 = 0;
5316        pSMB->hdr.smb_buf_length += byte_count;
5317        pSMB->ByteCount = cpu_to_le16(byte_count);
5318
5319        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5320                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5321        if (rc) {
5322                cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5323        } else {                /* decode response */
5324                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5325
5326                /* BB also check enough total bytes returned */
5327                /* BB we need to improve the validity checking
5328                of these trans2 responses */
5329                if (rc || (pSMBr->ByteCount < 4))
5330                        rc = -EIO;      /* bad smb */
5331           /* else if (pFindData){
5332                        memcpy((char *) pFindData,
5333                               (char *) &pSMBr->hdr.Protocol +
5334                               data_offset, kl);
5335                }*/ else {
5336                        /* check that length of list is not more than bcc */
5337                        /* check that each entry does not go beyond length
5338                           of list */
5339                        /* check that each element of each entry does not
5340                           go beyond end of list */
5341                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5342                        struct fealist *ea_response_data;
5343                        rc = 0;
5344                        /* validate_trans2_offsets() */
5345                        /* BB check if start of smb + data_offset > &bcc+ bcc */
5346                        ea_response_data = (struct fealist *)
5347                                (((char *) &pSMBr->hdr.Protocol) +
5348                                data_offset);
5349                        name_len = le32_to_cpu(ea_response_data->list_len);
5350                        cFYI(1, ("ea length %d", name_len));
5351                        if (name_len <= 8) {
5352                        /* returned EA size zeroed at top of function */
5353                                cFYI(1, ("empty EA list returned from server"));
5354                        } else {
5355                                /* account for ea list len */
5356                                name_len -= 4;
5357                                temp_fea = ea_response_data->list;
5358                                temp_ptr = (char *)temp_fea;
5359                                while (name_len > 0) {
5360                                        __u16 value_len;
5361                                        name_len -= 4;
5362                                        temp_ptr += 4;
5363                                        rc += temp_fea->name_len;
5364                                /* account for prefix user. and trailing null */
5365                                        rc = rc + 5 + 1;
5366                                        if (rc < (int)buf_size) {
5367                                                memcpy(EAData, "user.", 5);
5368                                                EAData += 5;
5369                                                memcpy(EAData, temp_ptr,
5370                                                       temp_fea->name_len);
5371                                                EAData += temp_fea->name_len;
5372                                                /* null terminate name */
5373                                                *EAData = 0;
5374                                                EAData = EAData + 1;
5375                                        } else if (buf_size == 0) {
5376                                                /* skip copy - calc size only */
5377                                        } else {
5378                                                /* stop before overrun buffer */
5379                                                rc = -ERANGE;
5380                                                break;
5381                                        }
5382                                        name_len -= temp_fea->name_len;
5383                                        temp_ptr += temp_fea->name_len;
5384                                        /* account for trailing null */
5385                                        name_len--;
5386                                        temp_ptr++;
5387                                        value_len =
5388                                              le16_to_cpu(temp_fea->value_len);
5389                                        name_len -= value_len;
5390                                        temp_ptr += value_len;
5391                                        /* BB check that temp_ptr is still
5392                                              within the SMB BB*/
5393
5394                                        /* no trailing null to account for
5395                                           in value len */
5396                                        /* go on to next EA */
5397                                        temp_fea = (struct fea *)temp_ptr;
5398                                }
5399                        }
5400                }
5401        }
5402        cifs_buf_release(pSMB);
5403        if (rc == -EAGAIN)
5404                goto QAllEAsRetry;
5405
5406        return (ssize_t)rc;
5407}
5408
5409ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5410                const unsigned char *searchName, const unsigned char *ea_name,
5411                unsigned char *ea_value, size_t buf_size,
5412                const struct nls_table *nls_codepage, int remap)
5413{
5414        TRANSACTION2_QPI_REQ *pSMB = NULL;
5415        TRANSACTION2_QPI_RSP *pSMBr = NULL;
5416        int rc = 0;
5417        int bytes_returned;
5418        int name_len;
5419        struct fea *temp_fea;
5420        char *temp_ptr;
5421        __u16 params, byte_count;
5422
5423        cFYI(1, ("In Query EA path %s", searchName));
5424QEARetry:
5425        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5426                      (void **) &pSMBr);
5427        if (rc)
5428                return rc;
5429
5430        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5431                name_len =
5432                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5433                                     PATH_MAX, nls_codepage, remap);
5434                name_len++;     /* trailing null */
5435                name_len *= 2;
5436        } else {        /* BB improve the check for buffer overruns BB */
5437                name_len = strnlen(searchName, PATH_MAX);
5438                name_len++;     /* trailing null */
5439                strncpy(pSMB->FileName, searchName, name_len);
5440        }
5441
5442        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5443        pSMB->TotalDataCount = 0;
5444        pSMB->MaxParameterCount = cpu_to_le16(2);
5445        /* BB find exact max SMB PDU from sess structure BB */
5446        pSMB->MaxDataCount = cpu_to_le16(4000);
5447        pSMB->MaxSetupCount = 0;
5448        pSMB->Reserved = 0;
5449        pSMB->Flags = 0;
5450        pSMB->Timeout = 0;
5451        pSMB->Reserved2 = 0;
5452        pSMB->ParameterOffset = cpu_to_le16(offsetof(
5453                struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5454        pSMB->DataCount = 0;
5455        pSMB->DataOffset = 0;
5456        pSMB->SetupCount = 1;
5457        pSMB->Reserved3 = 0;
5458        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5459        byte_count = params + 1 /* pad */ ;
5460        pSMB->TotalParameterCount = cpu_to_le16(params);
5461        pSMB->ParameterCount = pSMB->TotalParameterCount;
5462        pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5463        pSMB->Reserved4 = 0;
5464        pSMB->hdr.smb_buf_length += byte_count;
5465        pSMB->ByteCount = cpu_to_le16(byte_count);
5466
5467        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5468                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5469        if (rc) {
5470                cFYI(1, ("Send error in Query EA = %d", rc));
5471        } else {                /* decode response */
5472                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5473
5474                /* BB also check enough total bytes returned */
5475                /* BB we need to improve the validity checking
5476                of these trans2 responses */
5477                if (rc || (pSMBr->ByteCount < 4))
5478                        rc = -EIO;      /* bad smb */
5479           /* else if (pFindData){
5480                        memcpy((char *) pFindData,
5481                               (char *) &pSMBr->hdr.Protocol +
5482                               data_offset, kl);
5483                }*/ else {
5484                        /* check that length of list is not more than bcc */
5485                        /* check that each entry does not go beyond length
5486                           of list */
5487                        /* check that each element of each entry does not
5488                           go beyond end of list */
5489                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5490                        struct fealist *ea_response_data;
5491                        rc = -ENODATA;
5492                        /* validate_trans2_offsets() */
5493                        /* BB check if start of smb + data_offset > &bcc+ bcc*/
5494                        ea_response_data = (struct fealist *)
5495                                (((char *) &pSMBr->hdr.Protocol) +
5496                                data_offset);
5497                        name_len = le32_to_cpu(ea_response_data->list_len);
5498                        cFYI(1, ("ea length %d", name_len));
5499                        if (name_len <= 8) {
5500                        /* returned EA size zeroed at top of function */
5501                                cFYI(1, ("empty EA list returned from server"));
5502                        } else {
5503                                /* account for ea list len */
5504                                name_len -= 4;
5505                                temp_fea = ea_response_data->list;
5506                                temp_ptr = (char *)temp_fea;
5507                                /* loop through checking if we have a matching
5508                                name and then return the associated value */
5509                                while (name_len > 0) {
5510                                        __u16 value_len;
5511                                        name_len -= 4;
5512                                        temp_ptr += 4;
5513                                        value_len =
5514                                              le16_to_cpu(temp_fea->value_len);
5515                                /* BB validate that value_len falls within SMB,
5516                                even though maximum for name_len is 255 */
5517                                        if (memcmp(temp_fea->name, ea_name,
5518                                                  temp_fea->name_len) == 0) {
5519                                                /* found a match */
5520                                                rc = value_len;
5521                                /* account for prefix user. and trailing null */
5522                                                if (rc <= (int)buf_size) {
5523                                                        memcpy(ea_value,
5524                                                                temp_fea->name+temp_fea->name_len+1,
5525                                                                rc);
5526                                                        /* ea values, unlike ea
5527                                                           names, are not null
5528                                                           terminated */
5529                                                } else if (buf_size == 0) {
5530                                                /* skip copy - calc size only */
5531                                                } else {
5532                                                /* stop before overrun buffer */
5533                                                        rc = -ERANGE;
5534                                                }
5535                                                break;
5536                                        }
5537                                        name_len -= temp_fea->name_len;
5538                                        temp_ptr += temp_fea->name_len;
5539                                        /* account for trailing null */
5540                                        name_len--;
5541                                        temp_ptr++;
5542                                        name_len -= value_len;
5543                                        temp_ptr += value_len;
5544                                        /* No trailing null to account for in
5545                                           value_len.  Go on to next EA */
5546                                        temp_fea = (struct fea *)temp_ptr;
5547                                }
5548                        }
5549                }
5550        }
5551        cifs_buf_release(pSMB);
5552        if (rc == -EAGAIN)
5553                goto QEARetry;
5554
5555        return (ssize_t)rc;
5556}
5557
5558int
5559CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5560             const char *ea_name, const void *ea_value,
5561             const __u16 ea_value_len, const struct nls_table *nls_codepage,
5562             int remap)
5563{
5564        struct smb_com_transaction2_spi_req *pSMB = NULL;
5565        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5566        struct fealist *parm_data;
5567        int name_len;
5568        int rc = 0;
5569        int bytes_returned = 0;
5570        __u16 params, param_offset, byte_count, offset, count;
5571
5572        cFYI(1, ("In SetEA"));
5573SetEARetry:
5574        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5575                      (void **) &pSMBr);
5576        if (rc)
5577                return rc;
5578
5579        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5580                name_len =
5581                    cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5582                                     PATH_MAX, nls_codepage, remap);
5583                name_len++;     /* trailing null */
5584                name_len *= 2;
5585        } else {        /* BB improve the check for buffer overruns BB */
5586                name_len = strnlen(fileName, PATH_MAX);
5587                name_len++;     /* trailing null */
5588                strncpy(pSMB->FileName, fileName, name_len);
5589        }
5590
5591        params = 6 + name_len;
5592
5593        /* done calculating parms using name_len of file name,
5594        now use name_len to calculate length of ea name
5595        we are going to create in the inode xattrs */
5596        if (ea_name == NULL)
5597                name_len = 0;
5598        else
5599                name_len = strnlen(ea_name, 255);
5600
5601        count = sizeof(*parm_data) + ea_value_len + name_len;
5602        pSMB->MaxParameterCount = cpu_to_le16(2);
5603        /* BB find max SMB PDU from sess */
5604        pSMB->MaxDataCount = cpu_to_le16(1000);
5605        pSMB->MaxSetupCount = 0;
5606        pSMB->Reserved = 0;
5607        pSMB->Flags = 0;
5608        pSMB->Timeout = 0;
5609        pSMB->Reserved2 = 0;
5610        param_offset = offsetof(struct smb_com_transaction2_spi_req,
5611                                InformationLevel) - 4;
5612        offset = param_offset + params;
5613        pSMB->InformationLevel =
5614                cpu_to_le16(SMB_SET_FILE_EA);
5615
5616        parm_data =
5617                (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5618                                       offset);
5619        pSMB->ParameterOffset = cpu_to_le16(param_offset);
5620        pSMB->DataOffset = cpu_to_le16(offset);
5621        pSMB->SetupCount = 1;
5622        pSMB->Reserved3 = 0;
5623        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5624        byte_count = 3 /* pad */  + params + count;
5625        pSMB->DataCount = cpu_to_le16(count);
5626        parm_data->list_len = cpu_to_le32(count);
5627        parm_data->list[0].EA_flags = 0;
5628        /* we checked above that name len is less than 255 */
5629        parm_data->list[0].name_len = (__u8)name_len;
5630        /* EA names are always ASCII */
5631        if (ea_name)
5632                strncpy(parm_data->list[0].name, ea_name, name_len);
5633        parm_data->list[0].name[name_len] = 0;
5634        parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5635        /* caller ensures that ea_value_len is less than 64K but
5636        we need to ensure that it fits within the smb */
5637
5638        /*BB add length check to see if it would fit in
5639             negotiated SMB buffer size BB */
5640        /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5641        if (ea_value_len)
5642                memcpy(parm_data->list[0].name+name_len+1,
5643                       ea_value, ea_value_len);
5644
5645        pSMB->TotalDataCount = pSMB->DataCount;
5646        pSMB->ParameterCount = cpu_to_le16(params);
5647        pSMB->TotalParameterCount = pSMB->ParameterCount;
5648        pSMB->Reserved4 = 0;
5649        pSMB->hdr.smb_buf_length += byte_count;
5650        pSMB->ByteCount = cpu_to_le16(byte_count);
5651        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5652                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5653        if (rc)
5654                cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5655
5656        cifs_buf_release(pSMB);
5657
5658        if (rc == -EAGAIN)
5659                goto SetEARetry;
5660
5661        return rc;
5662}
5663
5664#endif
5665
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.