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