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

📄 iscsi-login.c

📁 ISCSI user client software.Client would be used to access the IPSAN server.
💻 C
📖 第 1 页 / 共 3 页
字号:
		} else			session->irrelevant_keys_bitmap |=						IRRELEVANT_MAXCONNECTIONS;		text = value_end;	} else if (iscsi_find_key_value("ErrorRecoveryLevel", text, end,					 &value, &value_end)) {		if (strcmp(value, "0")) {			iscsi_host_err(session, "Login negotiation failed, "				       "can't accept ErrorRecovery %s\n",				       value);			return LOGIN_NEGOTIATION_FAILED;		}		text = value_end;	} else if (iscsi_find_key_value ("X-com.cisco.protocol", text, end,					 &value, &value_end)) {		if (strcmp(value, "NotUnderstood") &&		    strcmp(value, "Reject") &&		    strcmp(value, "Irrelevant") &&		    strcmp(value, "draft20")) {			/* if we didn't get a compatible protocol, fail */			iscsi_host_err(session, "Login version mismatch, "				       "can't accept protocol %s\n", value);			return LOGIN_VERSION_MISMATCH;		}		text = value_end;	} else if (iscsi_find_key_value("X-com.cisco.PingTimeout", text, end,					 &value, &value_end))		/* we don't really care what the target ends up using */		text = value_end;	else if (iscsi_find_key_value("X-com.cisco.sendAsyncText", text, end,					 &value, &value_end))		/* we don't bother for the target response */		text = value_end;	else {		iscsi_host_err(session, "Login negotiation failed, couldn't "			       "recognize text %s\n", text);		return LOGIN_NEGOTIATION_FAILED;	}	*data = text;	return LOGIN_OK;}static enum iscsi_login_statuscheck_security_stage_status(struct iscsi_session *session,			    struct iscsi_acl *auth_client){	int debug_status = 0;	switch (acl_recv_end(auth_client)) {	case AUTH_STATUS_CONTINUE:		/* continue sending PDUs */		break;	case AUTH_STATUS_PASS:		break;	case AUTH_STATUS_NO_ERROR:	/* treat this as an error,					 * since we should get a					 * different code					 */	case AUTH_STATUS_ERROR:	case AUTH_STATUS_FAIL:	default:		if (acl_get_dbg_status(auth_client, &debug_status) !=		    AUTH_STATUS_NO_ERROR)			iscsi_host_err(session, "Login authentication failed "				       "with target %s, %s\n",				       session->target_name,				       acl_dbg_status_to_text(debug_status));		else			iscsi_host_err(session, "Login authentication failed "				       "with target %s\n",				       session->target_name);		return LOGIN_AUTHENTICATION_FAILED;	}	return LOGIN_OK;}/* * this assumes the text data is always NULL terminated.  The caller can * always arrange for that by using a slightly larger buffer than the max PDU * size, and then appending a NULL to the PDU. */static enum iscsi_login_statusiscsi_process_login_response(struct iscsi_session *session,			     struct iscsi_login_rsp_hdr *login_rsp_pdu,			     char *data, int max_data_length){	int transit = login_rsp_pdu->flags & ISCSI_FLAG_LOGIN_TRANSIT;	char *text = data;	char *end;	int pdu_current_stage, pdu_next_stage;	enum iscsi_login_status ret;	struct iscsi_acl *auth_client = session->auth_client_block ?					session->auth_client_block : NULL;	end = text + ntoh24(login_rsp_pdu->dlength) + 1;	if (end >= (data + max_data_length)) {		iscsi_host_err(session, "Login failed, process_login_response "			       "buffer too small to guarantee NULL "			       "termination\n");		return LOGIN_FAILED;	}	/* guarantee a trailing NUL */	*end = '\0';	/* if the response status was success, sanity check the response */	if (login_rsp_pdu->status_class == ISCSI_STATUS_CLS_SUCCESS) {		/* check the active version */		if (login_rsp_pdu->active_version != ISCSI_DRAFT20_VERSION) {			iscsi_host_err(session, "Login version mismatch, "				       "received incompatible active iSCSI "				       "version 0x%02x, expected version "				       "0x%02x\n",				       login_rsp_pdu->active_version,				       ISCSI_DRAFT20_VERSION);			return LOGIN_VERSION_MISMATCH;		}		/* make sure the current stage matches */		pdu_current_stage = (login_rsp_pdu->flags &				    ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;		if (pdu_current_stage != session->current_stage) {			iscsi_host_err(session, "Received invalid login PDU, "				       "current stage mismatch, session %d, "				       "response %d\n", session->current_stage,				       pdu_current_stage);			return LOGIN_INVALID_PDU;		}		/*		 * make sure that we're actually advancing if the T-bit is set		 */		pdu_next_stage = login_rsp_pdu->flags &				 ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;		if (transit && (pdu_next_stage <= session->current_stage))			return LOGIN_INVALID_PDU;	}	if (session->current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {		if (acl_recv_begin(auth_client) != AUTH_STATUS_NO_ERROR) {			iscsi_host_err(session, "Login failed because "				       "acl_recv_begin failed\n");			return LOGIN_FAILED;		}		if (acl_recv_transit_bit(auth_client, transit) !=		    AUTH_STATUS_NO_ERROR) {			iscsi_host_err(session, "Login failed because "				  "acl_recv_transit_bit failed\n");			return LOGIN_FAILED;		}	}	/* scan the text data */	while (text && (text < end)) {		/* skip any NULs separating each text key=value pair */		while ((text < end) && (*text == '\0'))			text++;		if (text >= end)			break;		/* handle keys appropriate for each stage */		switch (session->current_stage) {		case ISCSI_SECURITY_NEGOTIATION_STAGE:{				ret = get_security_text_keys(session, &text,							     auth_client, end);				if (ret != LOGIN_OK)					return ret;				break;			}		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:{				ret = get_op_params_text_keys(session, &text,							      end);				if (ret != LOGIN_OK)					return ret;				break;			}		default:			return LOGIN_FAILED;		}	}	if (session->current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {		ret = check_security_stage_status(session, auth_client);		if (ret != LOGIN_OK)			return ret;	}	/* record some of the PDU fields for later use */	session->tsih = ntohs(login_rsp_pdu->tsih);	session->exp_cmd_sn = ntohl(login_rsp_pdu->expcmdsn);	session->max_cmd_sn = ntohl(login_rsp_pdu->maxcmdsn);	if (login_rsp_pdu->status_class == ISCSI_STATUS_CLS_SUCCESS)		session->exp_stat_sn = ntohl(login_rsp_pdu->statsn) + 1;	if (transit) {		/* advance to the next stage */		session->partial_response = 0;		session->current_stage = login_rsp_pdu->flags &					 ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;		session->irrelevant_keys_bitmap = 0;	} else		/*		 * we got a partial response, don't advance,		 * more negotiation to do		 */		session->partial_response = 1;	return LOGIN_OK;	/* this PDU is ok, though the login process				 * may not be done yet				 */}static intadd_params_normal_session(struct iscsi_session *session, struct iscsi_hdr *pdu,                    char *data, int max_data_length){	char value[AUTH_STR_MAX_LEN];	/* these are only relevant for normal sessions */	if (!iscsi_add_text(session, pdu, data, max_data_length, "InitialR2T",			    session->initial_r2t ? "Yes" : "No"))		return 0;	if (!iscsi_add_text(session, pdu, data, max_data_length,			    "ImmediateData",			    session->immediate_data ? "Yes" : "No"))		return 0;	sprintf(value, "%d", session->max_burst_len);	if (!iscsi_add_text(session, pdu, data, max_data_length,			    "MaxBurstLength", value))		return 0;	sprintf(value, "%d",session->first_burst_len);	if (!iscsi_add_text(session, pdu, data, max_data_length,			    "FirstBurstLength", value))		return 0;	/* these we must have */	if (!iscsi_add_text(session, pdu, data, max_data_length,			    "MaxOutstandingR2T", "1"))		return 0;	if (!iscsi_add_text(session, pdu, data, max_data_length,			    "MaxConnections", "1"))		return 0;	if (!iscsi_add_text(session, pdu, data, max_data_length,			    "DataPDUInOrder", "Yes"))		return 0;	if (!iscsi_add_text(session, pdu, data, max_data_length,			    "DataSequenceInOrder", "Yes"))		return 0;	return 1;}static intadd_vendor_specific_text(struct iscsi_session *session, struct iscsi_hdr *pdu,                    char *data, int max_data_length){	char value[AUTH_STR_MAX_LEN];	/*	 * adjust the target's PingTimeout for normal sessions,	 * so that it matches the driver's ping timeout.  The	 * network probably has the same latency in both	 * directions, so the values ought to match.	 */	if (session->ping_timeout >= 0) {		sprintf(value, "%d", session->ping_timeout);		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "X-com.cisco.PingTimeout", value))			return 0;	}	if (session->send_async_text >= 0)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "X-com.cisco.sendAsyncText",				    session->send_async_text ? "Yes" : "No"))			return 0;	/*	 * vendor-specific protocol specification. list of protocol level	 * strings in order of preference allowable values are: draft<n>	 * (e.g. draft8), rfc<n> (e.g. rfc666).	 * For example: "X-com.cisco.protocol=draft20,draft8" requests draft 20,	 * or 8 if 20 isn't supported. "X-com.cisco.protocol=draft8,draft20"	 * requests draft 8, or 20 if 8 isn't supported. Targets that	 * understand this key SHOULD return the protocol level they selected	 * as a response to this key, though the active_version may be	 * sufficient to distinguish which protocol was chosen.	 * Note: This probably won't work unless we start in op param stage,	 * since the security stage limits what keys we can send, and we'd need	 * to have sent this on the first PDU of the login.  Keep sending it for	 * informational use, and so that we can sanity check things later if	 * the RFC and draft20 are using the same active version number,	 * but have non-trivial differences.	 */	if (!iscsi_add_text(session, pdu, data, max_data_length,			     "X-com.cisco.protocol", "draft20"))		return 0;	return 1;}static intcheck_irrelevant_keys(struct iscsi_session *session, struct iscsi_hdr *pdu,                    char *data, int max_data_length){	/* If you receive irrelevant keys, just check them from the irrelevant	 * keys bitmap and respond with the key=Irrelevant text	 */	if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXCONNECTIONS)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "MaxConnections", "Irrelevant"))			return 0;	if (session->irrelevant_keys_bitmap & IRRELEVANT_INITIALR2T)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "InitialR2T", "Irrelevant"))			return 0;	if (session->irrelevant_keys_bitmap & IRRELEVANT_IMMEDIATEDATA)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "ImmediateData", "Irrelevant"))			return 0;	if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXBURSTLENGTH)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "MaxBurstLength", "Irrelevant"))			return 0;	if (session->irrelevant_keys_bitmap & IRRELEVANT_FIRSTBURSTLENGTH)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "FirstBurstLength", "Irrelevant"))			return 0;	if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXOUTSTANDINGR2T)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "MaxOutstandingR2T", "Irrelevant"))			return 0;	if (session->irrelevant_keys_bitmap & IRRELEVANT_DATAPDUINORDER)		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "DataPDUInOrder", "Irrelevant"))			return 0;	if (session->irrelevant_keys_bitmap & IRRELEVANT_DATASEQUENCEINORDER )		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "DataSequenceInOrder", "Irrelevant"))			return 0;	return 1;}static intfill_crc_digest_text(struct iscsi_session *session, struct iscsi_hdr *pdu,		     char *data, int max_data_length){	switch (session->header_digest) {	case ISCSI_DIGEST_NONE:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "HeaderDigest", "None"))			return 0;		break;	case ISCSI_DIGEST_CRC32C:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "HeaderDigest", "CRC32C"))			return 0;		break;	case ISCSI_DIGEST_CRC32C_NONE:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "HeaderDigest", "CRC32C,None"))			return 0;		break;	default:	case ISCSI_DIGEST_NONE_CRC32C:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "HeaderDigest", "None,CRC32C"))			return 0;		break;	}	switch (session->data_digest) {	case ISCSI_DIGEST_NONE:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "DataDigest", "None"))			return 0;		break;	case ISCSI_DIGEST_CRC32C:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "DataDigest", "CRC32C"))			return 0;		break;	case ISCSI_DIGEST_CRC32C_NONE:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "DataDigest", "CRC32C,None"))			return 0;		break;	default:	case ISCSI_DIGEST_NONE_CRC32C:		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "DataDigest", "None,CRC32C"))			return 0;		break;	}	return 1;}static intfill_op_params_text(struct iscsi_session *session, struct iscsi_hdr *pdu,		    char *data, int max_data_length, int *transit){	char value[AUTH_STR_MAX_LEN];	/* we always try to go from op params to full feature stage */	session->current_stage = ISCSI_OP_PARMS_NEGOTIATION_STAGE;	session->next_stage = ISCSI_FULL_FEATURE_PHASE;	*transit = 1;	/*	 * If we haven't gotten a partial response, then either we shouldn't be	 * here, or we just switched to this stage, and need to start offering	 * keys.	 */	if (!session->partial_response) {		/*		 * request the desired settings the first time		 * we are in this stage		 */		if (!fill_crc_digest_text(session, pdu, data, max_data_length))			return 0;		sprintf(value, "%d", session->max_recv_data_segment_len);		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "MaxRecvDataSegmentLength", value))			return 0;		sprintf(value, "%d", session->def_time2wait);		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "DefaultTime2Wait", value))			return 0;		sprintf(value, "%d", session->def_time2retain);		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "DefaultTime2Retain", value))			return 0;		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "IFMarker", "No"))			return 0;		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "OFMarker", "No"))			return 0;		if (!iscsi_add_text(session, pdu, data, max_data_length,				    "ErrorRecoveryLevel", "0"))			return 0;		if (session->type == ISCSI_SESSION_TYPE_NORMAL)			if (!add_params_normal_session(session, pdu, data,						  max_data_length))

⌨️ 快捷键说明

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