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