⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 target_negotiate.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*	common/target_negotiate.c * *	vi: set autoindent tabstop=4 shiftwidth=4 : * *	This defines the functions used in the Login phase *	by the iSCSI target for parameter negotiation * *	Copyright (C) 2001-2004 InterOperability Lab (IOL) *	University of New Hampshire (UNH) *	Durham, NH 03824 * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2, or (at your option) *	any later version. * *	This program is distributed in the hope that it will be useful, *	but WITHOUT ANY WARRANTY; without even the implied warranty of *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *	GNU General Public License for more details. * *	You should have received a copy of the GNU General Public License *	along with this program; if not, write to the Free Software *	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, *	USA. * *	The name of IOL and/or UNH may not be used to endorse or promote *	products derived from this software without specific prior *  written permission. *//* * Converted to  indent -kr -i4 -ts4 -sob -l80 -ss -bs -psl. 07/25/2003 * TO Do. IMO . jpd * 1. target_security_negotiate(), target_parameter_negotiate() and *    scan_input_and_process have too many parameters both as  *    formal and auotomatic. * *    May want to consider passing structures. Also the functions *    are long. Consider resturctureing into smaller functions *    for each state. This is critical code that has been well tested *    so the risk is obvious.  */#include <linux/kernel.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/ctype.h>#include <linux/string.h>#include <linux/socket.h>#include <linux/module.h>#include "iscsi_common.h"#include "debug.h"#include "my_memory.h"#include "crc.h"/* chap and srp support - CHONG */#include "../security/chap/chap.h"#include "../security/srp/srp.h"#include "../security/misc/misc_func.h"#include "text_param.h"#include "target_negotiate.h"/************************************************************************* *This function sends a login response with proper status code when error * occurs in target during login phase * ************************************************************************/static intlogin_reject(struct iscsi_conn *conn, int class, int detail,			 struct generic_pdu *outputpdu){	TRACE(TRACE_ENTER_LEAVE, "Enter login_reject\n");	outputpdu->status_class = class;	outputpdu->status_detail = detail;	/* Draft 20, Section 5.3.1 Login Phase Start	   "-Login Response with Login Reject.  This is an immediate rejection	   from the target that causes the connection to terminate and the session	   to terminate if this is the first (or only) connection of a new	   session.  The T bit and the CSG and NSG fields are reserved."	 */	outputpdu->flags &= ~CSG;	/* set the CSN to zero */	outputpdu->flags &= ~NSG;	/* set the NSG to zero */	outputpdu->flags &= ~T_BIT;	/* Draft 20, Section 10.13.4 StatSN (for Login Response)	   "This field is valid only if Status-Class is 0."	 */	outputpdu->cmd_sn = 0;	outputpdu->exp_stat_sn = 0;	outputpdu->max_cmd_sn = 0;	/* send out the outputpdu which never has any data attached to it */	outputpdu->text_length = 0;	if (iscsi_send_msg(conn->conn_socket, outputpdu, conn->connection_flags) <		0) {		TRACE(TRACE_DEBUG, "iscsi_send_msg failed\n");		return -1;	}	TRACE(TRACE_ENTER_LEAVE, "Leave login_reject\n");	return 0;}/******************************************************************* *This function checks every login request except the first login for * new connection or session * *******************************************************************/static intcheck_other_login(struct iscsi_conn *conn, int correct_CSG,				  struct generic_pdu *inputpdu, struct generic_pdu *outputpdu){	int retval = 0;	TRACE(TRACE_ENTER_LEAVE, "Enter check_other_login\n");	/* check if the login has proper version set */	if ((inputpdu->version_max > ISCSI_MAX_VERSION) ||		(inputpdu->version_max < inputpdu->version_active)) {		/* protocol error  */		TRACE_ERROR("Bad version_max %d\n", inputpdu->version_max);		login_reject(conn, STAT_CLASS_INITIATOR,					 STAT_DETAIL_VERSION_NOT_SUPPORTED, outputpdu);		retval = -1;	}	TRACE(TRACE_ENTER_LEAVE, "Leave check_other_login, retval %d\n", retval);	return retval;}/***************************************************************************** *  This function checks if the first login has InitiatorName, and *  TargetName if SessionType is Normal (Discovery does not need TargetName) *  Send login reject if any parameter is missing. * ****************************************************************************/static intcheck_flags(struct iscsi_conn *conn, __u64 login_flags,			struct generic_pdu *outputpdu,			struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS]){	int err = 1;	struct parameter_type *ptr;	TRACE(TRACE_ENTER_LEAVE, "Enter check_flags\n");	if (!(login_flags & INITIATORNAME_FLAG)) {		TRACE_ERROR("Initiator name not given in initial login\n");		err = -1;	} else {		ptr = find_flag_parameter(TARGETPORTALGROUPTAG_FLAG, p_param_tbl);		if (!(login_flags & TARGETNAME_FLAG)) {			/* TargetName not included in first login pdu by initiator */			if (login_flags & DISCOVERY_FLAG) {				/* Discovery session, do not return TargetPortalGroupTag */				if (ptr) {					ptr->neg_info &= ~KEY_TO_BE_NEGOTIATED;				}			} else {				/* Normal session with no TargetName is bad */				TRACE_ERROR				("Target name not given in initial login to NORMAL session\n");				err = -1;			}		} else {			/* TargetName was in first login pdu from initiator			 * RFC 3720 Section 2.1 Definitions			 * "- SSID (Session ID):			 * ...			 * The TargetPortalGroupTag key must also be returned by the target			 * as a confirmation during connection establishment when			 * TargetName is given."			 */			if (ptr) {				/* force sending of TargetPortalGroupTag				 * (correct value already set up when connection set up)				 */				ptr->neg_info |= KEY_TO_BE_NEGOTIATED;			}		}	}	/* send a login reject if an error was seen */	if (err < 0) {		login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_MISSING_PARAMETER,					 outputpdu);	}	TRACE(TRACE_ENTER_LEAVE, "Leave check_flags, err = %d\n", err);	return err;}/**************************************************************** * This function checks the first login in a new connection * ****************************************************************/static intcheck_first_login(struct iscsi_conn *conn,				  struct generic_pdu *inputpdu, struct generic_pdu *outputpdu){	int retval = 0;	TRACE(TRACE_ENTER_LEAVE, "Enter check_first_login\n");	/* check that this new connection does not exceed MaxConnections	 * except for the following:	 * Draft 20 Section 5.3.4 Connection Reinstatement	 * "Targets MUST support opening a second connection even when they do	 * not support multiple connections in Full Feature Phase if	 * ErrorRecoveryLevel is 2 and SHOULD support opening a second	 * connection if ErrorRecoveryLevel is less than 2."	 */	if (conn->session->nconn > conn->session->oper_param->MaxConnections		&& conn->session->nconn > 2) {		TRACE_ERROR("current nconn %d > MaxConnections %d\n",					conn->session->nconn,					conn->session->oper_param->MaxConnections);		login_reject(conn, STAT_CLASS_INITIATOR,					 STAT_DETAIL_TOO_MANY_CONNECTIONS, outputpdu);		retval = -1;		goto out;	}	/* check versions */	if (inputpdu->version_active != conn->session->version_min) {		TRACE_ERROR("unsupported version %d, terminate the connection\n",					inputpdu->version_active);		login_reject(conn, STAT_CLASS_INITIATOR,					 STAT_DETAIL_VERSION_NOT_SUPPORTED, outputpdu);		retval = -1;		goto out;	}	conn->session->version_active = conn->session->version_max;out:	TRACE(TRACE_ENTER_LEAVE, "Leave check_first_login, retval %d\n", retval);	return retval;}void __attribute__ ((no_instrument_function))print_isid_tsih_message(struct iscsi_session *session, char *message){	int i;	char buffer[32], *ptr;		ptr = buffer;	for (i = 0; i < 6; i++) {		ptr += sprintf(ptr, " %02x", session->isid[i]);	}	printk("%sISID%s TSIH %u\n", message, buffer, session->tsih);}static void __attribute__ ((no_instrument_function))finalize_new_session(struct iscsi_session *session){	struct iscsi_global *host;	struct list_head *list_ptr;	struct iscsi_session *temp;	struct parameter_type *sess_iname, *temp_iname;	struct parameter_type *sess_tname, *temp_tname;	struct parameter_type *sess_pname, *temp_pname;	__u16 new_tsih;	if ((host = session->devdata) == NULL) {		/* should never happen */		goto out;	}	if ((sess_iname = find_flag_parameter(INITIATORNAME_FLAG,										  *session->session_params)) == NULL) {		/* should never happen */		goto out;	}	if ((sess_tname = find_flag_parameter(TARGETNAME_FLAG,										  *session->session_params)) == NULL) {		/* should never happen */		goto out;	}	if ((sess_pname = find_flag_parameter(TARGETPORTALGROUPTAG_FLAG,										  *session->session_params)) == NULL) {		/* should never happen */		goto out;	}	if (down_interruptible(&host->session_sem))		goto out;	/* check to see if this I_T nexus (i.e., session) is already in use	 * if so, we have to reset the old session	 *	 * RFC 3720 Section 2.1 Definitions	 * "I_T nexus: According to [SAM2], the I_T nexus is a relationship	 * between a SCSI Initiator Port and a SCSI Target Port.  For iSCSI,	 * this relationship is a session, defined as a relationship between	 * an iSCSI Initiator's end of the session (SCSI Initiator Port) and	 * the iSCSI Target's Portal Group.  The I_T nexus can be identified	 * by the conjunction of the SCSI port names; that is, the I_T nexus	 * identifier is the tuple (iSCSI Initiator Name + ',i,' + ISID, iSCSI	 * Target Name + ',t,' + Portal Group Tag).	 */	list_for_each(list_ptr, &host->session_list) {		temp = list_entry(list_ptr, struct iscsi_session, sess_link);		if (TRACE_TEST(TRACE_DEBUG))			print_isid_tsih_message(temp, "Looking at ");		/* do not look at sessions still being set up */		if (temp->tsih == 0)			continue;		/* first compare the isid's, since those are easy to get ahold of */		if (memcmp(temp->isid, session->isid, 6))			continue;		if (TRACE_TEST(TRACE_DEBUG))			print_isid_tsih_message(temp, "");		/* now get and compare the initiator names */		if ((temp_iname = find_flag_parameter(INITIATORNAME_FLAG,											  *temp->session_params)) == NULL) {			/* should never happen */			continue;		}		if (strcmp(temp_iname->str_value, sess_iname->str_value))			continue;		TRACE(TRACE_DEBUG, "InitiatorName=%s\n", temp_iname->str_value);		/* now get and compare the target names */		if ((temp_tname = find_flag_parameter(TARGETNAME_FLAG,											  *temp->session_params)) == NULL) {			/* should never happen */			continue;		}		if (temp_tname->str_value == NULL) {			if(sess_tname->str_value != NULL)				continue;			/* else both target names are NULL, we have a match, fall thru */		} else if (sess_tname->str_value == NULL) {			continue;		} else if (strcmp(temp_tname->str_value, sess_tname->str_value)) {			continue;		} else {			TRACE(TRACE_DEBUG, "TargetName=%s\n", temp_tname->str_value);			/* finally get and compare the target portal group tags */			if ((temp_pname = find_flag_parameter(TARGETPORTALGROUPTAG_FLAG,											  *temp->session_params)) == NULL) {				/* should never happen */				continue;			}			if (temp_pname->int_value != sess_pname->int_value)				continue;			TRACE(TRACE_DEBUG, "TargetPortalGroupTag=%u\n",				  temp_pname->int_value);		}		/* all 4 components of the I_T nexus match, the new session is a		 * reinstatement of the old session		 */		print_isid_tsih_message(temp, "Reinstate session with ");		iscsi_release_session(temp);		break;	}	/* assign this new session a new tsih which is not zero */retry_tsih:	if ((new_tsih = ++host->ntsih) == 0)		new_tsih = ++host->ntsih;	/* also check to ensure this tsih is not already in use! */	list_for_each(list_ptr, &host->session_list) {		temp = list_entry(list_ptr, struct iscsi_session, sess_link);		 if (temp->tsih == new_tsih)			goto retry_tsih;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -