// SPDX-License-Identifier: LGPL-2.1
/*
*
* SMB/CIFS session setup handling routines
*
* Copyright (c) International Business Machines Corp., 2006, 2009
* Author(s): Steve French (sfrench@us.ibm.com)
*
*/
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "ntlmssp.h"
#include "nterr.h"
#include <linux/utsname.h>
#include <linux/slab.h>
#include <linux/version.h>
#include "cifsfs.h"
#include "cifs_spnego.h"
#include "smb2proto.h"
#include "fs_context.h"
static int
cifs_ses_add_channel(struct cifs_ses *ses,
struct cifs_server_iface *iface);
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
{
int i;
spin_lock(&ses->chan_lock);
for (i = 0; i < ses->chan_count; i++) {
if (ses->chans[i].iface == iface) {
spin_unlock(&ses->chan_lock);
return true;
}
}
spin_unlock(&ses->chan_lock);
return false;
}
/* channel helper functions. assumed that chan_lock is held by caller. */
int
cifs_ses_get_chan_index(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int i;
/* if the channel is waiting for termination */
if (server && server->terminate)
return CIFS_INVAL_CHAN_INDEX;
for (i = 0; i < ses->chan_count; i++) {
if (ses->chans[i].server == server)
return i;
}
/* If we didn't find the channel, it is likely a bug */
if (server)
cifs_dbg(VFS, "unable to get chan index for server: 0x%llx",
server->conn_id);
return CIFS_INVAL_CHAN_INDEX;
}
void
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
int chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX)
return;
ses->chans[chan_index].in_reconnect = true;
}
void
cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX)
return;
ses->chans[chan_index].in_reconnect = false;
}
void
cifs_chan_set_need_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX)
return;
set_bit(chan_index, &ses->chans_need_reconnect);
cifs_dbg(FYI, "Set reconnect bitmask for chan %u; now 0x%lx\n",
chan_index, ses->chans_need_reconnect);
}
void
cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX)
return;
clear_bit(chan_index, &ses->chans_need_reconnect);
cifs_dbg(FYI, "Cleared reconnect bitmask for chan %u; now 0x%lx\n",
chan_index, ses->chans_need_reconnect);
}
bool
cifs_chan_needs_reconnect(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX)
return true; /* err on the safer side */
return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
}
bool
cifs_chan_is_iface_active(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX)
return true; /* err on the safer side */
return ses->chans[chan_index].iface &&
ses->chans[chan_index].iface->is_active;
}
/* returns number of channels added */
int cifs_try_adding_channels(struct cifs_ses *ses)
{