linux/fs/cifs/smb2transport.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/smb2transport.c
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2002, 2011
   5 *                 Etersoft, 2012
   6 *   Author(s): Steve French (sfrench@us.ibm.com)
   7 *              Jeremy Allison (jra@samba.org) 2006
   8 *              Pavel Shilovsky (pshilovsky@samba.org) 2012
   9 *
  10 *   This library is free software; you can redistribute it and/or modify
  11 *   it under the terms of the GNU Lesser General Public License as published
  12 *   by the Free Software Foundation; either version 2.1 of the License, or
  13 *   (at your option) any later version.
  14 *
  15 *   This library is distributed in the hope that it will be useful,
  16 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  18 *   the GNU Lesser General Public License for more details.
  19 *
  20 *   You should have received a copy of the GNU Lesser General Public License
  21 *   along with this library; if not, write to the Free Software
  22 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23 */
  24
  25#include <linux/fs.h>
  26#include <linux/list.h>
  27#include <linux/wait.h>
  28#include <linux/net.h>
  29#include <linux/delay.h>
  30#include <linux/uaccess.h>
  31#include <asm/processor.h>
  32#include <linux/mempool.h>
  33#include "smb2pdu.h"
  34#include "cifsglob.h"
  35#include "cifsproto.h"
  36#include "smb2proto.h"
  37#include "cifs_debug.h"
  38#include "smb2status.h"
  39
  40/*
  41 * Set message id for the request. Should be called after wait_for_free_request
  42 * and when srv_mutex is held.
  43 */
  44static inline void
  45smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
  46{
  47        hdr->MessageId = get_next_mid(server);
  48}
  49
  50static struct mid_q_entry *
  51smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
  52                     struct TCP_Server_Info *server)
  53{
  54        struct mid_q_entry *temp;
  55
  56        if (server == NULL) {
  57                cERROR(1, "Null TCP session in smb2_mid_entry_alloc");
  58                return NULL;
  59        }
  60
  61        temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
  62        if (temp == NULL)
  63                return temp;
  64        else {
  65                memset(temp, 0, sizeof(struct mid_q_entry));
  66                temp->mid = smb_buffer->MessageId;      /* always LE */
  67                temp->pid = current->pid;
  68                temp->command = smb_buffer->Command;    /* Always LE */
  69                temp->when_alloc = jiffies;
  70                temp->server = server;
  71
  72                /*
  73                 * The default is for the mid to be synchronous, so the
  74                 * default callback just wakes up the current task.
  75                 */
  76                temp->callback = cifs_wake_up_task;
  77                temp->callback_data = current;
  78        }
  79
  80        atomic_inc(&midCount);
  81        temp->mid_state = MID_REQUEST_ALLOCATED;
  82        return temp;
  83}
  84
  85static int
  86smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
  87                   struct mid_q_entry **mid)
  88{
  89        if (ses->server->tcpStatus == CifsExiting)
  90                return -ENOENT;
  91
  92        if (ses->server->tcpStatus == CifsNeedReconnect) {
  93                cFYI(1, "tcp session dead - return to caller to retry");
  94                return -EAGAIN;
  95        }
  96
  97        if (ses->status != CifsGood) {
  98                /* check if SMB2 session is bad because we are setting it up */
  99                if ((buf->Command != SMB2_SESSION_SETUP) &&
 100                    (buf->Command != SMB2_NEGOTIATE))
 101                        return -EAGAIN;
 102                /* else ok - we are setting up session */
 103        }
 104        *mid = smb2_mid_entry_alloc(buf, ses->server);
 105        if (*mid == NULL)
 106                return -ENOMEM;
 107        spin_lock(&GlobalMid_Lock);
 108        list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q);
 109        spin_unlock(&GlobalMid_Lock);
 110        return 0;
 111}
 112
 113int
 114smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 115                   bool log_error)
 116{
 117        unsigned int len = get_rfc1002_length(mid->resp_buf);
 118
 119        dump_smb(mid->resp_buf, min_t(u32, 80, len));
 120        /* convert the length into a more usable form */
 121        /* BB - uncomment with SMB2 signing implementation */
 122        /* if ((len > 24) &&
 123            (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
 124                if (smb2_verify_signature(mid->resp_buf, server))
 125                        cERROR(1, "Unexpected SMB signature");
 126        } */
 127
 128        return map_smb2_to_linux_error(mid->resp_buf, log_error);
 129}
 130
 131int
 132smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
 133                   unsigned int nvec, struct mid_q_entry **ret_mid)
 134{
 135        int rc;
 136        struct smb2_hdr *hdr = (struct smb2_hdr *)iov[0].iov_base;
 137        struct mid_q_entry *mid;
 138
 139        smb2_seq_num_into_buf(ses->server, hdr);
 140
 141        rc = smb2_get_mid_entry(ses, hdr, &mid);
 142        if (rc)
 143                return rc;
 144        /* rc = smb2_sign_smb2(iov, nvec, ses->server);
 145        if (rc)
 146                delete_mid(mid); */
 147        *ret_mid = mid;
 148        return rc;
 149}
 150
 151int
 152smb2_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
 153                         unsigned int nvec, struct mid_q_entry **ret_mid)
 154{
 155        int rc = 0;
 156        struct smb2_hdr *hdr = (struct smb2_hdr *)iov[0].iov_base;
 157        struct mid_q_entry *mid;
 158
 159        smb2_seq_num_into_buf(server, hdr);
 160
 161        mid = smb2_mid_entry_alloc(hdr, server);
 162        if (mid == NULL)
 163                return -ENOMEM;
 164
 165        /* rc = smb2_sign_smb2(iov, nvec, server);
 166        if (rc) {
 167                DeleteMidQEntry(mid);
 168                return rc;
 169        }*/
 170        *ret_mid = mid;
 171        return rc;
 172}
 173
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.